Skip to content

Commit 7269379

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 7269379

File tree

1 file changed

+30
-3
lines changed

1 file changed

+30
-3
lines changed

crates/bevy_ecs/src/storage/blob_vec.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,37 @@ 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 {
5380
BlobVec {
54-
swap_scratch: NonNull::dangling(),
55-
data: NonNull::dangling(),
81+
swap_scratch: dangling,
82+
data: dangling,
5683
capacity: usize::MAX,
5784
len: 0,
5885
item_layout,
@@ -63,7 +90,7 @@ impl BlobVec {
6390
.unwrap_or_else(|| std::alloc::handle_alloc_error(item_layout));
6491
let mut blob_vec = BlobVec {
6592
swap_scratch,
66-
data: NonNull::dangling(),
93+
data: dangling,
6794
capacity: 0,
6895
len: 0,
6996
item_layout,

0 commit comments

Comments
 (0)