Skip to content

Commit e237075

Browse files
committed
Auto merge of #138114 - compiler-errors:rollup-7xr4b69, r=compiler-errors
Rollup of 25 pull requests Successful merges: - #135733 (Implement `&pin const self` and `&pin mut self` sugars) - #135895 (Document workings of successors more clearly) - #136922 (Pattern types: Avoid having to handle an Option for range ends in the type system or the HIR) - #137303 (Remove `MaybeForgetReturn` suggestion) - #137327 (Undeprecate env::home_dir) - #137358 (Match Ergonomics 2024: add context and examples to the unstable book) - #137534 ([rustdoc] hide item that is not marked as doc(inline) and whose src is doc(hidden)) - #137565 (Try to point of macro expansion from resolver and method errors if it involves macro var) - #137637 (Check dyn flavor before registering upcast goal on wide pointer cast in MIR typeck) - #137643 (Add DWARF test case for non-C-like `repr128` enums) - #137744 (Re-add `Clone`-derive on `Thir`) - #137758 (fix usage of ty decl macro fragments in attributes) - #137764 (Ensure that negative auto impls are always applicable) - #137772 (Fix char count in `Display` for `ByteStr`) - #137798 (ci: use ubuntu 24 on arm large runner) - #137802 (miri native-call support: all previously exposed provenance is accessible to the callee) - #137805 (adjust Layout debug printing to match the internal field name) - #137808 (Do not require that unsafe fields lack drop glue) - #137820 (Clarify why InhabitedPredicate::instantiate_opt exists) - #137825 (Provide more context on resolve error caused from incorrect RTN) - #137834 (rustc_fluent_macro: use CARGO_CRATE_NAME instead of CARGO_PKG_NAME) - #137868 (Add minimal platform support documentation for powerpc-unknown-linux-gnuspe) - #137910 (Improve error message for `AsyncFn` trait failure for RPIT) - #137920 (interpret/provenance_map: consistently use range_is_empty) - #138038 (Update `compiler-builtins` to 0.1.151) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 0f308fc + 45b598f commit e237075

File tree

7 files changed

+120
-54
lines changed

7 files changed

+120
-54
lines changed

Diff for: src/alloc_addresses/mod.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,19 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
285285

286286
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
287287
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
288-
fn expose_ptr(&self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> {
288+
fn expose_provenance(&self, provenance: Provenance) -> InterpResult<'tcx> {
289289
let this = self.eval_context_ref();
290290
let mut global_state = this.machine.alloc_addresses.borrow_mut();
291+
292+
let (alloc_id, tag) = match provenance {
293+
Provenance::Concrete { alloc_id, tag } => (alloc_id, tag),
294+
Provenance::Wildcard => {
295+
// No need to do anything for wildcard pointers as
296+
// their provenances have already been previously exposed.
297+
return interp_ok(());
298+
}
299+
};
300+
291301
// In strict mode, we don't need this, so we can save some cycles by not tracking it.
292302
if global_state.provenance_mode == ProvenanceMode::Strict {
293303
return interp_ok(());
@@ -422,6 +432,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
422432
let rel_offset = this.truncate_to_target_usize(addr.bytes().wrapping_sub(base_addr));
423433
Some((alloc_id, Size::from_bytes(rel_offset)))
424434
}
435+
436+
/// Prepare all exposed memory for a native call.
437+
/// This overapproximates the modifications which external code might make to memory:
438+
/// We set all reachable allocations as initialized, mark all reachable provenances as exposed
439+
/// and overwrite them with `Provenance::WILDCARD`.
440+
fn prepare_exposed_for_native_call(&mut self) -> InterpResult<'tcx> {
441+
let this = self.eval_context_mut();
442+
// We need to make a deep copy of this list, but it's fine; it also serves as scratch space
443+
// for the search within `prepare_for_native_call`.
444+
let exposed: Vec<AllocId> =
445+
this.machine.alloc_addresses.get_mut().exposed.iter().copied().collect();
446+
this.prepare_for_native_call(exposed)
447+
}
425448
}
426449

427450
impl<'tcx> MiriMachine<'tcx> {

Diff for: src/machine.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -1291,18 +1291,12 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
12911291
/// Called on `ptr as usize` casts.
12921292
/// (Actually computing the resulting `usize` doesn't need machine help,
12931293
/// that's just `Scalar::try_to_int`.)
1294+
#[inline(always)]
12941295
fn expose_provenance(
12951296
ecx: &InterpCx<'tcx, Self>,
12961297
provenance: Self::Provenance,
12971298
) -> InterpResult<'tcx> {
1298-
match provenance {
1299-
Provenance::Concrete { alloc_id, tag } => ecx.expose_ptr(alloc_id, tag),
1300-
Provenance::Wildcard => {
1301-
// No need to do anything for wildcard pointers as
1302-
// their provenances have already been previously exposed.
1303-
interp_ok(())
1304-
}
1305-
}
1299+
ecx.expose_provenance(provenance)
13061300
}
13071301

13081302
/// Convert a pointer with provenance into an allocation-offset pair and extra provenance info.

Diff for: src/shims/native_lib.rs

+6-10
Original file line numberDiff line numberDiff line change
@@ -160,16 +160,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
160160
}
161161
let imm = this.read_immediate(arg)?;
162162
libffi_args.push(imm_to_carg(&imm, this)?);
163-
// If we are passing a pointer, prepare the memory it points to.
163+
// If we are passing a pointer, expose its provenance. Below, all exposed memory
164+
// (previously exposed and new exposed) will then be properly prepared.
164165
if matches!(arg.layout.ty.kind(), ty::RawPtr(..)) {
165166
let ptr = imm.to_scalar().to_pointer(this)?;
166167
let Some(prov) = ptr.provenance else {
167-
// Pointer without provenance may not access any memory.
168-
continue;
169-
};
170-
// We use `get_alloc_id` for its best-effort behaviour with Wildcard provenance.
171-
let Some(alloc_id) = prov.get_alloc_id() else {
172-
// Wildcard pointer, whatever it points to must be already exposed.
168+
// Pointer without provenance may not access any memory anyway, skip.
173169
continue;
174170
};
175171
// The first time this happens, print a warning.
@@ -178,12 +174,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
178174
this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem);
179175
}
180176

181-
this.prepare_for_native_call(alloc_id, prov)?;
177+
this.expose_provenance(prov)?;
182178
}
183179
}
184180

185-
// FIXME: In the future, we should also call `prepare_for_native_call` on all previously
186-
// exposed allocations, since C may access any of them.
181+
// Prepare all exposed memory.
182+
this.prepare_exposed_for_native_call()?;
187183

188184
// Convert them to `libffi::high::Arg` type.
189185
let libffi_args = libffi_args

Diff for: tests/native-lib/pass/ptr_write_access.rs

+36-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#![feature(box_as_ptr)]
77

88
use std::mem::MaybeUninit;
9-
use std::ptr::null;
9+
use std::ptr;
1010

1111
fn main() {
1212
test_increment_int();
@@ -20,6 +20,8 @@ fn main() {
2020
test_pass_dangling();
2121
test_swap_ptr_triple_dangling();
2222
test_return_ptr();
23+
test_pass_ptr_as_int();
24+
test_pass_ptr_via_previously_shared_mem();
2325
}
2426

2527
/// Test function that modifies an int.
@@ -112,7 +114,7 @@ fn test_swap_ptr() {
112114
}
113115

114116
let x = 61;
115-
let (mut ptr0, mut ptr1) = (&raw const x, null());
117+
let (mut ptr0, mut ptr1) = (&raw const x, ptr::null());
116118

117119
unsafe { swap_ptr(&mut ptr0, &mut ptr1) };
118120
assert_eq!(unsafe { *ptr1 }, x);
@@ -131,7 +133,7 @@ fn test_swap_ptr_tuple() {
131133
}
132134

133135
let x = 71;
134-
let mut tuple = Tuple { ptr0: &raw const x, ptr1: null() };
136+
let mut tuple = Tuple { ptr0: &raw const x, ptr1: ptr::null() };
135137

136138
unsafe { swap_ptr_tuple(&mut tuple) }
137139
assert_eq!(unsafe { *tuple.ptr1 }, x);
@@ -148,7 +150,7 @@ fn test_overwrite_dangling() {
148150
drop(b);
149151

150152
unsafe { overwrite_ptr(&mut ptr) };
151-
assert_eq!(ptr, null());
153+
assert_eq!(ptr, ptr::null());
152154
}
153155

154156
/// Test function that passes a dangling pointer.
@@ -200,3 +202,33 @@ fn test_return_ptr() {
200202
let ptr = unsafe { return_ptr(ptr) };
201203
assert_eq!(unsafe { *ptr }, x);
202204
}
205+
206+
/// Test casting a pointer to an integer and passing that to C.
207+
fn test_pass_ptr_as_int() {
208+
extern "C" {
209+
fn pass_ptr_as_int(ptr: usize, set_to_val: i32);
210+
}
211+
212+
let mut m: MaybeUninit<i32> = MaybeUninit::uninit();
213+
unsafe { pass_ptr_as_int(m.as_mut_ptr() as usize, 42) };
214+
assert_eq!(unsafe { m.assume_init() }, 42);
215+
}
216+
217+
fn test_pass_ptr_via_previously_shared_mem() {
218+
extern "C" {
219+
fn set_shared_mem(ptr: *mut *mut i32);
220+
fn init_ptr_stored_in_shared_mem(val: i32);
221+
}
222+
223+
let mut m: *mut i32 = ptr::null_mut();
224+
let ptr_to_m = &raw mut m;
225+
unsafe { set_shared_mem(&raw mut m) };
226+
227+
let mut m2: MaybeUninit<i32> = MaybeUninit::uninit();
228+
// Store a pointer to m2 somewhere that C code can access it.
229+
unsafe { ptr_to_m.write(m2.as_mut_ptr()) };
230+
// Have C code write there.
231+
unsafe { init_ptr_stored_in_shared_mem(42) };
232+
// Ensure this memory is now considered initialized.
233+
assert_eq!(unsafe { m2.assume_init() }, 42);
234+
}

Diff for: tests/native-lib/ptr_read_access.c

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,34 @@
11
#include <stdio.h>
2+
#include <stdint.h>
23

34
// See comments in build_native_lib()
45
#define EXPORT __attribute__((visibility("default")))
56

67
/* Test: test_access_pointer */
78

8-
EXPORT void print_pointer(const int *ptr) {
9+
EXPORT void print_pointer(const int32_t *ptr) {
910
printf("printing pointer dereference from C: %d\n", *ptr);
1011
}
1112

1213
/* Test: test_access_simple */
1314

1415
typedef struct Simple {
15-
int field;
16+
int32_t field;
1617
} Simple;
1718

18-
EXPORT int access_simple(const Simple *s_ptr) {
19+
EXPORT int32_t access_simple(const Simple *s_ptr) {
1920
return s_ptr->field;
2021
}
2122

2223
/* Test: test_access_nested */
2324

2425
typedef struct Nested {
25-
int value;
26+
int32_t value;
2627
struct Nested *next;
2728
} Nested;
2829

2930
// Returns the innermost/last value of a Nested pointer chain.
30-
EXPORT int access_nested(const Nested *n_ptr) {
31+
EXPORT int32_t access_nested(const Nested *n_ptr) {
3132
// Edge case: `n_ptr == NULL` (i.e. first Nested is None).
3233
if (!n_ptr) { return 0; }
3334

@@ -41,10 +42,10 @@ EXPORT int access_nested(const Nested *n_ptr) {
4142
/* Test: test_access_static */
4243

4344
typedef struct Static {
44-
int value;
45+
int32_t value;
4546
struct Static *recurse;
4647
} Static;
4748

48-
EXPORT int access_static(const Static *s_ptr) {
49+
EXPORT int32_t access_static(const Static *s_ptr) {
4950
return s_ptr->recurse->recurse->value;
5051
}

Diff for: tests/native-lib/ptr_write_access.c

+37-18
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
#include <stddef.h>
2+
#include <stdint.h>
23

34
// See comments in build_native_lib()
45
#define EXPORT __attribute__((visibility("default")))
56

67
/* Test: test_increment_int */
78

8-
EXPORT void increment_int(int *ptr) {
9+
EXPORT void increment_int(int32_t *ptr) {
910
*ptr += 1;
1011
}
1112

1213
/* Test: test_init_int */
1314

14-
EXPORT void init_int(int *ptr, int val) {
15+
EXPORT void init_int(int32_t *ptr, int32_t val) {
1516
*ptr = val;
1617
}
1718

1819
/* Test: test_init_array */
1920

20-
EXPORT void init_array(int *array, size_t len, int val) {
21+
EXPORT void init_array(int32_t *array, size_t len, int32_t val) {
2122
for (size_t i = 0; i < len; i++) {
2223
array[i] = val;
2324
}
@@ -26,65 +27,83 @@ EXPORT void init_array(int *array, size_t len, int val) {
2627
/* Test: test_init_static_inner */
2728

2829
typedef struct SyncPtr {
29-
int *ptr;
30+
int32_t *ptr;
3031
} SyncPtr;
3132

32-
EXPORT void init_static_inner(const SyncPtr *s_ptr, int val) {
33+
EXPORT void init_static_inner(const SyncPtr *s_ptr, int32_t val) {
3334
*(s_ptr->ptr) = val;
3435
}
3536

3637
/* Tests: test_exposed, test_pass_dangling */
3738

38-
EXPORT void ignore_ptr(__attribute__((unused)) const int *ptr) {
39+
EXPORT void ignore_ptr(__attribute__((unused)) const int32_t *ptr) {
3940
return;
4041
}
4142

4243
/* Test: test_expose_int */
43-
EXPORT void expose_int(const int *int_ptr, const int **pptr) {
44+
EXPORT void expose_int(const int32_t *int_ptr, const int32_t **pptr) {
4445
*pptr = int_ptr;
4546
}
4647

4748
/* Test: test_swap_ptr */
4849

49-
EXPORT void swap_ptr(const int **pptr0, const int **pptr1) {
50-
const int *tmp = *pptr0;
50+
EXPORT void swap_ptr(const int32_t **pptr0, const int32_t **pptr1) {
51+
const int32_t *tmp = *pptr0;
5152
*pptr0 = *pptr1;
5253
*pptr1 = tmp;
5354
}
5455

5556
/* Test: test_swap_ptr_tuple */
5657

5758
typedef struct Tuple {
58-
int *ptr0;
59-
int *ptr1;
59+
int32_t *ptr0;
60+
int32_t *ptr1;
6061
} Tuple;
6162

6263
EXPORT void swap_ptr_tuple(Tuple *t_ptr) {
63-
int *tmp = t_ptr->ptr0;
64+
int32_t *tmp = t_ptr->ptr0;
6465
t_ptr->ptr0 = t_ptr->ptr1;
6566
t_ptr->ptr1 = tmp;
6667
}
6768

6869
/* Test: test_overwrite_dangling */
6970

70-
EXPORT void overwrite_ptr(const int **pptr) {
71+
EXPORT void overwrite_ptr(const int32_t **pptr) {
7172
*pptr = NULL;
7273
}
7374

7475
/* Test: test_swap_ptr_triple_dangling */
7576

7677
typedef struct Triple {
77-
int *ptr0;
78-
int *ptr1;
79-
int *ptr2;
78+
int32_t *ptr0;
79+
int32_t *ptr1;
80+
int32_t *ptr2;
8081
} Triple;
8182

8283
EXPORT void swap_ptr_triple_dangling(Triple *t_ptr) {
83-
int *tmp = t_ptr->ptr0;
84+
int32_t *tmp = t_ptr->ptr0;
8485
t_ptr->ptr0 = t_ptr->ptr2;
8586
t_ptr->ptr2 = tmp;
8687
}
8788

88-
EXPORT const int *return_ptr(const int *ptr) {
89+
EXPORT const int32_t *return_ptr(const int32_t *ptr) {
8990
return ptr;
9091
}
92+
93+
/* Test: test_pass_ptr_as_int */
94+
95+
EXPORT void pass_ptr_as_int(uintptr_t ptr, int32_t set_to_val) {
96+
*(int32_t*)ptr = set_to_val;
97+
}
98+
99+
/* Test: test_pass_ptr_via_previously_shared_mem */
100+
101+
int32_t** shared_place;
102+
103+
EXPORT void set_shared_mem(int32_t** ptr) {
104+
shared_place = ptr;
105+
}
106+
107+
EXPORT void init_ptr_stored_in_shared_mem(int32_t val) {
108+
**shared_place = val;
109+
}

Diff for: tests/native-lib/scalar_arguments.c

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
#include <stdio.h>
2+
#include <stdint.h>
23

34
// See comments in build_native_lib()
45
#define EXPORT __attribute__((visibility("default")))
56

6-
EXPORT int add_one_int(int x) {
7+
EXPORT int32_t add_one_int(int32_t x) {
78
return 2 + x;
89
}
910

@@ -13,23 +14,23 @@ EXPORT void printer(void) {
1314

1415
// function with many arguments, to test functionality when some args are stored
1516
// on the stack
16-
EXPORT int test_stack_spill(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) {
17+
EXPORT int32_t test_stack_spill(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f, int32_t g, int32_t h, int32_t i, int32_t j, int32_t k, int32_t l) {
1718
return a+b+c+d+e+f+g+h+i+j+k+l;
1819
}
1920

20-
EXPORT unsigned int get_unsigned_int(void) {
21+
EXPORT uint32_t get_unsigned_int(void) {
2122
return -10;
2223
}
2324

24-
EXPORT short add_int16(short x) {
25+
EXPORT short add_int16(int16_t x) {
2526
return x + 3;
2627
}
2728

28-
EXPORT long add_short_to_long(short x, long y) {
29+
EXPORT long add_short_to_long(int16_t x, int64_t y) {
2930
return x + y;
3031
}
3132

3233
// To test that functions not marked with EXPORT cannot be called by Miri.
33-
int not_exported(void) {
34+
int32_t not_exported(void) {
3435
return 0;
3536
}

0 commit comments

Comments
 (0)