From bc9888c9b552cbd7f138ad36e743dab80e67f523 Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Sat, 12 Jun 2021 14:55:24 +0300
Subject: [PATCH] OS2_GetDisplayModes: malloc a new copy of mode's driver data.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Based on a patch by Jochen Schäfer <josch1710@live.de> :
The problem is, that in the initialization code uses the same structure for
desktop_mode and current_mode. See SDL_os2video.c:OS2_VideoInit():
stSDLDisplay.desktop_mode = stSDLDisplayMode;
stSDLDisplay.current_mode = stSDLDisplayMode;
...
stSDLDisplayMode.driverdata = pDisplayData;
Then, if you call GetDisplayModes, current_mode will added to the modes
list, with the same driverdata pointer to desktop_mode.
SDL_AddDisplayMode( display, &display->current_mode );
When VideoQuit gets called, first the modes list gets freed including the
driverdata, the desktop_mode gets freed. See SDL_video.c:SDL_VideoQuit():
for (j = display->num_display_modes; j--;) {
SDL_free(display->display_modes[j].driverdata);
display->display_modes[j].driverdata = NULL;
}
SDL_free(display->display_modes);
display->display_modes = NULL;
SDL_free(display->desktop_mode.driverdata);
display->desktop_mode.driverdata = NULL;
So, the display_modes[j].driverdata gets freed, but desktop_mode->driverdata
points to the same memory, but is not NULL'ed. When desktop_mode->driverdata
gets freed the memory is already freed, and libcx crashes the application on
SDL_Quit.
---
src/video/os2/SDL_os2video.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/video/os2/SDL_os2video.c b/src/video/os2/SDL_os2video.c
index 0ec0f1e61..45f7b05c5 100644
--- a/src/video/os2/SDL_os2video.c
+++ b/src/video/os2/SDL_os2video.c
@@ -1562,8 +1562,14 @@ static int OS2_GetDisplayDPI(_THIS, SDL_VideoDisplay *display, float *ddpi,
static void OS2_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
{
+ SDL_DisplayMode mode;
+
debug_os2("Enter");
- SDL_AddDisplayMode(display, &display->current_mode);
+ SDL_memcpy(&mode, &display->current_mode, sizeof(SDL_DisplayMode));
+ mode.driverdata = (MODEDATA *) SDL_malloc(sizeof(MODEDATA));
+ if (!mode.driverdata) return; /* yikes.. */
+ SDL_memcpy(mode.driverdata, display->current_mode.driverdata, sizeof(MODEDATA));
+ SDL_AddDisplayMode(display, &mode);
}
static int OS2_SetDisplayMode(_THIS, SDL_VideoDisplay *display,