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

Validity of Box<T> #145

Open
RalfJung opened this issue Jun 18, 2019 · 15 comments
Open

Validity of Box<T> #145

RalfJung opened this issue Jun 18, 2019 · 15 comments
Labels
A-validity Topic: Related to validity invariants S-pending-design Status: Resolving this issue requires addressing some open design questions

Comments

@RalfJung
Copy link
Member

RalfJung commented Jun 18, 2019

What is the validity invariant of Box<T>? If this was just a library type it would be the same as Unique<T>, which is the same as NonNull<T>. But actually most of the compiler treats Box<T> a lot like a reference, so at least de-facto right now, Box<T> likely has the same validity invariant as &T and &mut T (which is discussed in #76 and #77).

Also see some prior discussion in rust-lang/rust-memory-model#3.

@gnzlbg
Copy link
Contributor

gnzlbg commented Jun 18, 2019

I think that the validity invariant of Box is the same as NonNull<T>.

The safety invariant of Box are different.

@hanna-kruppe
Copy link

Boxes get annotated with attributes/metadata like noalias, align, dereferenceable, etc. which makes it immediate UB to e.g. pass an unaligned Box or a dangling Box around. Treating Box as just a non-null raw pointer is not enough to justify that.

@gnzlbg
Copy link
Contributor

gnzlbg commented Jun 18, 2019

Thanks for pointing that out.

Summary from Discord chat with @rkruppe: Currently we generate noalias for Box, and noalias is only allowed on function arguments and return values in LLVM-IR. This means that if we want to generate the same LLVM-IR that we generate today, the validity invariant for Box needs to be pretty much that of &mut T.

We also talked about whether it would be possible to enforce noalias on access to the Box only, (e.g. Deref/DerefMut could cast the NonNull<T> to a &mut T, and dereference that). This would allow relaxing the validity invariant of Box, and make noalias and the other properties part of its safety invariant. But this does not appear to be possible with LLVM today, and might never be. Relaxing the validity invariant does not enable users to do anything new, since they can always start using NonNull, and only upgrade to Box when the validity invariant is satisfied.

@RalfJung
Copy link
Member Author

We really emit dereferencable? That's interesting, considering that the Box might well be deallocated during the functions runtime! For this reason, Stacked Borrows does not add a "protector" for Box (formerly "barrier", that's the mechanism that Stacked Borrows uses to justify the dereferencable attribute by making sure that the reference remains dereferencable during the entire runtime of the function).

@gnzlbg
Copy link
Contributor

gnzlbg commented Jun 18, 2019

We really emit dereferencable?

@RalfJung This (https://rust.godbolt.org/z/E6Sl8a):

fn foo(x: Box<i32>) -> i32 { *x }

produces

define i32 @foo(i32* noalias align 4 dereferenceable(4)) unnamed_addr #0 {
start:
  %1 = load i32, i32* %0, align 4
  %2 = bitcast i32* %0 to i8*
  tail call void @__rust_dealloc(i8* nonnull %2, i64 4, i64 4) #1
  ret i32 %1
}

@nico-abram
Copy link

The godbolt link doesn't seem to produce dereferenceable any more

@RalfJung
Copy link
Member Author

RalfJung commented Feb 3, 2020

Yes, that was changed with rust-lang/rust#66645.

@nico-abram

This comment has been minimized.

@RalfJung

This comment has been minimized.

@nico-abram

This comment has been minimized.

@RalfJung

This comment has been minimized.

@jonhoo

This comment has been minimized.

@RalfJung
Copy link
Member Author

I created #258 for the aliasing rules for Box.

@JakobDegen
Copy link
Contributor

@RalfJung thoughts on leaving this open? We closed #76 . Maybe it's useful to have an issue about what the weaker validity invariants around box could be, but that would be premised on the answer to #258 being sufficiently weak

@RalfJung
Copy link
Member Author

RalfJung commented Aug 2, 2023

Some other issues that surely are relevant:

There are at least two questions which currently don't have another issue tracking them:

  • Does Box have to be aligned? If the answer is "yes" then there already is magic involved since NonNull obviously doesn't have to be aligned.
  • Is there any kind of derefencability requirement?

Basically there are a whole lot of axes and along each of them we can ask whether Box behaves like a reference or like NonNull, or maybe something in between (such as Unique). Right now for Miri the answer is basically always "like a mutable reference", except to account for "Box can be deallocated while the function is running". Many people consider that too strong. I am fairly sure that we do want alignment niches for Box though? So, I doubt the end result will be "like NonNull".

I would say let's track aliasing in #326, and everything else here. The alignment question and Box<!> is independent of the aliasing question. If we go for just Unique-style aliasing requirements (or no aliasing requirements), the wide pointer question and dereferenceability also become independent.

@RalfJung RalfJung added S-pending-design Status: Resolving this issue requires addressing some open design questions and removed C-active-discussion-topic labels Aug 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-validity Topic: Related to validity invariants S-pending-design Status: Resolving this issue requires addressing some open design questions
Projects
None yet
Development

No branches or pull requests

6 participants