From bb969ac74710604d13c189899d37c285e90ccaf8 Mon Sep 17 00:00:00 2001
From: Sylvain Becker <[EMAIL REDACTED]>
Date: Fri, 19 Jan 2024 17:39:57 +0100
Subject: [PATCH] Fixed bug #7614: Segmentation Fault in SDL_BlitSurface
(#7808)
Update SDL_BlitSurface to use Intersect functions
(cherry picked from commit 3639743d8909406557663af0854dc7bd97956b24)
---
src/video/SDL_surface.c | 121 +++++++++++++++++-----------------------
1 file changed, 51 insertions(+), 70 deletions(-)
diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c
index 6854f68b50f8..0306f8fc95df 100644
--- a/src/video/SDL_surface.c
+++ b/src/video/SDL_surface.c
@@ -701,86 +701,65 @@ int SDL_LowerBlit(SDL_Surface *src, SDL_Rect *srcrect,
int SDL_UpperBlit(SDL_Surface *src, const SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect)
{
- SDL_Rect fulldst;
- int srcx, srcy;
- Sint64 w, h;
+ SDL_Rect r_src, r_dst;
/* Make sure the surfaces aren't locked */
- if (!src || !dst) {
- return SDL_InvalidParamError("SDL_UpperBlit(): src/dst");
- }
- if (src->locked || dst->locked) {
+ if (!src) {
+ return SDL_InvalidParamError("src");
+ } else if (!dst) {
+ return SDL_InvalidParamError("dst");
+ } else if (src->locked || dst->locked) {
return SDL_SetError("Surfaces must not be locked during blit");
}
- /* If the destination rectangle is NULL, use the entire dest surface */
- if (!dstrect) {
- fulldst.x = fulldst.y = 0;
- fulldst.w = dst->w;
- fulldst.h = dst->h;
- dstrect = &fulldst;
+ /* Full src surface */
+ r_src.x = 0;
+ r_src.y = 0;
+ r_src.w = src->w;
+ r_src.h = src->h;
+
+ if (dstrect) {
+ r_dst.x = dstrect->x;
+ r_dst.y = dstrect->y;
+ } else {
+ r_dst.x = 0;
+ r_dst.y = 0;
}
/* clip the source rectangle to the source surface */
if (srcrect) {
- int maxw, maxh;
-
- srcx = srcrect->x;
- w = srcrect->w;
- if (srcx < 0) {
- w += srcx;
- dstrect->x -= srcx;
- srcx = 0;
- }
- maxw = src->w - srcx;
- if (maxw < w) {
- w = maxw;
+ SDL_Rect tmp;
+ if (SDL_IntersectRect(srcrect, &r_src, &tmp) == SDL_FALSE) {
+ goto end;
}
- srcy = srcrect->y;
- h = srcrect->h;
- if (srcy < 0) {
- h += srcy;
- dstrect->y -= srcy;
- srcy = 0;
- }
- maxh = src->h - srcy;
- if (maxh < h) {
- h = maxh;
- }
+ /* Shift dstrect, if srcrect origin has changed */
+ r_dst.x += tmp.x - srcrect->x;
+ r_dst.y += tmp.y - srcrect->y;
- } else {
- srcx = srcy = 0;
- w = src->w;
- h = src->h;
+ /* Update srcrect */
+ r_src = tmp;
}
+ /* There're no dstrect.w/h parameters. It's the same as srcrect */
+ r_dst.w = r_src.w;
+ r_dst.h = r_src.h;
+
/* clip the destination rectangle against the clip rectangle */
{
- SDL_Rect *clip = &dst->clip_rect;
- int dx, dy;
-
- dx = clip->x - dstrect->x;
- if (dx > 0) {
- w -= dx;
- dstrect->x += dx;
- srcx += dx;
- }
- dx = dstrect->x + w - clip->x - clip->w;
- if (dx > 0) {
- w -= dx;
+ SDL_Rect tmp;
+ if (SDL_IntersectRect(&r_dst, &dst->clip_rect, &tmp) == SDL_FALSE) {
+ goto end;
}
- dy = clip->y - dstrect->y;
- if (dy > 0) {
- h -= dy;
- dstrect->y += dy;
- srcy += dy;
- }
- dy = dstrect->y + h - clip->y - clip->h;
- if (dy > 0) {
- h -= dy;
- }
+ /* Shift srcrect, if dstrect has changed */
+ r_src.x += tmp.x - r_dst.x;
+ r_src.y += tmp.y - r_dst.y;
+ r_src.w = tmp.w;
+ r_src.h = tmp.h;
+
+ /* Update dstrect */
+ r_dst = tmp;
}
/* Switch back to a fast blit if we were previously stretching */
@@ -789,15 +768,17 @@ int SDL_UpperBlit(SDL_Surface *src, const SDL_Rect *srcrect,
SDL_InvalidateMap(src->map);
}
- if (w > 0 && h > 0) {
- SDL_Rect sr;
- sr.x = srcx;
- sr.y = srcy;
- sr.w = dstrect->w = w;
- sr.h = dstrect->h = h;
- return SDL_LowerBlit(src, &sr, dst, dstrect);
+ if (r_dst.w > 0 && r_dst.h > 0) {
+ if (dstrect) { /* update output parameter */
+ *dstrect = r_dst;
+ }
+ return SDL_LowerBlit(src, &r_src, dst, dstrect);
+ }
+
+end:
+ if (dstrect) { /* update output parameter */
+ dstrect->w = dstrect->h = 0;
}
- dstrect->w = dstrect->h = 0;
return 0;
}