Make tracking allocator default to crashing on a bad free instead of adding to bad_free_array #4605
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This makes the tracking allocator default to crashing when a bad free occurs, instead of adding the bad free to an array. The crash will look something like this:
Rationale
Almost once a month I talk to someone who has misbehaving code, and I ask them if they check the bad free array. They say that they use tracking allocator but didn't think of checking the bad free array as required. After all, without tracking allocator bad frees tend to crash so one finds them anyways. But with the tracking allocator, bad frees just silently pass by if you forget to check the bad_free_array.
A better default behavior is therefore for tracking allocator to also crash, but still provide all the nice source code location information it has access to.
Also, not only does the old style of adding to bad_free_array cause people to miss bad frees. It can also cause memory corruption in their development build! Let me explain why that can happen, here's the old code that added stuff to the
bad_free_array
if it wasn't in theallocation_map
:If you forgot to check
bad_free_array
, then all the bad frees were just silently added to the list. But to make things worse: Once in a blue moon the bad free would actually be of a valid pointer that exists indata.allocation_map
. In that case theelse
block happens in the code above: The bad free just deallocates some random memory! This can of course happen with a crash-callback too. But it is very likely that it will have crashed on some allocation before getting to one of those rare cases that ends up in theelse
block.Another problem is that
core
andvendor
has several examples that look like this:For anyone who learned about the tracking allocator from this example, they might never have known that the
bad_free_array
exists. So they just have lots of silent bad frees + possible memory corruptions.I know people would probably see these bad frees if they ever make a build without tracking allocator (because then it would probably crash on those bad frees). But I wouldn't be surprised if there are people out there who just give up on Odin because their program is just misbehaving (due to tracking-allocator-i-didnt-check-the-bad-free-array-memory-corruption), but they can't figure out why.
Backwards compatibility
This new default behavior is implemented using a callback
Tracking_Allocator.bad_free_callback
. This callback can be overridden totracking_allocator_bad_free_callback_add_to_array
in order to have the old behavior.The
bad_free_array
is still in the tracking allocator, making sure we don't break a lot of code at once. But in most programs it will not be used any more, so the "bad free checks" on shutdown won't do anything more. I can update the overview docs etc to remove thebad_free_array
checks.There were a few tests that explicitly checked
bad_free_array
, for those tests I use the callback that implements the old behavior.