From 166afebcad4533e1db0e42a2401d24218208c52d Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Wed, 1 Feb 2023 20:18:00 -0500 Subject: [PATCH] video: Update self-referential pointers when reallocating the display list The display list can contain self-referential pointers if the current mode pointer points to the desktop mode or a fullscreen mode array element, and reallocating the display or fullscreen mode lists without updating the current mode pointer in these cases can leave them pointing to freed memory or garbage data. Manually copy the list items and update the self-referential pointers if necessary. --- src/video/SDL_video.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 25d08d3149..e5b4795195 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -630,10 +630,21 @@ SDL_DisplayID SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send SDL_VideoDisplay *displays, *new_display; SDL_DisplayID id = 0; - displays = (SDL_VideoDisplay *)SDL_realloc(_this->displays, (_this->num_displays + 1) * sizeof(*displays)); + displays = (SDL_VideoDisplay *)SDL_malloc((_this->num_displays + 1) * sizeof(*displays)); if (displays) { int i; + + /* The display list may contain self-referential pointers to the desktop mode. */ + SDL_memcpy(displays, _this->displays, _this->num_displays * sizeof(*displays)); + for (i = 0; i < _this->num_displays; ++i) { + if (displays[i].current_mode == &_this->displays[i].desktop_mode) { + displays[i].current_mode = &displays[i].desktop_mode; + } + } + + SDL_free(_this->displays); _this->displays = displays; + id = _this->next_object_id++; new_display = &displays[_this->num_displays++]; @@ -938,10 +949,20 @@ SDL_bool SDL_AddFullscreenDisplayMode(SDL_VideoDisplay *display, const SDL_Displ /* Go ahead and add the new mode */ if (nmodes == display->max_fullscreen_modes) { - modes = (SDL_DisplayMode *)SDL_realloc(modes, (display->max_fullscreen_modes + 32) * sizeof(*modes)); + modes = (SDL_DisplayMode *)SDL_malloc((display->max_fullscreen_modes + 32) * sizeof(*modes)); if (modes == NULL) { return SDL_FALSE; } + + /* Copy the list and update the current mode pointer, if necessary. */ + SDL_memcpy(modes, display->fullscreen_modes, nmodes * sizeof(*modes)); + for (i = 0; i < nmodes; ++i) { + if (display->current_mode == &display->fullscreen_modes[i]) { + display->current_mode = &modes[i]; + } + } + + SDL_free(display->fullscreen_modes); display->fullscreen_modes = modes; display->max_fullscreen_modes += 32; }