-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Automatic cleanup after 1 second in SDL_FreeLater
can easily cause use after free bugs
#10378
Comments
I clarified that temporary memory doesn't last past the current event being handled or the current function scope: Lines 1437 to 1440 in a1a8278
You can always call free on the returned array. If you want, you can do this: const void *data = SDL_SomeFunction();
if (data) {
...
SDL_free(SDL_ClaimTemporaryMemory(data));
} That will transfer ownership of the memory to you, and you have full control over when you want to free it. |
Ah, I see that your repro case forces collection while the current event is still being processed. Hmmmmmmm |
Can't a context switch happen at any time? In that case I don't see how you can ever guarantee that 1 second has not passed from one instruction to the next which makes the "1 second cleanup rule" pretty useless. It's not clear why "the current function scope" is relevant. You can run a lot of code that takes a lot of time and calls a lot of functions in the current function scope. I feel it would almost be better to just let the caller free the memory. It increases the risk of memory leaks but those are pretty harmless, and easy to track down, compared to potential use-after-free bugs that only happen occasionally. Or have the memory freed automatically next time the same (or a related) function gets called (e.g. memory for an event could be freed when you request the next event). That's more deterministic and easier to understand than having to guess what "it's freed later" means. Right now it feels like I would always want to use |
Yep, this is all good feedback, thanks! We're trying to balance making the API easy to use and giving the application control over memory usage. |
…DL_FreeTemporaryMemory() when it's ready. Also mark up all functions that return temporary memory with SDL_DECLSPEC_TEMP, to help people implementing language bindings. Fixes libsdl-org#10378
…DL_FreeTemporaryMemory() when it's ready. Also mark up all functions that return temporary memory with SDL_DECLSPEC_TEMP, to help people implementing language bindings. Fixes libsdl-org#10378
…DL_FreeTemporaryMemory() when it's ready. Also mark up all functions that return temporary memory with SDL_DECLSPEC_TEMP, to help people implementing language bindings. Fixes libsdl-org#10378
We've change it so SDL no longer automatically frees temporary memory, instead you can call SDL_FreeTemporaryMemory() whenever you want. In addition, functions that return temporary memory are marked up with SDL_DECLSPEC_TEMP, so it's easy to see where you might want to claim memory. @icculus, note that SDL_DECLSPEC_TEMP becomes part of the ABI. |
The idea of
SDL_FreeLater
and its automatic cleanup raises (at least to me) immediate concern about memory bugs. The 1 second rule seems fine at first glance, the memory is called temporary and nobody would do expensive, lengthy processing with it. But the problem is that the 1 second is wall clock time. There are many things that can pause a thread for more then one second:SDL_Delay(1200)
(this is unrealistic, but makes use after free bugs easily reproducible)Demonstration
The last one can be easily demonstrated with
checkkeys
on Windows:Apply the following diff
Build and run
checkkeys.exe --resizable
At the same time, enter some text and start resizing the window (enter the text just before you start resizing)
Keep resizing until 1 second elapses
Notice that the resulting text contains garbage data, indicative of a use after free bug
The buggy text consists of
\xdd\xdd\xdd\xdd\xdd\xdd
on debug builds, which indicates freed memory.2024-07-26.02-01-04.mp4
The bug happens because the text string is temporarily allocated before the resize starts blocking. By the time the event is handled, 1 second would have already elapsed and the next call to
SDL_CollectTemporaryMemory
will free it, leaving a dangling pointer.The workaround for the bug is to call
SDL_ClaimTemporaryMemory
as soon as possible, but that defeats the purpose of the temporary memory.I started looking into this issue when SDL3-CS was changed to no longer free certain arrays to account for the change in #10311.
Please try to use a better heuristic for automatic cleanup. Or better yet, don't add functionality that, by definition, introduces use after free bugs. (I don't mind calling
SDL_free
on a returned array :)The text was updated successfully, but these errors were encountered: