Normally, a static is not placed in .rodata if it contains an UnsafeCell. However, this doesn't work for PhantomData<UnsafeCell> fields:
struct Test(i32, PhantomData<UnsafeCell<i32>>);
static TEST: Test = Test(0, PhantomData);
The TEST static is placed in .rodata, which is surprising to me.
Example where this misconception leads to undefined behavior: https://is.gd/M3ozkx
cc @oli-obk
TEST.0 is shared data that's not in an UnsafeCell. AFAIK mutating such data causes undefined behavior.
It's good that PhantomData placed the static in .rodata -- this makes the UB easy to detect.
Nominating due to my desire for all soundness bugs to have assigned priority tags.
I don't consider this a soundness bug. In fact, I think that the existing behavior is probably correct, although it is to some extent an unsafe code guidelines issue (but this is not an area where there has ever been disagreement, to my knowledge). I believe that mutating field .0 would be illegal even if we treated the PhantomData<UnsafeCell<T>> as preventing the field from going into rodata -- in other words, the compiler might be validly able to assume that the .0 field is not changed (along with any other fields not actually contained within an UnsafeCell).
The right way to encode this is struct Foo(UnsafeCell<i32>).
Closing therefore, feel free to follow-up! :)
Most helpful comment
TEST.0is shared data that's not in anUnsafeCell. AFAIK mutating such data causes undefined behavior.It's good that
PhantomDataplaced the static in.rodata-- this makes the UB easy to detect.