Fix display.set_mode segfault after resizing#3501
Fix display.set_mode segfault after resizing#3501MightyJosip wants to merge 2 commits intopygame-community:mainfrom
Conversation
There was a problem hiding this comment.
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.
|
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 |
|
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); |
There was a problem hiding this comment.
I'm probably failing to notice something here, but why aren't we freeing the old surface here?
There was a problem hiding this comment.
Because if we free then we get segmentation fault from the linked issue. You have more explanation in the discord link
ankith26
left a comment
There was a problem hiding this comment.
I'm not sure if the current freeing logic here is okay.
We essentially have to consider two cases:
- The display surface is created on our side with a
PG_CreateSurfacecall. In this case we are responsible for freeing it, otherwise it leaks - The display surface is obtained via a call from
SDL_GetWindowSurface. In this case callingSDL_FreeSurfaceis 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. |
This should fix the following code that segfaults
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