-
-
Notifications
You must be signed in to change notification settings - Fork 206
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
Fix use-after-free and 3 memory leaks; enforce AddressSanitizer in CI #133
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The object pointer may become dangling if the object is destroyed, thus calling `object_get_instance_id` via FFI can cause UB. The only reliable way to check object validity is through `is_instance_id_valid`. This change increases the size of `Gd` by 8 bytes, but is needed for safety.
Bromeon
added
bug
c: tooling
CI, automation, tools
c: ffi
Low-level components and interaction with GDExtension API
labels
Feb 26, 2023
bors try |
tryBuild succeeded: |
…t() before running the init fn Impacts: * Simplifies ffi_methods! usage for Variant, GodotString, StringName, TypedArray, PackedArray, Dictionary * impl Default does not need to re-implement from_sys_init() * Functions which do *not* expect a pre-initialized instance can directly call from_sys_init() in the future, avoiding 2 inits (memory leak)
Affected: * TypedArray::share() * Dictionary::share() * PackedArray::from(&Array) Output from Godot compiled with LeakSanitizer, prior to this commit: SUMMARY: AddressSanitizer: 864 byte(s) leaked in 10 allocation(s).
Bromeon
force-pushed
the
bugfix/mem-corruption
branch
from
February 26, 2023 22:14
08b934b
to
cbd22fa
Compare
bors r+ |
Build succeeded: |
This was referenced Jun 5, 2023
bors bot
added a commit
that referenced
this pull request
Jul 6, 2023
325: Address sanitizers for Rust r=Bromeon a=Bromeon We have missed a lot of UB that occurred only in Rust code and wasn't detected by AddressSanitizer outside of C++ code. This PR enables ASan for Rust code using `-Zsanitizer=address` in the two memcheck CI jobs. As such, this is a follow-up to #133. The CI currently fails because there is still some UB on `master`... ideally we can fix this soon. bors try Co-authored-by: Jan Haller <bromeon@gmail.com>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
bug
c: ffi
Low-level components and interaction with GDExtension API
c: tooling
CI, automation, tools
ub
Undefined behavior
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.
Changes implementation of the
Gd
smart pointer to cache the instance ID in each object. To my knowledge, instance IDs are the only reliable way to check for object validity in Godot, as raw object pointers may become dangling.In addition, this PR fixes 3 memory leaks around arrays and dictionaries. Those occurred due to
from_sys_init()
usingT::default()
in too many places. This essentially lead to allocating a default-constructed object, which is then immediately overwritten by theinit
function, which also allocates a new object. I refactored theGodotFfi::from_sys_init()
to never calldefault()
, and add an explicitfrom_sys_init_default()
for cases where this is desired. This also cuts down on some of the boilerplate.Both use-after-free and memory leaks were discovered using AddressSanitizer/LeakSanitizer. Great tooling from the C++ world, which also proves useful for us, as miri can't be used in FFI contexts. From now on, UB or leaks detected by ASan/LSan will cause a hard error in CI. The tools are not 100% bullet-proof; they didn't detect the following UAF case in a short test, but they are still of great value as a more systematic counter to memory errors.
use-after-free, false negative
On a side note, getting these working correctly in CI was a bit of a marathon because ASan/LSan don't have stacktraces for dynamically loaded libraries (a known wontfix problem, see google/sanitizers#89). Additionally, false positives for memory leaks were reported: a simple
println!
would cause 1024 bytes of non-reclaimable memory. Therefore, I had to compile a special version of nightly Godot that disables dynamic library unloading viadlclose
, to keep the stacktrace around, and this seemed to fix the false-positive issue as well. Although likely unrelated, what I also found during research was rust-lang/rust#19776.Fixes #89.