Fix ExceptionPackage memory errors#3088
Conversation
First, adds an explicit destructor call to fix a memory leak in `Literal::operator=` in which existing `ExceptionPackage`s would be silently dropped. Next, changes `Literal::getExceptionPackage` to return the `ExceptionPackage` by value to avoid a use-after-free bug in the interpreter that was surfaced by the new destructor call. Fixes WebAssembly#3087.
src/wasm/literal.cpp
Outdated
| // Avoid calling the destructor, which may not be correct | ||
| new (&exn) auto( | ||
| std::move(std::make_unique<ExceptionPackage>(*other.exn))); |
There was a problem hiding this comment.
This was already not calling the destructor; the addition of std::move is just a drive-by optimization.
It is important to not call the destructor if the previous type was anything besides exnref, so this line was already correct. The only thing missing was that we had to call the destructor if the previous type was exnref.
There was a problem hiding this comment.
This is one of those days where I think longingly of Rust 🦀
|
Looking at your fix (yay!), this somewhat reminds me of binaryen/src/wasm-interpreter.h Lines 68 to 71 in fecfa92 which is (pretty much the only occasion not in literal.h/cpp) passing a literal by reference. Just curious if this might be problematic, or is this fine? |
|
(just gave this a shot, and indeed removing just the |
This is fine as long as the reference returned by this function is never used after the underlying In Rust, we would have to add a lifetime annotation to this function in order to return the reference, but in return the type system would guarantee that the reference would never be dangling. |
|
In modern times an idiom has grown from it meaning "Any source of great and unexpected troubles", or alternatively "A present which seems valuable but which in reality is a curse". What is _______ ? |
|
Omg, now the issue is that the copy constructor is implemented in terms of the assignment operator, but the assignment operator now reads from the current value of This is quite the pandora's box ;) |
|
Not sure if related, but though I check out your branch, compile with Makes me wonder if we should add (more) AddressSanitizer to CI? |
|
We already have ASan on CI, but we disable the leak checker, probably because all our leaks would cause our CI to fail! It would certainly be good to clean up the remaining leaks and enable leak checking on CI. |
|
To be clear, I think this PR is good to land, though. That other leak can be cleaned up separately. |
|
Come to think of it, I'm not sure if we should use Can't we just make this #3087 says |
That's how I've been thinking about it.
It seems slightly simpler to me to use
|
|
Hmm I don't recall exactly why |
Hmm, good point. Even if it feels dangerous, it's actually the same as using a unique_ptr in this case. Of course one way to actually make this safer would be to upgrade to C++17 and use a std::variant instead of manually managing a union here. Maybe that would be worth doing soonish... |
kripken
left a comment
There was a problem hiding this comment.
This specific incremental change looks good.
In general moving more to passing by value as @aheejin said sounds good to me. I don't think interpreter perf matters much which is the one place that would be noticed. (However, we should try to avoid increasing the size if possible, but sounds like that might not be an issue.)
| assert(type == Type::exnref); | ||
| return *exn.get(); | ||
| } | ||
| ExceptionPackage getExceptionPackage() const; |
There was a problem hiding this comment.
why move this body to the cpp? all the siblings are here it seems.
There was a problem hiding this comment.
Since ExceptionPackage is now returned by value, it needs to be a complete type at the point of this function definition. But the definition of ExceptionPackage can't move before the definition of Literal for the same reason, so the only choice was to move getExceptionPackage to be defined out of line, which means it needs to be in the .cpp file.
|
Cool, I'll land this as-is (even though the unique_ptr doesn't buy us much) for now and we can revisit this and probably make |
|
+1 for doing c++17 sooner than later in order to use |
|
I think using But maybe it's not worth putting much time on this given that |
I didn't have any problem with this clause.. In my machine, both the size of |
|
@aheejin I agree |
|
Yeah, using it was my fault in the first place ;( But anyway, it will likely to be gone at some point. |
First, adds an explicit destructor call to fix a memory leak in
Literal::operator=in which existingExceptionPackages would besilently dropped. Next, changes
Literal::getExceptionPackagetoreturn the
ExceptionPackageby value to avoid a use-after-free bugin the interpreter that was surfaced by the new destructor call.
Fixes #3087.