Skip to content

Commit 9e39bfb

Browse files
committed
organize shims and make some only available to libstd as they are incomplete
1 parent f274111 commit 9e39bfb

File tree

6 files changed

+193
-196
lines changed

6 files changed

+193
-196
lines changed

src/helpers.rs

+1
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

+9-8
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 met, 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

+57-92
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2424
let result = this.getenv(args[0])?;
2525
this.write_scalar(result, dest)?;
2626
}
27-
2827
"unsetenv" => {
2928
let result = this.unsetenv(args[0])?;
3029
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
3130
}
32-
3331
"setenv" => {
3432
let result = this.setenv(args[0], args[1])?;
3533
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
3634
}
37-
3835
"getcwd" => {
3936
let result = this.getcwd(args[0], args[1])?;
4037
this.write_scalar(result, dest)?;
4138
}
42-
4339
"chdir" => {
4440
let result = this.chdir(args[0])?;
4541
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
@@ -50,17 +46,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
5046
let result = this.open(args[0], args[1])?;
5147
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
5248
}
53-
5449
"fcntl" => {
5550
let result = this.fcntl(args[0], args[1], args.get(2).cloned())?;
5651
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
5752
}
58-
5953
"read" => {
6054
let result = this.read(args[0], args[1], args[2])?;
6155
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
6256
}
63-
6457
"write" => {
6558
let fd = this.read_scalar(args[0])?.to_i32()?;
6659
let buf = this.read_scalar(args[1])?.not_undef()?;
@@ -94,43 +87,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
9487
// Now, `result` is the value we return back to the program.
9588
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
9689
}
97-
9890
"unlink" => {
9991
let result = this.unlink(args[0])?;
10092
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
10193
}
102-
10394
"symlink" => {
10495
let result = this.symlink(args[0], args[1])?;
10596
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
10697
}
107-
10898
"rename" => {
10999
let result = this.rename(args[0], args[1])?;
110100
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
111101
}
112-
113102
"mkdir" => {
114103
let result = this.mkdir(args[0], args[1])?;
115104
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
116105
}
117-
118106
"rmdir" => {
119107
let result = this.rmdir(args[0])?;
120108
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
121109
}
122-
123110
"closedir" => {
124111
let result = this.closedir(args[0])?;
125112
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
126113
}
127-
128114
"lseek" | "lseek64" => {
129115
let result = this.lseek64(args[0], args[1], args[2])?;
130116
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
131117
}
118+
"posix_fadvise" => {
119+
// fadvise is only informational, we can ignore it.
120+
this.write_null(dest)?;
121+
}
132122

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

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

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

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

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

243-
// Return success (`0`).
242+
// Miscellaneous
243+
"isatty" => {
244+
let _fd = this.read_scalar(args[0])?.to_i32()?;
245+
// "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"
246+
// FIXME: we just say nothing is a terminal.
247+
let enotty = this.eval_libc("ENOTTY")?;
248+
this.set_last_error(enotty)?;
244249
this.write_null(dest)?;
245250
}
246-
247-
// We don't support threading.
248-
"pthread_create" => {
249-
throw_unsup_format!("Miri does not support threading");
251+
"pthread_atfork" => {
252+
let _prepare = this.read_scalar(args[0])?.not_undef()?;
253+
let _parent = this.read_scalar(args[1])?.not_undef()?;
254+
let _child = this.read_scalar(args[1])?.not_undef()?;
255+
// We do not support forking, so there is nothing to do here.
256+
this.write_null(dest)?;
250257
}
251258

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

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

0 commit comments

Comments
 (0)