1use std::ffi::OsStr;
2use std::str;
3
4use rustc_abi::{CanonAbi, Size};
5use rustc_middle::ty::Ty;
6use rustc_span::Symbol;
7use rustc_target::callconv::FnAbi;
8use rustc_target::spec::Os;
9
10use self::shims::unix::android::foreign_items as android;
11use self::shims::unix::freebsd::foreign_items as freebsd;
12use self::shims::unix::linux::foreign_items as linux;
13use self::shims::unix::macos::foreign_items as macos;
14use self::shims::unix::solarish::foreign_items as solarish;
15use crate::concurrency::cpu_affinity::CpuAffinityMask;
16use crate::shims::alloc::EvalContextExt as _;
17use crate::shims::unix::*;
18use crate::{shim_sig, *};
19
20pub fn is_dyn_sym(name: &str, target_os: &Os) -> bool {
21 match name {
22 "isatty" => true,
24 "signal" => true,
27 "getentropy" | "getrandom" => true,
29 _ =>
31 match *target_os {
32 Os::Android => android::is_dyn_sym(name),
33 Os::FreeBsd => freebsd::is_dyn_sym(name),
34 Os::Linux => linux::is_dyn_sym(name),
35 Os::MacOs => macos::is_dyn_sym(name),
36 Os::Solaris | Os::Illumos => solarish::is_dyn_sym(name),
37 _ => false,
38 },
39 }
40}
41
42impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
43pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
44 fn sysconf(&mut self, val: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
46 let this = self.eval_context_mut();
47
48 let name = this.read_scalar(val)?.to_i32()?;
49 let sysconfs: &[(&str, fn(&MiriInterpCx<'_>) -> Scalar)] = &[
52 ("_SC_PAGESIZE", |this| Scalar::from_int(this.machine.page_size, this.pointer_size())),
53 ("_SC_PAGE_SIZE", |this| Scalar::from_int(this.machine.page_size, this.pointer_size())),
54 ("_SC_NPROCESSORS_CONF", |this| {
55 Scalar::from_int(this.machine.num_cpus, this.pointer_size())
56 }),
57 ("_SC_NPROCESSORS_ONLN", |this| {
58 Scalar::from_int(this.machine.num_cpus, this.pointer_size())
59 }),
60 ("_SC_GETPW_R_SIZE_MAX", |this| Scalar::from_int(512, this.pointer_size())),
63 ("_SC_OPEN_MAX", |this| Scalar::from_int(2_i32.pow(16), this.pointer_size())),
68 ];
69 for &(sysconf_name, value) in sysconfs {
70 let sysconf_name = this.eval_libc_i32(sysconf_name);
71 if sysconf_name == name {
72 return interp_ok(value(this));
73 }
74 }
75 throw_unsup_format!("unimplemented sysconf name: {}", name)
76 }
77
78 fn strerror_r(
79 &mut self,
80 errnum: &OpTy<'tcx>,
81 buf: &OpTy<'tcx>,
82 buflen: &OpTy<'tcx>,
83 ) -> InterpResult<'tcx, Scalar> {
84 let this = self.eval_context_mut();
85
86 let errnum = this.read_scalar(errnum)?;
87 let buf = this.read_pointer(buf)?;
88 let buflen = this.read_target_usize(buflen)?;
89 let error = this.try_errnum_to_io_error(errnum)?;
90 let formatted = match error {
91 Some(err) => format!("{err}"),
92 None => format!("<unknown errnum in strerror_r: {errnum}>"),
93 };
94 let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?;
95 if complete {
96 interp_ok(Scalar::from_i32(0))
97 } else {
98 interp_ok(Scalar::from_i32(this.eval_libc_i32("ERANGE")))
99 }
100 }
101
102 fn emulate_foreign_item_inner(
103 &mut self,
104 link_name: Symbol,
105 abi: &FnAbi<'tcx, Ty<'tcx>>,
106 args: &[OpTy<'tcx>],
107 dest: &MPlaceTy<'tcx>,
108 ) -> InterpResult<'tcx, EmulateItemResult> {
109 let this = self.eval_context_mut();
110
111 match link_name.as_str() {
113 "getenv" => {
115 let [name] = this.check_shim_sig(
116 shim_sig!(extern "C" fn(*const _) -> *mut _),
117 link_name,
118 abi,
119 args,
120 )?;
121 let result = this.getenv(name)?;
122 this.write_pointer(result, dest)?;
123 }
124 "unsetenv" => {
125 let [name] = this.check_shim_sig(
126 shim_sig!(extern "C" fn(*const _) -> i32),
127 link_name,
128 abi,
129 args,
130 )?;
131 let result = this.unsetenv(name)?;
132 this.write_scalar(result, dest)?;
133 }
134 "setenv" => {
135 let [name, value, overwrite] = this.check_shim_sig(
136 shim_sig!(extern "C" fn(*const _, *const _, i32) -> i32),
137 link_name,
138 abi,
139 args,
140 )?;
141 this.read_scalar(overwrite)?.to_i32()?;
142 let result = this.setenv(name, value)?;
143 this.write_scalar(result, dest)?;
144 }
145 "getcwd" => {
146 let [buf, size] = this.check_shim_sig(
147 shim_sig!(extern "C" fn(*mut _, usize) -> *mut _),
148 link_name,
149 abi,
150 args,
151 )?;
152 let result = this.getcwd(buf, size)?;
153 this.write_pointer(result, dest)?;
154 }
155 "chdir" => {
156 let [path] = this.check_shim_sig(
157 shim_sig!(extern "C" fn(*const _) -> i32),
158 link_name,
159 abi,
160 args,
161 )?;
162 let result = this.chdir(path)?;
163 this.write_scalar(result, dest)?;
164 }
165 "getpid" => {
166 let [] = this.check_shim_sig(
167 shim_sig!(extern "C" fn() -> libc::pid_t),
168 link_name,
169 abi,
170 args,
171 )?;
172 let result = this.getpid()?;
173 this.write_scalar(result, dest)?;
174 }
175 "sysconf" => {
176 let [val] = this.check_shim_sig(
177 shim_sig!(extern "C" fn(i32) -> isize),
178 link_name,
179 abi,
180 args,
181 )?;
182 let result = this.sysconf(val)?;
183 this.write_scalar(result, dest)?;
184 }
185 "read" => {
187 let [fd, buf, count] = this.check_shim_sig(
188 shim_sig!(extern "C" fn(i32, *mut _, usize) -> isize),
189 link_name,
190 abi,
191 args,
192 )?;
193 let fd = this.read_scalar(fd)?.to_i32()?;
194 let buf = this.read_pointer(buf)?;
195 let count = this.read_target_usize(count)?;
196 this.read(fd, buf, count, None, dest)?;
197 }
198 "write" => {
199 let [fd, buf, n] = this.check_shim_sig(
200 shim_sig!(extern "C" fn(i32, *const _, usize) -> isize),
201 link_name,
202 abi,
203 args,
204 )?;
205 let fd = this.read_scalar(fd)?.to_i32()?;
206 let buf = this.read_pointer(buf)?;
207 let count = this.read_target_usize(n)?;
208 trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
209 this.write(fd, buf, count, None, dest)?;
210 }
211 "pread" => {
212 let [fd, buf, count, offset] = this.check_shim_sig(
213 shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off_t) -> isize),
214 link_name,
215 abi,
216 args,
217 )?;
218 let fd = this.read_scalar(fd)?.to_i32()?;
219 let buf = this.read_pointer(buf)?;
220 let count = this.read_target_usize(count)?;
221 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
222 this.read(fd, buf, count, Some(offset), dest)?;
223 }
224 "pwrite" => {
225 let [fd, buf, n, offset] = this.check_shim_sig(
226 shim_sig!(extern "C" fn(i32, *const _, usize, libc::off_t) -> isize),
227 link_name,
228 abi,
229 args,
230 )?;
231 let fd = this.read_scalar(fd)?.to_i32()?;
232 let buf = this.read_pointer(buf)?;
233 let count = this.read_target_usize(n)?;
234 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
235 trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
236 this.write(fd, buf, count, Some(offset), dest)?;
237 }
238 "close" => {
239 let [fd] = this.check_shim_sig(
240 shim_sig!(extern "C" fn(i32) -> i32),
241 link_name,
242 abi,
243 args,
244 )?;
245 let result = this.close(fd)?;
246 this.write_scalar(result, dest)?;
247 }
248 "fcntl" => {
249 let ([fd_num, cmd], varargs) =
250 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
251 let result = this.fcntl(fd_num, cmd, varargs)?;
252 this.write_scalar(result, dest)?;
253 }
254 "dup" => {
255 let [old_fd] = this.check_shim_sig(
256 shim_sig!(extern "C" fn(i32) -> i32),
257 link_name,
258 abi,
259 args,
260 )?;
261 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
262 let new_fd = this.dup(old_fd)?;
263 this.write_scalar(new_fd, dest)?;
264 }
265 "dup2" => {
266 let [old_fd, new_fd] = this.check_shim_sig(
267 shim_sig!(extern "C" fn(i32, i32) -> i32),
268 link_name,
269 abi,
270 args,
271 )?;
272 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
273 let new_fd = this.read_scalar(new_fd)?.to_i32()?;
274 let result = this.dup2(old_fd, new_fd)?;
275 this.write_scalar(result, dest)?;
276 }
277 "flock" => {
278 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::MacOs, Os::Illumos], link_name)?;
280 let [fd, op] = this.check_shim_sig(
281 shim_sig!(extern "C" fn(i32, i32) -> i32),
282 link_name,
283 abi,
284 args,
285 )?;
286 let fd = this.read_scalar(fd)?.to_i32()?;
287 let op = this.read_scalar(op)?.to_i32()?;
288 let result = this.flock(fd, op)?;
289 this.write_scalar(result, dest)?;
290 }
291
292 "open" => {
294 let ([path_raw, flag], varargs) =
297 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
298 let result = this.open(path_raw, flag, varargs)?;
299 this.write_scalar(result, dest)?;
300 }
301 "unlink" => {
302 let [path] = this.check_shim_sig(
303 shim_sig!(extern "C" fn(*const _) -> i32),
304 link_name,
305 abi,
306 args,
307 )?;
308 let result = this.unlink(path)?;
309 this.write_scalar(result, dest)?;
310 }
311 "symlink" => {
312 let [target, linkpath] = this.check_shim_sig(
313 shim_sig!(extern "C" fn(*const _, *const _) -> i32),
314 link_name,
315 abi,
316 args,
317 )?;
318 let result = this.symlink(target, linkpath)?;
319 this.write_scalar(result, dest)?;
320 }
321 "fstat" => {
322 let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
323 let result = this.fstat(fd, buf)?;
324 this.write_scalar(result, dest)?;
325 }
326 "rename" => {
327 let [oldpath, newpath] = this.check_shim_sig(
328 shim_sig!(extern "C" fn(*const _, *const _) -> i32),
329 link_name,
330 abi,
331 args,
332 )?;
333 let result = this.rename(oldpath, newpath)?;
334 this.write_scalar(result, dest)?;
335 }
336 "mkdir" => {
337 let [path, mode] = this.check_shim_sig(
338 shim_sig!(extern "C" fn(*const _, libc::mode_t) -> i32),
339 link_name,
340 abi,
341 args,
342 )?;
343 let result = this.mkdir(path, mode)?;
344 this.write_scalar(result, dest)?;
345 }
346 "rmdir" => {
347 let [path] = this.check_shim_sig(
348 shim_sig!(extern "C" fn(*const _) -> i32),
349 link_name,
350 abi,
351 args,
352 )?;
353 let result = this.rmdir(path)?;
354 this.write_scalar(result, dest)?;
355 }
356 "opendir" => {
357 let [name] = this.check_shim_sig(
358 shim_sig!(extern "C" fn(*const _) -> *mut _),
359 link_name,
360 abi,
361 args,
362 )?;
363 let result = this.opendir(name)?;
364 this.write_scalar(result, dest)?;
365 }
366 "closedir" => {
367 let [dirp] = this.check_shim_sig(
368 shim_sig!(extern "C" fn(*mut _) -> i32),
369 link_name,
370 abi,
371 args,
372 )?;
373 let result = this.closedir(dirp)?;
374 this.write_scalar(result, dest)?;
375 }
376 "lseek" => {
377 let [fd, offset, whence] = this.check_shim_sig(
378 shim_sig!(extern "C" fn(i32, libc::off_t, i32) -> libc::off_t),
379 link_name,
380 abi,
381 args,
382 )?;
383 let fd = this.read_scalar(fd)?.to_i32()?;
384 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
385 let whence = this.read_scalar(whence)?.to_i32()?;
386 this.lseek64(fd, offset, whence, dest)?;
387 }
388 "ftruncate" => {
389 let [fd, length] = this.check_shim_sig(
390 shim_sig!(extern "C" fn(i32, libc::off_t) -> i32),
391 link_name,
392 abi,
393 args,
394 )?;
395 let fd = this.read_scalar(fd)?.to_i32()?;
396 let length = this.read_scalar(length)?.to_int(length.layout.size)?;
397 let result = this.ftruncate64(fd, length)?;
398 this.write_scalar(result, dest)?;
399 }
400 "fsync" => {
401 let [fd] = this.check_shim_sig(
402 shim_sig!(extern "C" fn(i32) -> i32),
403 link_name,
404 abi,
405 args,
406 )?;
407 let result = this.fsync(fd)?;
408 this.write_scalar(result, dest)?;
409 }
410 "fdatasync" => {
411 let [fd] = this.check_shim_sig(
412 shim_sig!(extern "C" fn(i32) -> i32),
413 link_name,
414 abi,
415 args,
416 )?;
417 let result = this.fdatasync(fd)?;
418 this.write_scalar(result, dest)?;
419 }
420 "readlink" => {
421 let [pathname, buf, bufsize] = this.check_shim_sig(
422 shim_sig!(extern "C" fn(*const _, *mut _, usize) -> isize),
423 link_name,
424 abi,
425 args,
426 )?;
427 let result = this.readlink(pathname, buf, bufsize)?;
428 this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
429 }
430 "posix_fadvise" => {
431 let [fd, offset, len, advice] = this.check_shim_sig(
432 shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t, i32) -> i32),
433 link_name,
434 abi,
435 args,
436 )?;
437 this.read_scalar(fd)?.to_i32()?;
438 this.read_scalar(offset)?.to_int(offset.layout.size)?;
439 this.read_scalar(len)?.to_int(len.layout.size)?;
440 this.read_scalar(advice)?.to_i32()?;
441 this.write_null(dest)?;
443 }
444
445 "posix_fallocate" => {
446 this.check_target_os(
448 &[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos, Os::Android],
449 link_name,
450 )?;
451 let [fd, offset, len] = this.check_shim_sig(
452 shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t) -> i32),
453 link_name,
454 abi,
455 args,
456 )?;
457
458 let fd = this.read_scalar(fd)?.to_i32()?;
459 let offset =
461 i64::try_from(this.read_scalar(offset)?.to_int(offset.layout.size)?).unwrap();
462 let len = i64::try_from(this.read_scalar(len)?.to_int(len.layout.size)?).unwrap();
463
464 let result = this.posix_fallocate(fd, offset, len)?;
465 this.write_scalar(result, dest)?;
466 }
467
468 "realpath" => {
469 let [path, resolved_path] = this.check_shim_sig(
470 shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
471 link_name,
472 abi,
473 args,
474 )?;
475 let result = this.realpath(path, resolved_path)?;
476 this.write_scalar(result, dest)?;
477 }
478 "mkstemp" => {
479 let [template] = this.check_shim_sig(
480 shim_sig!(extern "C" fn(*mut _) -> i32),
481 link_name,
482 abi,
483 args,
484 )?;
485 let result = this.mkstemp(template)?;
486 this.write_scalar(result, dest)?;
487 }
488
489 "socketpair" => {
491 let [domain, type_, protocol, sv] = this.check_shim_sig(
492 shim_sig!(extern "C" fn(i32, i32, i32, *mut _) -> i32),
493 link_name,
494 abi,
495 args,
496 )?;
497 let result = this.socketpair(domain, type_, protocol, sv)?;
498 this.write_scalar(result, dest)?;
499 }
500 "pipe" => {
501 let [pipefd] = this.check_shim_sig(
502 shim_sig!(extern "C" fn(*mut _) -> i32),
503 link_name,
504 abi,
505 args,
506 )?;
507 let result = this.pipe2(pipefd, None)?;
508 this.write_scalar(result, dest)?;
509 }
510 "pipe2" => {
511 this.check_target_os(
513 &[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos],
514 link_name,
515 )?;
516 let [pipefd, flags] = this.check_shim_sig(
517 shim_sig!(extern "C" fn(*mut _, i32) -> i32),
518 link_name,
519 abi,
520 args,
521 )?;
522 let result = this.pipe2(pipefd, Some(flags))?;
523 this.write_scalar(result, dest)?;
524 }
525
526 "gettimeofday" => {
528 let [tv, tz] = this.check_shim_sig(
529 shim_sig!(extern "C" fn(*mut _, *mut _) -> i32),
530 link_name,
531 abi,
532 args,
533 )?;
534 let result = this.gettimeofday(tv, tz)?;
535 this.write_scalar(result, dest)?;
536 }
537 "localtime_r" => {
538 let [timep, result_op] = this.check_shim_sig(
539 shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
540 link_name,
541 abi,
542 args,
543 )?;
544 let result = this.localtime_r(timep, result_op)?;
545 this.write_pointer(result, dest)?;
546 }
547 "clock_gettime" => {
548 let [clk_id, tp] = this.check_shim_sig(
549 shim_sig!(extern "C" fn(libc::clockid_t, *mut _) -> i32),
550 link_name,
551 abi,
552 args,
553 )?;
554 this.clock_gettime(clk_id, tp, dest)?;
555 }
556
557 "posix_memalign" => {
559 let [memptr, align, size] =
560 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
561 let result = this.posix_memalign(memptr, align, size)?;
562 this.write_scalar(result, dest)?;
563 }
564
565 "mmap" => {
566 let [addr, length, prot, flags, fd, offset] =
567 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
568 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
569 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
570 this.write_scalar(ptr, dest)?;
571 }
572 "munmap" => {
573 let [addr, length] =
574 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
575 let result = this.munmap(addr, length)?;
576 this.write_scalar(result, dest)?;
577 }
578
579 "reallocarray" => {
580 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
582 let [ptr, nmemb, size] =
583 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
584 let ptr = this.read_pointer(ptr)?;
585 let nmemb = this.read_target_usize(nmemb)?;
586 let size = this.read_target_usize(size)?;
587 match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
593 None => {
594 this.set_last_error(LibcError("ENOMEM"))?;
595 this.write_null(dest)?;
596 }
597 Some(len) => {
598 let res = this.realloc(ptr, len.bytes())?;
599 this.write_pointer(res, dest)?;
600 }
601 }
602 }
603 "aligned_alloc" => {
604 let [align, size] =
607 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
608 let res = this.aligned_alloc(align, size)?;
609 this.write_pointer(res, dest)?;
610 }
611
612 "dlsym" => {
614 let [handle, symbol] =
615 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
616 this.read_target_usize(handle)?;
617 let symbol = this.read_pointer(symbol)?;
618 let name = this.read_c_str(symbol)?;
619 if let Ok(name) = str::from_utf8(name)
620 && is_dyn_sym(name, &this.tcx.sess.target.os)
621 {
622 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
623 this.write_pointer(ptr, dest)?;
624 } else {
625 this.write_null(dest)?;
626 }
627 }
628
629 "pthread_key_create" => {
631 let [key, dtor] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
632 let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
633 let dtor = this.read_pointer(dtor)?;
634
635 let dtor = if !this.ptr_is_null(dtor)? {
637 Some((
638 this.get_ptr_fn(dtor)?.as_instance()?,
639 this.machine.current_user_relevant_span(),
640 ))
641 } else {
642 None
643 };
644
645 let key_type = key.layout.ty
648 .builtin_deref(true)
649 .ok_or_else(|| err_ub_format!(
650 "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
651 ))?;
652 let key_layout = this.layout_of(key_type)?;
653
654 let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
656 this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place)?;
657
658 this.write_null(dest)?;
660 }
661 "pthread_key_delete" => {
662 let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
663 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
664 this.machine.tls.delete_tls_key(key)?;
665 this.write_null(dest)?;
667 }
668 "pthread_getspecific" => {
669 let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
670 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
671 let active_thread = this.active_thread();
672 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
673 this.write_scalar(ptr, dest)?;
674 }
675 "pthread_setspecific" => {
676 let [key, new_ptr] =
677 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
678 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
679 let active_thread = this.active_thread();
680 let new_data = this.read_scalar(new_ptr)?;
681 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
682
683 this.write_null(dest)?;
685 }
686
687 "pthread_mutexattr_init" => {
689 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
690 this.pthread_mutexattr_init(attr)?;
691 this.write_null(dest)?;
692 }
693 "pthread_mutexattr_settype" => {
694 let [attr, kind] =
695 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
696 let result = this.pthread_mutexattr_settype(attr, kind)?;
697 this.write_scalar(result, dest)?;
698 }
699 "pthread_mutexattr_destroy" => {
700 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
701 this.pthread_mutexattr_destroy(attr)?;
702 this.write_null(dest)?;
703 }
704 "pthread_mutex_init" => {
705 let [mutex, attr] =
706 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
707 this.pthread_mutex_init(mutex, attr)?;
708 this.write_null(dest)?;
709 }
710 "pthread_mutex_lock" => {
711 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
712 this.pthread_mutex_lock(mutex, dest)?;
713 }
714 "pthread_mutex_trylock" => {
715 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
716 let result = this.pthread_mutex_trylock(mutex)?;
717 this.write_scalar(result, dest)?;
718 }
719 "pthread_mutex_unlock" => {
720 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
721 let result = this.pthread_mutex_unlock(mutex)?;
722 this.write_scalar(result, dest)?;
723 }
724 "pthread_mutex_destroy" => {
725 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
726 this.pthread_mutex_destroy(mutex)?;
727 this.write_int(0, dest)?;
728 }
729 "pthread_rwlock_rdlock" => {
730 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
731 this.pthread_rwlock_rdlock(rwlock, dest)?;
732 }
733 "pthread_rwlock_tryrdlock" => {
734 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
735 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
736 this.write_scalar(result, dest)?;
737 }
738 "pthread_rwlock_wrlock" => {
739 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
740 this.pthread_rwlock_wrlock(rwlock, dest)?;
741 }
742 "pthread_rwlock_trywrlock" => {
743 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
744 let result = this.pthread_rwlock_trywrlock(rwlock)?;
745 this.write_scalar(result, dest)?;
746 }
747 "pthread_rwlock_unlock" => {
748 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
749 this.pthread_rwlock_unlock(rwlock)?;
750 this.write_null(dest)?;
751 }
752 "pthread_rwlock_destroy" => {
753 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
754 this.pthread_rwlock_destroy(rwlock)?;
755 this.write_null(dest)?;
756 }
757 "pthread_condattr_init" => {
758 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
759 this.pthread_condattr_init(attr)?;
760 this.write_null(dest)?;
761 }
762 "pthread_condattr_setclock" => {
763 let [attr, clock_id] =
764 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
765 let result = this.pthread_condattr_setclock(attr, clock_id)?;
766 this.write_scalar(result, dest)?;
767 }
768 "pthread_condattr_getclock" => {
769 let [attr, clock_id] =
770 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
771 this.pthread_condattr_getclock(attr, clock_id)?;
772 this.write_null(dest)?;
773 }
774 "pthread_condattr_destroy" => {
775 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
776 this.pthread_condattr_destroy(attr)?;
777 this.write_null(dest)?;
778 }
779 "pthread_cond_init" => {
780 let [cond, attr] =
781 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
782 this.pthread_cond_init(cond, attr)?;
783 this.write_null(dest)?;
784 }
785 "pthread_cond_signal" => {
786 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
787 this.pthread_cond_signal(cond)?;
788 this.write_null(dest)?;
789 }
790 "pthread_cond_broadcast" => {
791 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
792 this.pthread_cond_broadcast(cond)?;
793 this.write_null(dest)?;
794 }
795 "pthread_cond_wait" => {
796 let [cond, mutex] =
797 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
798 this.pthread_cond_wait(cond, mutex, dest)?;
799 }
800 "pthread_cond_timedwait" => {
801 let [cond, mutex, abstime] =
802 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
803 this.pthread_cond_timedwait(
804 cond, mutex, abstime, dest, false,
805 )?;
806 }
807 "pthread_cond_destroy" => {
808 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
809 this.pthread_cond_destroy(cond)?;
810 this.write_null(dest)?;
811 }
812
813 "pthread_create" => {
815 let [thread, attr, start, arg] =
816 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
817 this.pthread_create(thread, attr, start, arg)?;
818 this.write_null(dest)?;
819 }
820 "pthread_join" => {
821 let [thread, retval] =
822 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
823 this.pthread_join(thread, retval, dest)?;
824 }
825 "pthread_detach" => {
826 let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
827 let res = this.pthread_detach(thread)?;
828 this.write_scalar(res, dest)?;
829 }
830 "pthread_self" => {
831 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
832 let res = this.pthread_self()?;
833 this.write_scalar(res, dest)?;
834 }
835 "sched_yield" => {
836 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
837 this.sched_yield()?;
838 this.write_null(dest)?;
839 }
840 "nanosleep" => {
841 let [duration, rem] =
842 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
843 let result = this.nanosleep(duration, rem)?;
844 this.write_scalar(result, dest)?;
845 }
846 "clock_nanosleep" => {
847 this.check_target_os(
849 &[Os::FreeBsd, Os::Linux, Os::Android, Os::Solaris, Os::Illumos],
850 link_name,
851 )?;
852 let [clock_id, flags, req, rem] =
853 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
854 let result = this.clock_nanosleep(clock_id, flags, req, rem)?;
855 this.write_scalar(result, dest)?;
856 }
857 "sched_getaffinity" => {
858 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
860 let [pid, cpusetsize, mask] =
861 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
862 let pid = this.read_scalar(pid)?.to_u32()?;
863 let cpusetsize = this.read_target_usize(cpusetsize)?;
864 let mask = this.read_pointer(mask)?;
865
866 let thread_id = match pid {
868 0 => this.active_thread(),
869 _ =>
870 throw_unsup_format!(
871 "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"
872 ),
873 };
874
875 let chunk_size = CpuAffinityMask::chunk_size(this);
877
878 if this.ptr_is_null(mask)? {
879 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
880 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
881 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
883 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
884 let cpuset = cpuset.clone();
885 let byte_count =
887 Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
888 this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
889 this.write_null(dest)?;
890 } else {
891 this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
893 }
894 }
895 "sched_setaffinity" => {
896 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
898 let [pid, cpusetsize, mask] =
899 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
900 let pid = this.read_scalar(pid)?.to_u32()?;
901 let cpusetsize = this.read_target_usize(cpusetsize)?;
902 let mask = this.read_pointer(mask)?;
903
904 let thread_id = match pid {
906 0 => this.active_thread(),
907 _ =>
908 throw_unsup_format!(
909 "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"
910 ),
911 };
912
913 if this.ptr_is_null(mask)? {
914 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
915 } else {
916 let bits_slice =
920 this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
921 let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
923 std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
924 match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
925 Some(cpuset) => {
926 this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
927 this.write_null(dest)?;
928 }
929 None => {
930 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
932 }
933 }
934 }
935 }
936
937 "isatty" => {
939 let [fd] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
940 let result = this.isatty(fd)?;
941 this.write_scalar(result, dest)?;
942 }
943 "pthread_atfork" => {
944 let [prepare, parent, child] =
945 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
946 this.read_pointer(prepare)?;
947 this.read_pointer(parent)?;
948 this.read_pointer(child)?;
949 this.write_null(dest)?;
951 }
952 "getentropy" => {
953 this.check_target_os(
956 &[Os::Linux, Os::MacOs, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
957 link_name,
958 )?;
959 let [buf, bufsize] =
960 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
961 let buf = this.read_pointer(buf)?;
962 let bufsize = this.read_target_usize(bufsize)?;
963
964 if bufsize > 256 {
970 this.set_last_error_and_return(LibcError("EIO"), dest)?;
971 } else {
972 this.gen_random(buf, bufsize)?;
973 this.write_null(dest)?;
974 }
975 }
976
977 "strerror_r" => {
978 let [errnum, buf, buflen] =
979 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
980 let result = this.strerror_r(errnum, buf, buflen)?;
981 this.write_scalar(result, dest)?;
982 }
983
984 "getrandom" => {
985 this.check_target_os(
988 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
989 link_name,
990 )?;
991 let [ptr, len, flags] =
992 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
993 let ptr = this.read_pointer(ptr)?;
994 let len = this.read_target_usize(len)?;
995 let _flags = this.read_scalar(flags)?.to_i32()?;
996 this.gen_random(ptr, len)?;
998 this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
999 }
1000 "arc4random_buf" => {
1001 this.check_target_os(&[Os::FreeBsd, Os::Illumos, Os::Solaris], link_name)?;
1004 let [ptr, len] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1005 let ptr = this.read_pointer(ptr)?;
1006 let len = this.read_target_usize(len)?;
1007 this.gen_random(ptr, len)?;
1008 }
1009 "_Unwind_RaiseException" => {
1010 this.check_target_os(
1024 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android, Os::MacOs],
1025 link_name,
1026 )?;
1027 let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1029 this.handle_miri_start_unwind(payload)?;
1030 return interp_ok(EmulateItemResult::NeedsUnwind);
1031 }
1032 "getuid" | "geteuid" => {
1033 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1034 this.write_int(UID, dest)?;
1036 }
1037
1038 "pthread_attr_getguardsize" if this.frame_in_std() => {
1041 let [_attr, guard_size] =
1042 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1043 let guard_size_layout = this.machine.layouts.usize;
1044 let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
1045 this.write_scalar(
1046 Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
1047 &guard_size,
1048 )?;
1049
1050 this.write_null(dest)?;
1052 }
1053
1054 "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
1055 let [_] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1056 this.write_null(dest)?;
1057 }
1058 "pthread_attr_setstacksize" if this.frame_in_std() => {
1059 let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1060 this.write_null(dest)?;
1061 }
1062
1063 "pthread_attr_getstack" if this.frame_in_std() => {
1064 let [attr_place, addr_place, size_place] =
1067 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1068 let _attr_place =
1069 this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
1070 let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?;
1071 let size_place = this.deref_pointer_as(size_place, this.machine.layouts.usize)?;
1072
1073 this.write_scalar(
1074 Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
1075 &addr_place,
1076 )?;
1077 this.write_scalar(
1078 Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
1079 &size_place,
1080 )?;
1081
1082 this.write_null(dest)?;
1084 }
1085
1086 "signal" | "sigaltstack" if this.frame_in_std() => {
1087 let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1088 this.write_null(dest)?;
1089 }
1090 "sigaction" | "mprotect" if this.frame_in_std() => {
1091 let [_, _, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1092 this.write_null(dest)?;
1093 }
1094
1095 "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
1096 let [uid, pwd, buf, buflen, result] =
1098 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1099 this.check_no_isolation("`getpwuid_r`")?;
1100
1101 let uid = this.read_scalar(uid)?.to_u32()?;
1102 let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?;
1103 let buf = this.read_pointer(buf)?;
1104 let buflen = this.read_target_usize(buflen)?;
1105 let result = this.deref_pointer_as(result, this.machine.layouts.mut_raw_ptr)?;
1106
1107 if uid != UID {
1109 throw_unsup_format!("`getpwuid_r` on other users is not supported");
1110 }
1111
1112 this.write_uninit(&pwd)?;
1115
1116 #[allow(deprecated)]
1118 let home_dir = std::env::home_dir().unwrap();
1119 let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
1120 let pw_dir = this.project_field_named(&pwd, "pw_dir")?;
1121 this.write_pointer(buf, &pw_dir)?;
1122
1123 if written {
1124 this.write_pointer(pwd.ptr(), &result)?;
1125 this.write_null(dest)?;
1126 } else {
1127 this.write_null(&result)?;
1128 this.write_scalar(this.eval_libc("ERANGE"), dest)?;
1129 }
1130 }
1131
1132 _ => {
1134 let target_os = &this.tcx.sess.target.os;
1135 return match target_os {
1136 Os::Android =>
1137 android::EvalContextExt::emulate_foreign_item_inner(
1138 this, link_name, abi, args, dest,
1139 ),
1140 Os::FreeBsd =>
1141 freebsd::EvalContextExt::emulate_foreign_item_inner(
1142 this, link_name, abi, args, dest,
1143 ),
1144 Os::Linux =>
1145 linux::EvalContextExt::emulate_foreign_item_inner(
1146 this, link_name, abi, args, dest,
1147 ),
1148 Os::MacOs =>
1149 macos::EvalContextExt::emulate_foreign_item_inner(
1150 this, link_name, abi, args, dest,
1151 ),
1152 Os::Solaris | Os::Illumos =>
1153 solarish::EvalContextExt::emulate_foreign_item_inner(
1154 this, link_name, abi, args, dest,
1155 ),
1156 _ => interp_ok(EmulateItemResult::NotSupported),
1157 };
1158 }
1159 };
1160
1161 interp_ok(EmulateItemResult::NeedsReturn)
1162 }
1163}