From d6fc629b5b1580e487dfd9e7f2eb4108a1b5d7e0 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 26 Mar 2024 14:11:38 -0700 Subject: [PATCH] Fixed Windows rawinput crash RAWINPUT structures are variable size --- src/video/windows/SDL_windowsevents.c | 47 ++++++++++++++------------- src/video/windows/SDL_windowswindow.h | 2 +- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 9c690b562..bd4e11916 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -667,7 +667,7 @@ void WIN_PollRawInput(SDL_VideoDevice *_this) { SDL_Window *window; SDL_WindowData *data; - UINT size, count, i, total = 0; + UINT size, i, count, total = 0; RAWINPUT *input; Uint64 now; @@ -678,7 +678,7 @@ void WIN_PollRawInput(SDL_VideoDevice *_this) } data = window->driverdata; - if (data->rawinput_size == 0) { + if (data->rawinput_offset == 0) { BOOL isWow64; data->rawinput_offset = sizeof(RAWINPUTHEADER); @@ -686,33 +686,34 @@ void WIN_PollRawInput(SDL_VideoDevice *_this) /* We're going to get 64-bit data, so use the 64-bit RAWINPUTHEADER size */ data->rawinput_offset += 8; } - - if (GetRawInputBuffer(NULL, &data->rawinput_size, sizeof(RAWINPUTHEADER)) == (UINT)-1) { - return; - } - if (data->rawinput_size == 0) { - return; - } } /* Get all available events */ + input = (RAWINPUT *)data->rawinput; for (;;) { - if (total == data->rawinput_count) { - count = total + 8; - input = (RAWINPUT *)SDL_realloc(data->rawinput, count * data->rawinput_size); - if (!input) { - return; + size = data->rawinput_size - ((BYTE *)input - data->rawinput); + count = GetRawInputBuffer(input, &size, sizeof(RAWINPUTHEADER)); + if (count == 0 || count == (UINT)-1) { + if (!data->rawinput || (count == (UINT)-1 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { + const size_t RAWINPUT_BUFFER_SIZE_INCREMENT = 96; // 2 64-bit raw mouse packets + BYTE *rawinput = (BYTE *)SDL_realloc(data->rawinput, data->rawinput_size + RAWINPUT_BUFFER_SIZE_INCREMENT); + if (!rawinput) { + break; + } + input = (RAWINPUT *)(rawinput + ((BYTE *)input - data->rawinput)); + data->rawinput = rawinput; + data->rawinput_size += RAWINPUT_BUFFER_SIZE_INCREMENT; + } else { + break; } - data->rawinput = input; - data->rawinput_count = count; - } + } else { + total += count; - size = (data->rawinput_count - total) * data->rawinput_size; - count = GetRawInputBuffer((RAWINPUT *)((BYTE *)data->rawinput + (total * data->rawinput_size)), &size, sizeof(RAWINPUTHEADER)); - if (count == (UINT)-1 || count == 0) { - break; + // Advance input to the end of the buffer + while (count--) { + input = NEXTRAWINPUTBLOCK(input); + } } - total += count; } now = SDL_GetTicksNS(); @@ -728,7 +729,7 @@ void WIN_PollRawInput(SDL_VideoDevice *_this) timestamp = now; increment = 0; } - for (i = 0, input = data->rawinput; i < total; ++i, input = NEXTRAWINPUTBLOCK(input)) { + for (i = 0, input = (RAWINPUT *)data->rawinput; i < total; ++i, input = NEXTRAWINPUTBLOCK(input)) { timestamp += increment; if (input->header.dwType == RIM_TYPEMOUSE) { RAWMOUSE *rawmouse = (RAWMOUSE *)((BYTE *)input + data->rawinput_offset); diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h index b98eba628..9cd8e52a0 100644 --- a/src/video/windows/SDL_windowswindow.h +++ b/src/video/windows/SDL_windowswindow.h @@ -70,7 +70,7 @@ struct SDL_WindowData UINT windowed_mode_corner_rounding; COLORREF dwma_border_color; #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - RAWINPUT *rawinput; + BYTE *rawinput; UINT rawinput_offset; UINT rawinput_size; UINT rawinput_count;