-
-
Notifications
You must be signed in to change notification settings - Fork 662
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 bugs in in ctl::optional #1203
Conversation
Manually manage the lifetime of `value_` by using an anonymous `union`. This fixes a bunch of double-frees and double-constructs. Additionally move the `present_` flag last. When `T` has padding `present_` will be placed there saving `alignof(T)` bytes from `sizeof(optional<T>)`.
LGTM I like the approach. I'm assuming that you've tested and verified that this does indeed behave the way you expect it to. I'm trying to think about why I've seen other people do As far as I can tell, manually managed lifetimes is pretty much table stakes for writing an I believe there may be some CLA type actions that @jart can help you with if this is your first contribution to cosmopolitan. |
I didn't test this in this PR but I have implemented too many "optionals" I would want to admit. I sent @jart the CLA already. |
This was done before C++11 because unions could not take non-POD types before that. From https://en.cppreference.com/w/cpp/language/union. Until C++11:
C+11 onwards:
|
Ok - I would want to see some sanity testing actually. I am sure this is fine, but it looks like the old optional was assuming that it would just have a default-constructed value in there at all times, and I'm not yet totally sold on the current assignment operator implementations (relative to a by-value assignment operator that just does |
Can I run the existing tests with ubsan? I am running tests like so and they fail on master:
Is this the right way to run them?
Yeap the old optional was broken. ctl::optional<std::string> s;
s.reset(); // destroy the default constructed string
s = std::string("42"); // assignment into a destroyed string (oops)
This also works but it is generally suboptimal as it involves 3 assignments vs 2 when implemented by hand. Most of the times compiler can elide but not always. If you want I can switch to pass by value and swap. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved for copyright.
Try |
Ran the tests with ubsan and they pass. Also added test that fails in old optional. |
Looks good. Merge at your leisure. |
Actually nvm I don't know if you have the power to push the button - I'll push the button. |
Anyway - thanks for this! |
We should probably look at this. The only compiler we really care about here (IIUC) is cosmoc++, which is based on gcc, which I'd be surprised if it couldn't elide the assignment. Plus you get to elide a conditional branch if you do it by-value. |
We have no control of |
Manually manage the lifetime of
value_
by using an anonymousunion
. This fixes a bunch of double-frees and double-constructs.Additionally move the
present_
flag last. WhenT
has paddingpresent_
will be placed there savingalignof(T)
bytes fromsizeof(optional<T>)
.