diff --git a/src_c/surface.c b/src_c/surface.c index b3e40ccb5c..8139f028d8 100644 --- a/src_c/surface.c +++ b/src_c/surface.c @@ -3799,6 +3799,21 @@ pgSurface_Blit(pgSurfaceObject *dstobj, pgSurfaceObject *srcobj, SDL_Rect orig_clip, sub_clip; Uint8 alpha; + if ((dstrect->x <= INT_MIN + dstrect->w) || + (dstrect->x >= INT_MAX - dstrect->w) || + (dstrect->y <= INT_MIN + dstrect->h) || + (dstrect->y >= INT_MAX - dstrect->h)) { + // destination rect has values that are too large + return 0; + } + if (srcrect != NULL && ((srcrect->x <= INT_MIN + srcrect->w) || + (srcrect->x >= INT_MAX - dstrect->w) || + (srcrect->y <= INT_MIN + srcrect->h) || + (srcrect->y >= INT_MAX - dstrect->h))) { + // source rect has values that are too large: + return 0; + } + /* passthrough blits to the real surface */ if (((pgSurfaceObject *)dstobj)->subsurface) { PyObject *owner; diff --git a/test/surface_test.py b/test/surface_test.py index ca60ccb8e0..ea7e51a2ed 100644 --- a/test/surface_test.py +++ b/test/surface_test.py @@ -1061,6 +1061,59 @@ def test_blit_zero_overlap(self): ) # Remaining corners self.assertEqual(self.dst_surface.get_at((0, 63)), (0, 0, 0)) + def test_blit_bad_frect_position_values(self): + """Previously segfaulted - these should now silently exit and blit nothing""" + + # test the old segfault case s- just to make sure it doesn't segfault + pygame.display.init() + screen = pygame.display.set_mode((800, 600)) + screen.fill((0, 0, 0)) + test_surf = pygame.Surface((1057, 398), flags=pygame.SRCALPHA) + pos_rect = pygame.FRect(float("nan"), 202.0, 100.0, 100.0) + screen.blit(test_surf, pos_rect) + pygame.display.quit() + + surf_width = 2048 + c_max_int = 2147483647 + pygame.display.init() + screen = pygame.display.set_mode((63, 600)) + test_surf = pygame.Surface((surf_width, 400), flags=pygame.SRCALPHA) + screen.blit(test_surf, (c_max_int - surf_width - 64, 200.0)) + pygame.display.quit() + + # thoroughly test the fix code in FRect + # these parts could be removed or changed once FRect is able to + # handle/reject large values like this + c_min_int = -2147483648 + self.dst_surface.blit( + self.src_surface, pygame.FRect(float("nan"), float("inf"), 300, 300) + ) + + self.assertEqual(self.dst_surface.get_at((0, 0)), (0, 0, 0)) + self.assertEqual(self.dst_surface.get_at((63, 63)), (0, 0, 0)) + + self.dst_surface.blit( + self.src_surface, pygame.FRect(c_max_int, c_max_int, c_max_int, c_max_int) + ) + + self.assertEqual(self.dst_surface.get_at((0, 0)), (0, 0, 0)) + self.assertEqual(self.dst_surface.get_at((63, 63)), (0, 0, 0)) + + # test area too + self.dst_surface.blit( + self.src_surface, (0, 0), pygame.FRect(c_max_int, c_max_int, 300, 300) + ) + + self.assertEqual(self.dst_surface.get_at((0, 0)), (0, 0, 0)) + self.assertEqual(self.dst_surface.get_at((63, 63)), (0, 0, 0)) + + self.dst_surface.blit( + self.src_surface, (0, 0), pygame.FRect(c_min_int, c_min_int, 300, 300) + ) + + self.assertEqual(self.dst_surface.get_at((0, 0)), (0, 0, 0)) + self.assertEqual(self.dst_surface.get_at((63, 63)), (0, 0, 0)) + def test_blit__SRCALPHA_opaque_source(self): src = pygame.Surface((256, 256), SRCALPHA, 32) dst = src.copy()