Skip to content

Commit b1c8717

Browse files
Fix UB in empty slice related code
* This actually fixes an issue that was already present in the codebase too
1 parent 7418ebc commit b1c8717

File tree

1 file changed

+32
-3
lines changed

1 file changed

+32
-3
lines changed

crates/bevy_ecs/src/storage/blob_vec.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,39 @@ impl BlobVec {
4949
drop: Option<unsafe fn(OwningPtr<'_>)>,
5050
capacity: usize,
5151
) -> BlobVec {
52+
/*NOTE: dangling pointers still need to be well aligned for the type when using slices (even though they are 0-length).
53+
This is important for [`SimdAlignedVec`] and any function that would return a slice view of this BlobVec.
54+
It is also important if the BlobVec contains ZSTs and is mutably queried, as this will entail the
55+
creation of a slice (even if 0-length).
56+
57+
Since neither strict_provenance nor alloc_layout_extra is stable, there is no way to construct a NonNull::dangling()
58+
pointer from `item_layout`. Creating an aligned NonNull dangling pointer manually with integer casts works, but Miri doesn't like that,
59+
and it could break in the future. Instead, assume that `MAX_SIMD_ALIGNMENT` will be the greatest alignment required of any
60+
possible instruction on the system and create a dangling pointer out of a type guaranteed to need that alignment.
61+
62+
Currently, that type is batch::AlignedBatch64.
63+
64+
TODO: In the future, this restriction can be easily removed when either `strict_provenance` or `Layout::dangling()` becomes stable.
65+
66+
67+
Obviously, this won't make sense if the contained type needs more alignment than that.
68+
Therefore we have the following check:
69+
*/
70+
71+
if item_layout.align() > batch::MAX_SIMD_ALIGNMENT {
72+
panic!(
73+
"Attempted to create a BlobVec with an item layout alignment > MAX_SIMD_ALIGNMENT"
74+
);
75+
}
76+
77+
let dangling = NonNull::<batch::AlignedBatch64<(), 4>>::dangling().cast::<u8>();
78+
5279
if item_layout.size() == 0 {
80+
let data_dangling = NonNull::<batch::AlignedBatch64<(), 4>>::dangling().cast::<u8>();
81+
5382
BlobVec {
54-
swap_scratch: NonNull::dangling(),
55-
data: NonNull::dangling(),
83+
swap_scratch: dangling,
84+
data: dangling,
5685
capacity: usize::MAX,
5786
len: 0,
5887
item_layout,
@@ -63,7 +92,7 @@ impl BlobVec {
6392
.unwrap_or_else(|| std::alloc::handle_alloc_error(item_layout));
6493
let mut blob_vec = BlobVec {
6594
swap_scratch,
66-
data: NonNull::dangling(),
95+
data: dangling,
6796
capacity: 0,
6897
len: 0,
6998
item_layout,

0 commit comments

Comments
 (0)