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

A really sad solution to extern type: special case reference-to-ZST #305

Open
CAD97 opened this issue Sep 21, 2021 · 1 comment
Open

A really sad solution to extern type: special case reference-to-ZST #305

CAD97 opened this issue Sep 21, 2021 · 1 comment

Comments

@CAD97
Copy link

CAD97 commented Sep 21, 2021

The topical issue is that it is common for FFI libraries (and even pure-Rust libraries, sometimes) to use &(), &[Align; 0], &c_void, or some newtype wrappers of such as an opaque shared pointer to "some opaque object" which otherwise fits with Rust's & semantics.

The rustnomicon recommends this ZST approach (with ?Sync, ?Send, ?Unpin markers) for opaque objects, and bindgen uses it, but both manage to only ever mention using it with raw pointers, never with references. However, they also don't warn off using references, and I know it's not uncommon to see in practice (e.g. cxx will freely emit references to extern FFI types).

The problem comes from SB's reborrowing: this reduces the provenance of the reference to just what the ZST type indicates – zero bytes – even though it's trying to represent a type of unknown size rather than one of known zero size.

The proper solution is extern type (and SB to accommodate it), no questions asked. But extern type has been unstable for a long time, and the longer it's unstable, the more code which is using &ZST will emerge.

So I thought of a really sad way of handling this without invasively changing a lot of SB's provenance handling: relax reborrowing for just reference-to-ZST. This explicitly ignores the &Header-to-VLA use-case in favor of minimally patching SB to support &OpaqueZST.

I don't think it'd be as simple as just not emitting reborrow guards for reference-to-ZST, but since real reference-to-ZST can't be used to access memory locations anyway, it should be sound to allow them to carry around (potentially invalidated) provenance, which could be then used when cast back to a pointer.

More formally, with the snippet

let a: *const [u8; 8];
let b = &*(a as *const [u8; 0]);
let c = a as *const [u8; 0] as *const [u8; 8]; 

No matter a's provenance, current SB (AIUI) would give b Shr provenance over 0 bytes, and thus c also has provenance over 0 bytes. Under this "solution", because b is a reference-to-ZST, it would retain Raw provenance equal to that of a (note that gaining Shr provenance to more than 0 bytes would be potentially an unsound race introduction), which would then be inherited by c as well, allowing c to be validly used.

I describe this as a sad solution, because the full solution would relax the requirements to handle &Header-to-VLA as well, and this is an ugly special case in an otherwise very uniform model.

@CAD97
Copy link
Author

CAD97 commented Sep 21, 2021

Heavily related: #276, #256, and #134.

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

1 participant