UB in crossbeam scoped threads?

so, i was reading the source code for crossbeam's scoped threads:

and it seems like the function basically transmutes the closure from Box<dyn 'env> to a Box<dyn 'static> and spawns it, and then joins it before returning.

however, afaik box does not guarantee a stable layout when T: !Sized, so does that not mean that transmuting is UB?

from the nomicon:

For repr(C) types and repr(transparent) types, layout is precisely defined. But for your run-of-the-mill repr(Rust) , it is not. Even different instances of the same generic type can have wildly different layout. Vec<i32> and Vec<u32> might have their fields in the same order, or they might not.

it seems to me that Box<dyn 'env> and Box<dyn 'static> are two different types, kinda like the Vec<{i32, u32}> example shown above

I think the rationale is that lifetimes are erased fairly early in compilation, so types differing only in a lifetime parameter can always be safely transmuted into each other, as far as layout guarantees are concerned.

In the particular case of Box<dyn SomeTrait + 'lifetime> the thing is even more clear since variance allows conversion of Box<dyn SomeTrait + 'a> into Box<dyn SomeTrait + 'b> whenever 'b: 'a anyways, even behind one (or multiple) reference(s), e.g. &Box<dyn SomeTrait + 'a> into &Box<dyn SomeTrait + 'b> which underlines that the two types must have the same layout.

4 Likes

~i'm not qualified to verify the first part of your answer, since i dont know much about rust compiler internals, so i will not.~

so i think the rust compiler internally manages the layouts, so it can convert between different types and lifetimes safely. however, transmute does not do that. it literally just reinterprets the bits no matter if their layouts. so i think variance being able to convert between different types and as casts are very different to transmute.

idk tho, i could be wrong, and i hope i am, because i dont want one of rust's most used library to have holes.

This is in fact simpler: lifetimes does not affect layout (or any codegen). All that they do is describe the functions and types to the borrow checker, all other parts of compilation pipeline just ignore them, so T<'a> and T<'b> at runtime are always the same.

1 Like

hmm, just to confirm: does what you said apply even to Box<dyn FnOnce() + Send + 'lt>

Of course, it's not special here.

2 Likes

thanks goodness, or rather, you and @steffahn !

i'm afraid that i can't mark both of yours as answers, so i will have to go with the one who finally cleared my doubts... so thanks @Cerber-Ursi

btw, @steffahn , rest assured that i appreciate your time spent trying to help me.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.