Skip to content

Commit a71aef1

Browse files
committed
C string function shims: consistently treat "invalid" pointers as UB
1 parent 9d3e9b4 commit a71aef1

File tree

6 files changed

+46
-6
lines changed

6 files changed

+46
-6
lines changed

src/shims/foreign_items.rs

+12
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
690690
let right = this.read_pointer(right)?;
691691
let n = Size::from_bytes(this.read_target_usize(n)?);
692692

693+
// C requires that this must always be a valid pointer (C18 §7.1.4).
694+
this.ptr_get_alloc_id(left)?;
695+
this.ptr_get_alloc_id(right)?;
696+
693697
let result = {
694698
let left_bytes = this.read_bytes_ptr_strip_provenance(left, n)?;
695699
let right_bytes = this.read_bytes_ptr_strip_provenance(right, n)?;
@@ -714,6 +718,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
714718
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
715719
let val = val as u8;
716720

721+
// C requires that this must always be a valid pointer (C18 §7.1.4).
722+
this.ptr_get_alloc_id(ptr)?;
723+
717724
if let Some(idx) = this
718725
.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(num))?
719726
.iter()
@@ -738,6 +745,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
738745
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
739746
let val = val as u8;
740747

748+
// C requires that this must always be a valid pointer (C18 §7.1.4).
749+
this.ptr_get_alloc_id(ptr)?;
750+
741751
let idx = this
742752
.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(num))?
743753
.iter()
@@ -752,6 +762,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
752762
"strlen" => {
753763
let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
754764
let ptr = this.read_pointer(ptr)?;
765+
// This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
755766
let n = this.read_c_str(ptr)?.len();
756767
this.write_scalar(
757768
Scalar::from_target_usize(u64::try_from(n).unwrap(), this),
@@ -791,6 +802,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
791802
// pointer provenance is preserved by this implementation of `strcpy`.
792803
// That is probably overly cautious, but there also is no fundamental
793804
// reason to have `strcpy` destroy pointer provenance.
805+
// This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
794806
let n = this.read_c_str(ptr_src)?.len().checked_add(1).unwrap();
795807
this.mem_copy(
796808
ptr_src,

tests/fail/shims/memchr_null.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
1+
error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
22
--> $DIR/memchr_null.rs:LL:CC
33
|
44
LL | libc::memchr(ptr::null(), 0, 0);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

tests/fail/shims/memcmp_null.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
1+
error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
22
--> $DIR/memcmp_null.rs:LL:CC
33
|
44
LL | libc::memcmp(ptr::null(), ptr::null(), 0);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

tests/fail/shims/memcmp_zero.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@ignore-target-windows: No libc on Windows
2+
//@compile-flags: -Zmiri-permissive-provenance
3+
4+
// C says that passing "invalid" pointers is UB for all string functions.
5+
// It is unclear whether `(int*)42` is "invalid", but there is no actually
6+
// a `char` living at that address, so arguably it cannot be a valid pointer.
7+
// Hence this is UB.
8+
fn main() {
9+
let ptr = 42 as *const u8;
10+
unsafe {
11+
libc::memcmp(ptr.cast(), ptr.cast(), 0); //~ERROR: dangling
12+
}
13+
}

tests/fail/shims/memcmp_zero.stderr

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance)
2+
--> $DIR/memcmp_zero.rs:LL:CC
3+
|
4+
LL | libc::memcmp(ptr.cast(), ptr.cast(), 0);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance)
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `main` at $DIR/memcmp_zero.rs:LL:CC
11+
12+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
13+
14+
error: aborting due to previous error
15+

tests/fail/shims/memrchr_null.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
1+
error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
22
--> $DIR/memrchr_null.rs:LL:CC
33
|
44
LL | libc::memrchr(ptr::null(), 0, 0);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

0 commit comments

Comments
 (0)