Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Fix display.set_mode segfault after resizing #3501

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
MightyJosip wants to merge 2 commits into pygame-community:main
base: main
Choose a base branch
Loading
from MightyJosip:surface-segfault

Conversation

@MightyJosip
Copy link
Member

@MightyJosip MightyJosip commented Jun 15, 2025
edited
Loading

This should fix the following code that segfaults

import pygame
pygame.display.set_mode([800, 600], flags=pygame.SCALED)
pygame.display.set_mode([800, 598], flags=pygame.RESIZABLE | pygame.SCALED)

This also fixes #2571

TLDR: Changing size of the window invalidates surface returned by SDL_GetWindowSurface() as explained in https://wiki.libsdl.org/SDL2/SDL_GetWindowSurface, so this commit makes sure the module always has the reference to the right SDL_Surface (hopefully). There are other possible fixes for this, but this one to me looks the most elegant (unless we rewrite the entire module/function).

And the long explanation is available in our discord server https://discord.com/channels/772505616680878080/772940667231928360/1383591122101604402

Also, if someone knows another place in our code when the resizing could happen, make sure to notify me to add this new helper function there as well

EDIT: Looks like there is a memory leak with this change, will need to check if it happens without it

EDIT 2: I am pretty sure that the memory leak happens because of #3502

@MightyJosip MightyJosip requested a review from a team as a code owner June 15, 2025 10:47
Copy link
Member

@ankith26 ankith26 left a comment
edited
Loading

Choose a reason for hiding this comment

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

LGTM, thanks for the fix! 🎉

re: memory leak, I am not seeing any noticeable evidence of that. I believe that even if there is a memory leak, it would probably not be a result of this PR.

Also, if someone knows another place in our code when the resizing could happen, make sure to notify me to add this new helper function there as well

There is some logic in pg_flip_internal that is exactly like _check_window_resized you may wanna update that snippet as well, just for code quality reasons. Nothing related to this fix per se.

I have tested this change on Ubuntu and found no issues, but I am also requesting reviews from Windows users to verify that this fixes the issue at hand.

Copy link
Member Author

What I mean by the memory leak is the following:

import pygame
import random
import psutil
import os
pygame.display.set_mode((800, 600), flags=pygame.SCALED)
while True:
 print(f"Memory usage: {psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024:.2f} MB")
 pygame.display.set_mode([random.randint(600, 800), random.randint(600, 800)], flags=pygame.RESIZABLE | pygame.SCALED)

It is probably happening because with this change the old surface is not freed. However, if I free the surface, then I return to the old problem of segfault 🤣 . Really hard issue

Copy link
Member

the old surface should be freed already by SDL, it cannot be freed on our side.

surface = pgSurface_New2(surf, newownedsurf != NULL);
}
else {
_check_window_resized(win, 0);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm probably failing to notice something here, but why aren't we freeing the old surface here?

Copy link
Member Author

@MightyJosip MightyJosip Jun 16, 2025
edited
Loading

Choose a reason for hiding this comment

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

Because if we free then we get segmentation fault from the linked issue. You have more explanation in the discord link

gresm reacted with thumbs up emoji
Copy link
Member

@ankith26 ankith26 left a comment

Choose a reason for hiding this comment

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

I'm not sure if the current freeing logic here is okay.

We essentially have to consider two cases:

  1. The display surface is created on our side with a PG_CreateSurface call. In this case we are responsible for freeing it, otherwise it leaks
  2. The display surface is obtained via a call from SDL_GetWindowSurface. In this case calling SDL_FreeSurface is a noop because its managed by SDL. The fact that this surface becomes invalidated by SDL is the reason for any segfault we get while accessing it.

This makes our freeing logic complex. We have to now actually keep track of how the previous surface was allocated and free it based on that condition.

Copy link
Member

I'm not sure if the current freeing logic here is okay.

We essentially have to consider two cases:

  1. The display surface is created on our side with a PG_CreateSurface call. In this case we are responsible for freeing it, otherwise it leaks
  2. The display surface is obtained via a call from SDL_GetWindowSurface. In this case calling SDL_FreeSurface is a noop because its managed by SDL. The fact that this surface becomes invalidated by SDL is the reason for any segfault we get while accessing it.

This makes our freeing logic complex. We have to now actually keep track of how the previous surface was allocated and free it based on that condition.

Almost sounds like we need something like 'PGObtainDisplaySurface' with a 'PGFreeDisplaySurface' and a 'PGDisplaySurface' that tracks who owns the surface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@gresm gresm gresm left review comments

@ankith26 ankith26 ankith26 requested changes

Requested changes must be addressed to merge this pull request.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Calling a second time pygame.display.set_mode with vsync and vsync already enabled doesn't work correctly

AltStyle によって変換されたページ (->オリジナル) /