Skip to content
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

offset_of! is unsound #1564

Open
kazcw opened this issue Jan 29, 2020 · 6 comments
Open

offset_of! is unsound #1564

kazcw opened this issue Jan 29, 2020 · 6 comments

Comments

@kazcw
Copy link

kazcw commented Jan 29, 2020

offset_of! is unsound. There's no right way to implement it until RFC #2582 is implemented. The RFC describes why things like the ptr::null trick are invalid:

references must be aligned and dereferencable, even when they are created and never used.

@shaleh
Copy link
Collaborator

shaleh commented Jan 29, 2020

@kazcw what is our alternative? How likely is this to fail in practice?

@kazcw
Copy link
Author

kazcw commented Jan 30, 2020

If it were just a matter of breaking rustc's invariants that might not be as bad, because rustc itself doesn't do a lot of wild optimizations; but it compiles to getelementptr inbounds { ... }, { ... }* null, ..., which is a trap value to LLVM, causing the subsequent ptrtoint to be UB, and leaving you at LLVM's mercy. LLVM's mercy tends to involve nasal demons.

In this case one option would be: instead of doing the address calculations using a hypothetical instance at NULL, use a real instance. Since this macro is only used with C structs, and Rust has no constraints on the value range of fields in C structs, the example value can be conjured with mem::zeroed. You could use a trivial trait to mark that the types it operates on can be zero-initialized safely, and then use the trait's method instead of ptr::null(). In release builds the example value will be optimized away.

@shaleh
Copy link
Collaborator

shaleh commented Jan 30, 2020

Thank you for the explanation @kazcw that is very helpful.

@shaleh
Copy link
Collaborator

shaleh commented Jan 30, 2020

Ok, let's try moving to https://github.com/Gilnaa/memoffset.
This does NOT fix the problem that @kazcw raises. However, it moves the problem of solving it out of our code base. They have ideas and are looking at using solutions from the RFC mentioned which has actually been more than partially implemented. Long term, there may end up being a supported macro from the Rust core and we drop the dependency. A pre-RFC exists for such a macro currently.

@agraven
Copy link
Collaborator

agraven commented Aug 9, 2020

In that case I presume we need to replace the usage of offset_of! the field-offset crate in LispBufferRef::reset_local_variables as well? (I didn't realize we had our own macro when I imported that crate)

@RalfJung
Copy link

RalfJung commented Apr 3, 2021

FWIW, the latest version of https://github.com/Gilnaa/memoffset actually works in a way that is compliant with the Rust Reference. :)

But doing * on a NULL pointer is still UB, even inside addr_of!.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants