Skip to content

set_at now take a long long for y instead of int #2962

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src_c/draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1425,8 +1425,12 @@ clip_line(SDL_Surface *surf, SDL_Rect surf_clip_rect, int *x1, int *y1,
}

static int
set_at(SDL_Surface *surf, SDL_Rect surf_clip_rect, int x, int y, Uint32 color)
set_at(SDL_Surface *surf, SDL_Rect surf_clip_rect, int x, long long y,
Uint32 color)
{
// y should be long long so that y * surf->pitch doesn't overflow the int
// bounds in the case of very large surfaces and drawing on the edge of
// them
Uint8 *pixels = (Uint8 *)surf->pixels;

if (x < surf_clip_rect.x || x >= surf_clip_rect.x + surf_clip_rect.w ||
Expand Down Expand Up @@ -1459,7 +1463,7 @@ static void
set_and_check_rect(SDL_Surface *surf, SDL_Rect surf_clip_rect, int x, int y,
Uint32 color, int *drawn_area)
{
if (set_at(surf, surf_clip_rect, x, y, color)) {
if (set_at(surf, surf_clip_rect, x, (long long)y, color)) {
add_pixel_to_drawn_list(x, y, drawn_area);
}
}
Expand Down Expand Up @@ -1788,7 +1792,7 @@ drawhorzlineclip(SDL_Surface *surf, SDL_Rect surf_clip_rect, Uint32 color,
}

if (x1 == x2) {
set_at(surf, surf_clip_rect, x1, y1, color);
set_at(surf, surf_clip_rect, x1, (long long)y1, color);
return;
}
drawhorzline(surf, color, x1, y1, x2);
Expand Down
15 changes: 15 additions & 0 deletions test/draw_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import math
import os
import sys
import unittest
import warnings
Expand Down Expand Up @@ -1846,6 +1847,20 @@ def test_line_clipping_with_thickness(self):
"start={}, end={}".format(end_points[n], start_points[n]),
)

@unittest.skipIf(pygame.system.get_total_ram() < 4096, "Surface is too large")
def test_line_draw_large_surf_regression(self):
"""Regression test for https://github.com/pygame-community/pygame-ce/issues/2961"""
try:
surface = pygame.Surface((14457, 37200))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the addition of this test. It makes the assumption that the host has enough memory.

A better solution would be a RAM check with pygame.system.get_total_ram, and then running this test if the RAM is above some threshold, but I'm not a fan of this either.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't particularly like it either, but I felt it would be better to have some way to test that it hasn't regressed in the future. I couldn't think of any solution other than "make a gigantic surface" that CI won't have the memory for. I did try to make the surface as small as I could and still cause the segfault without the changes from this branch

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A follow-up of my message, yes I think it's not the method to follow to add the test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A surface of 14457x37200 pixels, at 4 bytes per pixel is about 2.15 gigs. To be safe, I can skip the test if the total memory is 4 gigs or less

except pygame.error:
self.skipTest(
"Surface too large to run this test in this environment, or too many background tasks"
)

point1 = [400, 37135]
point2 = [401, 37136]
pygame.draw.line(surface, (255, 255, 255), point1, point2, 1)


### Lines Testing #############################################################

Expand Down
Loading