Skip to content

Commit 26f2b66

Browse files
committed
size_of_val_raw: for length 0 this is safe to call
1 parent 16e8803 commit 26f2b66

File tree

4 files changed

+43
-0
lines changed

4 files changed

+43
-0
lines changed

Diff for: library/core/src/alloc/layout.rs

+2
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ impl Layout {
183183
/// - a [slice], then the length of the slice tail must be an initialized
184184
/// integer, and the size of the *entire value*
185185
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
186+
/// For the special case where the dynamic tail length is 0, this function
187+
/// is safe to call.
186188
/// - a [trait object], then the vtable part of the pointer must point
187189
/// to a valid vtable for the type `T` acquired by an unsizing coercion,
188190
/// and the size of the *entire value*

Diff for: library/core/src/mem/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,12 @@ pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
359359
/// - a [slice], then the length of the slice tail must be an initialized
360360
/// integer, and the size of the *entire value*
361361
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
362+
/// For the special case where the dynamic tail length is 0, this function
363+
/// is safe to call.
364+
// NOTE: the reason this is safe is that if an overflow were to occur already with size 0,
365+
// then we would stop compilation as even the "statically known" part of the type would
366+
// already be too big (or the call may be in dead code and optimized away, but then it
367+
// doesn't matter).
362368
/// - a [trait object], then the vtable part of the pointer must point
363369
/// to a valid vtable acquired by an unsizing coercion, and the size
364370
/// of the *entire value* (dynamic tail length + statically sized prefix)
@@ -506,6 +512,8 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
506512
/// - a [slice], then the length of the slice tail must be an initialized
507513
/// integer, and the size of the *entire value*
508514
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
515+
/// For the special case where the dynamic tail length is 0, this function
516+
/// is safe to call.
509517
/// - a [trait object], then the vtable part of the pointer must point
510518
/// to a valid vtable acquired by an unsizing coercion, and the size
511519
/// of the *entire value* (dynamic tail length + statically sized prefix)

Diff for: tests/ui/layout/size-of-val-raw-too-big.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ build-fail
2+
//@ compile-flags: --target i686-unknown-linux-gnu --crate-type lib
3+
//@ needs-llvm-components: x86
4+
//@ error-pattern: too big for the current architecture
5+
#![feature(no_core, lang_items, intrinsics)]
6+
#![allow(internal_features)]
7+
#![no_std]
8+
#![no_core]
9+
10+
#[lang = "sized"]
11+
pub trait Sized {}
12+
#[lang = "copy"]
13+
pub trait Copy: Sized {}
14+
15+
// 0x7fffffff is fine, but with the padding for the unsized tail it is too big.
16+
#[repr(C)]
17+
pub struct Example([u8; 0x7fffffff], [u16]);
18+
19+
extern "rust-intrinsic" {
20+
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
21+
}
22+
23+
// We guarantee that with length 0, `size_of_val_raw` (which calls the `size_of_val` intrinsic)
24+
// is safe to call. The compiler aborts execution if a length of 0 would overflow.
25+
// So let's construct a case where length 0 just barely overflows, and ensure that
26+
// does abort execution.
27+
pub fn check(x: *const Example) {
28+
unsafe { size_of_val(x); }
29+
}

Diff for: tests/ui/layout/size-of-val-raw-too-big.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
error: values of the type `Example` are too big for the current architecture
2+
3+
error: aborting due to 1 previous error
4+

0 commit comments

Comments
 (0)