Skip to content

Commit eba85a6

Browse files
committed
organize posix/linux/macos shims and make some only available to libstd as they are incomplete
Looks like whatever the _SC_GETPW_R_SIZE_MAX sysconf was needed for, is no longer present, so we can get rid of it
1 parent 0d0a457 commit eba85a6

File tree

5 files changed

+122
-144
lines changed

5 files changed

+122
-144
lines changed

src/helpers.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
8181

8282
/// Helper function to get a `libc` constant as an `i32`.
8383
fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> {
84+
// TODO: Cache the result.
8485
self.eval_libc(name)?.to_i32()
8586
}
8687

src/shims/foreign_items.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
196196
// Here we dispatch all the shims for foreign functions. If you have a platform specific
197197
// shim, add it to the corresponding submodule.
198198
match link_name {
199+
// Standard C allocation
199200
"malloc" => {
200201
let size = this.read_scalar(args[0])?.to_machine_usize(this)?;
201202
let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C);
@@ -220,6 +221,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
220221
this.write_scalar(res, dest)?;
221222
}
222223

224+
// Rust allocation
225+
// (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic
226+
// allocation that also checks that all conditions are emt, such as not permitting zero-sized allocations.)
223227
"__rust_alloc" => {
224228
let size = this.read_scalar(args[0])?.to_machine_usize(this)?;
225229
let align = this.read_scalar(args[1])?.to_machine_usize(this)?;
@@ -274,6 +278,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
274278
this.write_scalar(new_ptr, dest)?;
275279
}
276280

281+
// C memory handling functions
277282
"memcmp" => {
278283
let left = this.read_scalar(args[0])?.not_undef()?;
279284
let right = this.read_scalar(args[1])?.not_undef()?;
@@ -293,7 +298,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
293298

294299
this.write_scalar(Scalar::from_int(result, Size::from_bits(32)), dest)?;
295300
}
296-
297301
"memrchr" => {
298302
let ptr = this.read_scalar(args[0])?.not_undef()?;
299303
let val = this.read_scalar(args[1])?.to_i32()? as u8;
@@ -311,7 +315,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
311315
this.write_null(dest)?;
312316
}
313317
}
314-
315318
"memchr" => {
316319
let ptr = this.read_scalar(args[0])?.not_undef()?;
317320
let val = this.read_scalar(args[1])?.to_i32()? as u8;
@@ -328,7 +331,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
328331
this.write_null(dest)?;
329332
}
330333
}
331-
332334
"strlen" => {
333335
let ptr = this.read_scalar(args[0])?.not_undef()?;
334336
let n = this.memory.read_c_str(ptr)?.len();
@@ -358,11 +360,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
358360
};
359361
this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?;
360362
}
361-
// underscore case for windows
362363
| "_hypotf"
363364
| "hypotf"
364365
| "atan2f"
365366
=> {
367+
// underscore case for windows, here and below
368+
// (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
366369
// FIXME: Using host floats.
367370
let f1 = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
368371
let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?);
@@ -373,7 +376,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
373376
};
374377
this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?;
375378
}
376-
377379
| "cbrt"
378380
| "cosh"
379381
| "sinh"
@@ -396,8 +398,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
396398
};
397399
this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?;
398400
}
399-
// underscore case for windows, here and below
400-
// (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
401401
| "_hypot"
402402
| "hypot"
403403
| "atan2"
@@ -412,11 +412,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
412412
};
413413
this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?;
414414
}
415-
// For radix-2 (binary) systems, `ldexp` and `scalbn` are the same.
416415
| "_ldexp"
417416
| "ldexp"
418417
| "scalbn"
419418
=> {
419+
// For radix-2 (binary) systems, `ldexp` and `scalbn` are the same.
420420
let x = this.read_scalar(args[0])?.to_f64()?;
421421
let exp = this.read_scalar(args[1])?.to_i32()?;
422422

@@ -434,6 +434,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
434434
this.write_scalar(Scalar::from_f64(res), dest)?;
435435
}
436436

437+
// Target-specific shims
437438
_ => match this.tcx.sess.target.target.target_os.as_str() {
438439
"linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
439440
"windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),

src/shims/foreign_items/posix.rs

Lines changed: 57 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2525
let result = this.getenv(args[0])?;
2626
this.write_scalar(result, dest)?;
2727
}
28-
2928
"unsetenv" => {
3029
let result = this.unsetenv(args[0])?;
3130
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
3231
}
33-
3432
"setenv" => {
3533
let result = this.setenv(args[0], args[1])?;
3634
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
3735
}
38-
3936
"getcwd" => {
4037
let result = this.getcwd(args[0], args[1])?;
4138
this.write_scalar(result, dest)?;
4239
}
43-
4440
"chdir" => {
4541
let result = this.chdir(args[0])?;
4642
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
@@ -51,17 +47,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
5147
let result = this.open(args[0], args[1])?;
5248
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
5349
}
54-
5550
"fcntl" => {
5651
let result = this.fcntl(args[0], args[1], args.get(2).cloned())?;
5752
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
5853
}
59-
6054
"read" => {
6155
let result = this.read(args[0], args[1], args[2])?;
6256
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
6357
}
64-
6558
"write" => {
6659
let fd = this.read_scalar(args[0])?.to_i32()?;
6760
let buf = this.read_scalar(args[1])?.not_undef()?;
@@ -95,43 +88,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
9588
// Now, `result` is the value we return back to the program.
9689
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
9790
}
98-
9991
"unlink" => {
10092
let result = this.unlink(args[0])?;
10193
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
10294
}
103-
10495
"symlink" => {
10596
let result = this.symlink(args[0], args[1])?;
10697
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
10798
}
108-
10999
"rename" => {
110100
let result = this.rename(args[0], args[1])?;
111101
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
112102
}
113-
114103
"mkdir" => {
115104
let result = this.mkdir(args[0], args[1])?;
116105
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
117106
}
118-
119107
"rmdir" => {
120108
let result = this.rmdir(args[0])?;
121109
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
122110
}
123-
124111
"closedir" => {
125112
let result = this.closedir(args[0])?;
126113
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
127114
}
128-
129115
"lseek" | "lseek64" => {
130116
let result = this.lseek64(args[0], args[1], args[2])?;
131117
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
132118
}
119+
"posix_fadvise" => {
120+
// fadvise is only informational, we can ignore it.
121+
this.write_null(dest)?;
122+
}
133123

134-
// Other shims
124+
// Allocation
135125
"posix_memalign" => {
136126
let ret = this.deref_operand(args[0])?;
137127
let align = this.read_scalar(args[1])?.to_machine_usize(this)?;
@@ -160,6 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
160150
this.write_null(dest)?;
161151
}
162152

153+
// Dynamic symbol loading
163154
"dlsym" => {
164155
let _handle = this.read_scalar(args[0])?;
165156
let symbol = this.read_scalar(args[1])?.not_undef()?;
@@ -174,7 +165,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
174165
}
175166
}
176167

177-
// Hook pthread calls that go to the thread-local storage memory subsystem.
168+
// Querying system information
169+
"sysconf" => {
170+
let name = this.read_scalar(args[0])?.to_i32()?;
171+
172+
let sysconfs = &[
173+
("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, dest.layout.size)),
174+
("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, dest.layout.size)),
175+
];
176+
let mut result = None;
177+
for &(sysconf_name, value) in sysconfs {
178+
let sysconf_name = this.eval_libc_i32(sysconf_name)?;
179+
if sysconf_name == name {
180+
result = Some(value);
181+
break;
182+
}
183+
}
184+
if let Some(result) = result {
185+
this.write_scalar(result, dest)?;
186+
} else {
187+
throw_unsup_format!("unimplemented sysconf name: {}", name)
188+
}
189+
}
190+
191+
// Thread-local storage
178192
"pthread_key_create" => {
179193
let key_place = this.deref_operand(args[0])?;
180194

@@ -221,36 +235,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
221235
this.write_null(dest)?;
222236
}
223237

224-
// Stack size/address stuff.
225-
| "pthread_attr_init"
226-
| "pthread_attr_destroy"
227-
| "pthread_self"
228-
| "pthread_attr_setstacksize" => {
229-
this.write_null(dest)?;
238+
// Better error for attempts to create a thread
239+
"pthread_create" => {
240+
throw_unsup_format!("Miri does not support threading");
230241
}
231-
"pthread_attr_getstack" => {
232-
let addr_place = this.deref_operand(args[1])?;
233-
let size_place = this.deref_operand(args[2])?;
234-
235-
this.write_scalar(
236-
Scalar::from_uint(STACK_ADDR, addr_place.layout.size),
237-
addr_place.into(),
238-
)?;
239-
this.write_scalar(
240-
Scalar::from_uint(STACK_SIZE, size_place.layout.size),
241-
size_place.into(),
242-
)?;
243242

244-
// Return success (`0`).
243+
// Miscellaneous
244+
"isatty" => {
245+
let _fd = this.read_scalar(args[0])?.to_i32()?;
246+
// "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error"
247+
// FIXME: we just say nothing is a terminal.
248+
let enotty = this.eval_libc("ENOTTY")?;
249+
this.set_last_error(enotty)?;
245250
this.write_null(dest)?;
246251
}
247-
248-
// We don't support threading.
249-
"pthread_create" => {
250-
throw_unsup_format!("Miri does not support threading");
252+
"pthread_atfork" => {
253+
let _prepare = this.read_scalar(args[0])?.not_undef()?;
254+
let _parent = this.read_scalar(args[1])?.not_undef()?;
255+
let _child = this.read_scalar(args[1])?.not_undef()?;
256+
// We do not support forking, so there is nothing to do here.
257+
this.write_null(dest)?;
251258
}
252259

253-
// Stub out calls for condvar, mutex and rwlock, to just return `0`.
260+
// Incomplete shims that we "stub out" just to get pre-main initialziation code to work.
261+
// These shims are enabled only when the caller is in the standard library.
262+
| "pthread_attr_init"
263+
| "pthread_attr_destroy"
264+
| "pthread_self"
265+
| "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => {
266+
this.write_null(dest)?;
267+
}
254268
| "pthread_mutexattr_init"
255269
| "pthread_mutexattr_settype"
256270
| "pthread_mutex_init"
@@ -266,68 +280,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
266280
| "pthread_condattr_setclock"
267281
| "pthread_cond_init"
268282
| "pthread_condattr_destroy"
269-
| "pthread_cond_destroy"
283+
| "pthread_cond_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::")
270284
=> {
271285
this.write_null(dest)?;
272286
}
273-
274-
// We don't support fork so we don't have to do anything for atfork.
275-
"pthread_atfork" => {
276-
this.write_null(dest)?;
277-
}
278-
279-
// Some things needed for `sys::thread` initialization to go through.
280287
| "signal"
281288
| "sigaction"
282289
| "sigaltstack"
290+
| "mprotect" if this.frame().instance.to_string().starts_with("std::sys::unix::")
283291
=> {
284-
this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?;
285-
}
286-
287-
"sysconf" => {
288-
let name = this.read_scalar(args[0])?.to_i32()?;
289-
290-
trace!("sysconf() called with name {}", name);
291-
// TODO: Cache the sysconf integers via Miri's global cache.
292-
let sysconfs = &[
293-
("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, dest.layout.size)),
294-
("_SC_GETPW_R_SIZE_MAX", Scalar::from_int(-1, dest.layout.size)),
295-
("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, dest.layout.size)),
296-
];
297-
let mut result = None;
298-
for &(sysconf_name, value) in sysconfs {
299-
let sysconf_name = this.eval_libc_i32(sysconf_name)?;
300-
if sysconf_name == name {
301-
result = Some(value);
302-
break;
303-
}
304-
}
305-
if let Some(result) = result {
306-
this.write_scalar(result, dest)?;
307-
} else {
308-
throw_unsup_format!("unimplemented sysconf name: {}", name)
309-
}
310-
}
311-
312-
"isatty" => {
313-
this.write_null(dest)?;
314-
}
315-
316-
"posix_fadvise" => {
317-
// fadvise is only informational, we can ignore it.
318-
this.write_null(dest)?;
319-
}
320-
321-
"mmap" => {
322-
// This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
323-
let addr = this.read_scalar(args[0])?.not_undef()?;
324-
this.write_scalar(addr, dest)?;
325-
}
326-
327-
"mprotect" => {
328292
this.write_null(dest)?;
329293
}
330294

295+
// Platform-specific shims
331296
_ => {
332297
match this.tcx.sess.target.target.target_os.as_str() {
333298
"linux" => return linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),

0 commit comments

Comments
 (0)