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(
148 shim_sig!(extern "C" fn(*mut _, usize) -> *mut _),
149 link_name,
150 abi,
151 args,
152 )?;
153 let result = this.getcwd(buf, size)?;
154 this.write_pointer(result, dest)?;
155 }
156 "chdir" => {
157 let [path] = this.check_shim_sig(
159 shim_sig!(extern "C" fn(*const _) -> i32),
160 link_name,
161 abi,
162 args,
163 )?;
164 let result = this.chdir(path)?;
165 this.write_scalar(result, dest)?;
166 }
167 "getpid" => {
168 let [] = this.check_shim_sig(
169 shim_sig!(extern "C" fn() -> libc::pid_t),
170 link_name,
171 abi,
172 args,
173 )?;
174 let result = this.getpid()?;
175 this.write_scalar(result, dest)?;
176 }
177 "sysconf" => {
178 let [val] = this.check_shim_sig(
179 shim_sig!(extern "C" fn(i32) -> isize),
180 link_name,
181 abi,
182 args,
183 )?;
184 let result = this.sysconf(val)?;
185 this.write_scalar(result, dest)?;
186 }
187 "read" => {
189 let [fd, buf, count] = this.check_shim_sig(
190 shim_sig!(extern "C" fn(i32, *mut _, usize) -> isize),
191 link_name,
192 abi,
193 args,
194 )?;
195 let fd = this.read_scalar(fd)?.to_i32()?;
196 let buf = this.read_pointer(buf)?;
197 let count = this.read_target_usize(count)?;
198 this.read(fd, buf, count, None, dest)?;
199 }
200 "write" => {
201 let [fd, buf, n] = this.check_shim_sig(
202 shim_sig!(extern "C" fn(i32, *const _, usize) -> isize),
203 link_name,
204 abi,
205 args,
206 )?;
207 let fd = this.read_scalar(fd)?.to_i32()?;
208 let buf = this.read_pointer(buf)?;
209 let count = this.read_target_usize(n)?;
210 trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
211 this.write(fd, buf, count, None, dest)?;
212 }
213 "pread" => {
214 let [fd, buf, count, offset] = this.check_shim_sig(
216 shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off_t) -> isize),
217 link_name,
218 abi,
219 args,
220 )?;
221 let fd = this.read_scalar(fd)?.to_i32()?;
222 let buf = this.read_pointer(buf)?;
223 let count = this.read_target_usize(count)?;
224 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
225 this.read(fd, buf, count, Some(offset), dest)?;
226 }
227 "pwrite" => {
228 let [fd, buf, n, offset] = this.check_shim_sig(
230 shim_sig!(extern "C" fn(i32, *const _, usize, libc::off_t) -> isize),
231 link_name,
232 abi,
233 args,
234 )?;
235 let fd = this.read_scalar(fd)?.to_i32()?;
236 let buf = this.read_pointer(buf)?;
237 let count = this.read_target_usize(n)?;
238 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
239 trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
240 this.write(fd, buf, count, Some(offset), dest)?;
241 }
242 "close" => {
243 let [fd] = this.check_shim_sig(
244 shim_sig!(extern "C" fn(i32) -> i32),
245 link_name,
246 abi,
247 args,
248 )?;
249 let result = this.close(fd)?;
250 this.write_scalar(result, dest)?;
251 }
252 "fcntl" => {
253 let ([fd_num, cmd], varargs) =
254 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
255 let result = this.fcntl(fd_num, cmd, varargs)?;
256 this.write_scalar(result, dest)?;
257 }
258 "dup" => {
259 let [old_fd] = this.check_shim_sig(
260 shim_sig!(extern "C" fn(i32) -> i32),
261 link_name,
262 abi,
263 args,
264 )?;
265 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
266 let new_fd = this.dup(old_fd)?;
267 this.write_scalar(new_fd, dest)?;
268 }
269 "dup2" => {
270 let [old_fd, new_fd] = this.check_shim_sig(
271 shim_sig!(extern "C" fn(i32, i32) -> i32),
272 link_name,
273 abi,
274 args,
275 )?;
276 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
277 let new_fd = this.read_scalar(new_fd)?.to_i32()?;
278 let result = this.dup2(old_fd, new_fd)?;
279 this.write_scalar(result, dest)?;
280 }
281 "flock" => {
282 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::MacOs, Os::Illumos], link_name)?;
284 let [fd, op] = this.check_shim_sig(
285 shim_sig!(extern "C" fn(i32, i32) -> i32),
286 link_name,
287 abi,
288 args,
289 )?;
290 let fd = this.read_scalar(fd)?.to_i32()?;
291 let op = this.read_scalar(op)?.to_i32()?;
292 let result = this.flock(fd, op)?;
293 this.write_scalar(result, dest)?;
294 }
295
296 "open" => {
298 let ([path_raw, flag], varargs) =
301 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
302 let result = this.open(path_raw, flag, varargs)?;
303 this.write_scalar(result, dest)?;
304 }
305 "unlink" => {
306 let [path] = this.check_shim_sig(
308 shim_sig!(extern "C" fn(*const _) -> i32),
309 link_name,
310 abi,
311 args,
312 )?;
313 let result = this.unlink(path)?;
314 this.write_scalar(result, dest)?;
315 }
316 "symlink" => {
317 let [target, linkpath] = this.check_shim_sig(
319 shim_sig!(extern "C" fn(*const _, *const _) -> i32),
320 link_name,
321 abi,
322 args,
323 )?;
324 let result = this.symlink(target, linkpath)?;
325 this.write_scalar(result, dest)?;
326 }
327 "fstat" => {
328 let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
329 let result = this.fstat(fd, buf)?;
330 this.write_scalar(result, dest)?;
331 }
332 "rename" => {
333 let [oldpath, newpath] = this.check_shim_sig(
335 shim_sig!(extern "C" fn(*const _, *const _) -> i32),
336 link_name,
337 abi,
338 args,
339 )?;
340 let result = this.rename(oldpath, newpath)?;
341 this.write_scalar(result, dest)?;
342 }
343 "mkdir" => {
344 let [path, mode] = this.check_shim_sig(
346 shim_sig!(extern "C" fn(*const _, libc::mode_t) -> i32),
347 link_name,
348 abi,
349 args,
350 )?;
351 let result = this.mkdir(path, mode)?;
352 this.write_scalar(result, dest)?;
353 }
354 "rmdir" => {
355 let [path] = this.check_shim_sig(
357 shim_sig!(extern "C" fn(*const _) -> i32),
358 link_name,
359 abi,
360 args,
361 )?;
362 let result = this.rmdir(path)?;
363 this.write_scalar(result, dest)?;
364 }
365 "opendir" => {
366 let [name] = this.check_shim_sig(
367 shim_sig!(extern "C" fn(*const _) -> *mut _),
368 link_name,
369 abi,
370 args,
371 )?;
372 let result = this.opendir(name)?;
373 this.write_scalar(result, dest)?;
374 }
375 "closedir" => {
376 let [dirp] = this.check_shim_sig(
377 shim_sig!(extern "C" fn(*mut _) -> i32),
378 link_name,
379 abi,
380 args,
381 )?;
382 let result = this.closedir(dirp)?;
383 this.write_scalar(result, dest)?;
384 }
385 "readdir" => {
386 let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
387 this.readdir(dirp, dest)?;
388 }
389 "lseek" => {
390 let [fd, offset, whence] = this.check_shim_sig(
392 shim_sig!(extern "C" fn(i32, libc::off_t, i32) -> libc::off_t),
393 link_name,
394 abi,
395 args,
396 )?;
397 let fd = this.read_scalar(fd)?.to_i32()?;
398 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
399 let whence = this.read_scalar(whence)?.to_i32()?;
400 this.lseek(fd, offset, whence, dest)?;
401 }
402 "ftruncate" => {
403 let [fd, length] = this.check_shim_sig(
404 shim_sig!(extern "C" fn(i32, libc::off_t) -> i32),
405 link_name,
406 abi,
407 args,
408 )?;
409 let fd = this.read_scalar(fd)?.to_i32()?;
410 let length = this.read_scalar(length)?.to_int(length.layout.size)?;
411 let result = this.ftruncate64(fd, length)?;
412 this.write_scalar(result, dest)?;
413 }
414 "fsync" => {
415 let [fd] = this.check_shim_sig(
417 shim_sig!(extern "C" fn(i32) -> i32),
418 link_name,
419 abi,
420 args,
421 )?;
422 let result = this.fsync(fd)?;
423 this.write_scalar(result, dest)?;
424 }
425 "fdatasync" => {
426 let [fd] = this.check_shim_sig(
428 shim_sig!(extern "C" fn(i32) -> i32),
429 link_name,
430 abi,
431 args,
432 )?;
433 let result = this.fdatasync(fd)?;
434 this.write_scalar(result, dest)?;
435 }
436 "readlink" => {
437 let [pathname, buf, bufsize] = this.check_shim_sig(
438 shim_sig!(extern "C" fn(*const _, *mut _, usize) -> isize),
439 link_name,
440 abi,
441 args,
442 )?;
443 let result = this.readlink(pathname, buf, bufsize)?;
444 this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
445 }
446 "posix_fadvise" => {
447 let [fd, offset, len, advice] = this.check_shim_sig(
448 shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t, i32) -> i32),
449 link_name,
450 abi,
451 args,
452 )?;
453 this.read_scalar(fd)?.to_i32()?;
454 this.read_scalar(offset)?.to_int(offset.layout.size)?;
455 this.read_scalar(len)?.to_int(len.layout.size)?;
456 this.read_scalar(advice)?.to_i32()?;
457 this.write_null(dest)?;
459 }
460
461 "posix_fallocate" => {
462 this.check_target_os(
464 &[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos, Os::Android],
465 link_name,
466 )?;
467 let [fd, offset, len] = this.check_shim_sig(
468 shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t) -> i32),
469 link_name,
470 abi,
471 args,
472 )?;
473
474 let fd = this.read_scalar(fd)?.to_i32()?;
475 let offset =
477 i64::try_from(this.read_scalar(offset)?.to_int(offset.layout.size)?).unwrap();
478 let len = i64::try_from(this.read_scalar(len)?.to_int(len.layout.size)?).unwrap();
479
480 let result = this.posix_fallocate(fd, offset, len)?;
481 this.write_scalar(result, dest)?;
482 }
483
484 "realpath" => {
485 let [path, resolved_path] = this.check_shim_sig(
486 shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
487 link_name,
488 abi,
489 args,
490 )?;
491 let result = this.realpath(path, resolved_path)?;
492 this.write_scalar(result, dest)?;
493 }
494 "mkstemp" => {
495 let [template] = this.check_shim_sig(
496 shim_sig!(extern "C" fn(*mut _) -> i32),
497 link_name,
498 abi,
499 args,
500 )?;
501 let result = this.mkstemp(template)?;
502 this.write_scalar(result, dest)?;
503 }
504
505 "socketpair" => {
507 let [domain, type_, protocol, sv] = this.check_shim_sig(
508 shim_sig!(extern "C" fn(i32, i32, i32, *mut _) -> i32),
509 link_name,
510 abi,
511 args,
512 )?;
513 let result = this.socketpair(domain, type_, protocol, sv)?;
514 this.write_scalar(result, dest)?;
515 }
516 "pipe" => {
517 let [pipefd] = this.check_shim_sig(
518 shim_sig!(extern "C" fn(*mut _) -> i32),
519 link_name,
520 abi,
521 args,
522 )?;
523 let result = this.pipe2(pipefd, None)?;
524 this.write_scalar(result, dest)?;
525 }
526 "pipe2" => {
527 this.check_target_os(
529 &[Os::Linux, Os::Android, Os::FreeBsd, Os::Solaris, Os::Illumos],
530 link_name,
531 )?;
532 let [pipefd, flags] = this.check_shim_sig(
533 shim_sig!(extern "C" fn(*mut _, i32) -> i32),
534 link_name,
535 abi,
536 args,
537 )?;
538 let result = this.pipe2(pipefd, Some(flags))?;
539 this.write_scalar(result, dest)?;
540 }
541
542 "gettimeofday" => {
544 let [tv, tz] = this.check_shim_sig(
545 shim_sig!(extern "C" fn(*mut _, *mut _) -> i32),
546 link_name,
547 abi,
548 args,
549 )?;
550 let result = this.gettimeofday(tv, tz)?;
551 this.write_scalar(result, dest)?;
552 }
553 "localtime_r" => {
554 let [timep, result_op] = this.check_shim_sig(
555 shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
556 link_name,
557 abi,
558 args,
559 )?;
560 let result = this.localtime_r(timep, result_op)?;
561 this.write_pointer(result, dest)?;
562 }
563 "clock_gettime" => {
564 let [clk_id, tp] = this.check_shim_sig(
565 shim_sig!(extern "C" fn(libc::clockid_t, *mut _) -> i32),
566 link_name,
567 abi,
568 args,
569 )?;
570 this.clock_gettime(clk_id, tp, dest)?;
571 }
572
573 "posix_memalign" => {
575 let [memptr, align, size] =
576 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
577 let result = this.posix_memalign(memptr, align, size)?;
578 this.write_scalar(result, dest)?;
579 }
580
581 "mmap" => {
582 let [addr, length, prot, flags, fd, offset] =
583 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
584 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
585 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
586 this.write_scalar(ptr, dest)?;
587 }
588 "munmap" => {
589 let [addr, length] =
590 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
591 let result = this.munmap(addr, length)?;
592 this.write_scalar(result, dest)?;
593 }
594
595 "reallocarray" => {
596 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
598 let [ptr, nmemb, size] =
599 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
600 let ptr = this.read_pointer(ptr)?;
601 let nmemb = this.read_target_usize(nmemb)?;
602 let size = this.read_target_usize(size)?;
603 match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
609 None => {
610 this.set_last_error(LibcError("ENOMEM"))?;
611 this.write_null(dest)?;
612 }
613 Some(len) => {
614 let res = this.realloc(ptr, len.bytes())?;
615 this.write_pointer(res, dest)?;
616 }
617 }
618 }
619 "aligned_alloc" => {
620 let [align, size] =
623 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
624 let res = this.aligned_alloc(align, size)?;
625 this.write_pointer(res, dest)?;
626 }
627
628 "dlsym" => {
630 let [handle, symbol] =
631 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
632 this.read_target_usize(handle)?;
633 let symbol = this.read_pointer(symbol)?;
634 let name = this.read_c_str(symbol)?;
635 if let Ok(name) = str::from_utf8(name)
636 && is_dyn_sym(name, &this.tcx.sess.target.os)
637 {
638 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
639 this.write_pointer(ptr, dest)?;
640 } else {
641 this.write_null(dest)?;
642 }
643 }
644
645 "pthread_key_create" => {
647 let [key, dtor] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
648 let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
649 let dtor = this.read_pointer(dtor)?;
650
651 let dtor = if !this.ptr_is_null(dtor)? {
653 Some((
654 this.get_ptr_fn(dtor)?.as_instance()?,
655 this.machine.current_user_relevant_span(),
656 ))
657 } else {
658 None
659 };
660
661 let key_type = key.layout.ty
664 .builtin_deref(true)
665 .ok_or_else(|| err_ub_format!(
666 "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
667 ))?;
668 let key_layout = this.layout_of(key_type)?;
669
670 let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
672 this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place)?;
673
674 this.write_null(dest)?;
676 }
677 "pthread_key_delete" => {
678 let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
680 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
681 this.machine.tls.delete_tls_key(key)?;
682 this.write_null(dest)?;
684 }
685 "pthread_getspecific" => {
686 let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
688 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
689 let active_thread = this.active_thread();
690 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
691 this.write_scalar(ptr, dest)?;
692 }
693 "pthread_setspecific" => {
694 let [key, new_ptr] =
696 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
697 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
698 let active_thread = this.active_thread();
699 let new_data = this.read_scalar(new_ptr)?;
700 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
701
702 this.write_null(dest)?;
704 }
705
706 "pthread_mutexattr_init" => {
708 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
709 this.pthread_mutexattr_init(attr)?;
710 this.write_null(dest)?;
711 }
712 "pthread_mutexattr_settype" => {
713 let [attr, kind] =
714 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
715 let result = this.pthread_mutexattr_settype(attr, kind)?;
716 this.write_scalar(result, dest)?;
717 }
718 "pthread_mutexattr_destroy" => {
719 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
720 this.pthread_mutexattr_destroy(attr)?;
721 this.write_null(dest)?;
722 }
723 "pthread_mutex_init" => {
724 let [mutex, attr] =
725 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
726 this.pthread_mutex_init(mutex, attr)?;
727 this.write_null(dest)?;
728 }
729 "pthread_mutex_lock" => {
730 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
731 this.pthread_mutex_lock(mutex, dest)?;
732 }
733 "pthread_mutex_trylock" => {
734 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
735 let result = this.pthread_mutex_trylock(mutex)?;
736 this.write_scalar(result, dest)?;
737 }
738 "pthread_mutex_unlock" => {
739 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
740 let result = this.pthread_mutex_unlock(mutex)?;
741 this.write_scalar(result, dest)?;
742 }
743 "pthread_mutex_destroy" => {
744 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
745 this.pthread_mutex_destroy(mutex)?;
746 this.write_int(0, dest)?;
747 }
748 "pthread_rwlock_rdlock" => {
749 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
750 this.pthread_rwlock_rdlock(rwlock, dest)?;
751 }
752 "pthread_rwlock_tryrdlock" => {
753 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
754 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
755 this.write_scalar(result, dest)?;
756 }
757 "pthread_rwlock_wrlock" => {
758 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
759 this.pthread_rwlock_wrlock(rwlock, dest)?;
760 }
761 "pthread_rwlock_trywrlock" => {
762 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
763 let result = this.pthread_rwlock_trywrlock(rwlock)?;
764 this.write_scalar(result, dest)?;
765 }
766 "pthread_rwlock_unlock" => {
767 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
768 this.pthread_rwlock_unlock(rwlock)?;
769 this.write_null(dest)?;
770 }
771 "pthread_rwlock_destroy" => {
772 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
773 this.pthread_rwlock_destroy(rwlock)?;
774 this.write_null(dest)?;
775 }
776 "pthread_condattr_init" => {
777 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
778 this.pthread_condattr_init(attr)?;
779 this.write_null(dest)?;
780 }
781 "pthread_condattr_setclock" => {
782 let [attr, clock_id] =
783 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
784 let result = this.pthread_condattr_setclock(attr, clock_id)?;
785 this.write_scalar(result, dest)?;
786 }
787 "pthread_condattr_getclock" => {
788 let [attr, clock_id] =
789 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
790 this.pthread_condattr_getclock(attr, clock_id)?;
791 this.write_null(dest)?;
792 }
793 "pthread_condattr_destroy" => {
794 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
795 this.pthread_condattr_destroy(attr)?;
796 this.write_null(dest)?;
797 }
798 "pthread_cond_init" => {
799 let [cond, attr] =
800 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
801 this.pthread_cond_init(cond, attr)?;
802 this.write_null(dest)?;
803 }
804 "pthread_cond_signal" => {
805 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
806 this.pthread_cond_signal(cond)?;
807 this.write_null(dest)?;
808 }
809 "pthread_cond_broadcast" => {
810 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
811 this.pthread_cond_broadcast(cond)?;
812 this.write_null(dest)?;
813 }
814 "pthread_cond_wait" => {
815 let [cond, mutex] =
816 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
817 this.pthread_cond_wait(cond, mutex, dest)?;
818 }
819 "pthread_cond_timedwait" => {
820 let [cond, mutex, abstime] =
821 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
822 this.pthread_cond_timedwait(
823 cond, mutex, abstime, dest, false,
824 )?;
825 }
826 "pthread_cond_destroy" => {
827 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
828 this.pthread_cond_destroy(cond)?;
829 this.write_null(dest)?;
830 }
831
832 "pthread_create" => {
834 let [thread, attr, start, arg] =
835 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
836 this.pthread_create(thread, attr, start, arg)?;
837 this.write_null(dest)?;
838 }
839 "pthread_join" => {
840 let [thread, retval] =
841 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
842 this.pthread_join(thread, retval, dest)?;
843 }
844 "pthread_detach" => {
845 let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
846 let res = this.pthread_detach(thread)?;
847 this.write_scalar(res, dest)?;
848 }
849 "pthread_self" => {
850 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
851 let res = this.pthread_self()?;
852 this.write_scalar(res, dest)?;
853 }
854 "sched_yield" => {
855 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
857 this.sched_yield()?;
858 this.write_null(dest)?;
859 }
860 "nanosleep" => {
861 let [duration, rem] =
862 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
863 let result = this.nanosleep(duration, rem)?;
864 this.write_scalar(result, dest)?;
865 }
866 "clock_nanosleep" => {
867 this.check_target_os(
869 &[Os::FreeBsd, Os::Linux, Os::Android, Os::Solaris, Os::Illumos],
870 link_name,
871 )?;
872 let [clock_id, flags, req, rem] =
873 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
874 let result = this.clock_nanosleep(clock_id, flags, req, rem)?;
875 this.write_scalar(result, dest)?;
876 }
877 "sched_getaffinity" => {
878 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
880 let [pid, cpusetsize, mask] =
881 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
882 let pid = this.read_scalar(pid)?.to_u32()?;
883 let cpusetsize = this.read_target_usize(cpusetsize)?;
884 let mask = this.read_pointer(mask)?;
885
886 let thread_id = match pid {
888 0 => this.active_thread(),
889 _ =>
890 throw_unsup_format!(
891 "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"
892 ),
893 };
894
895 let chunk_size = CpuAffinityMask::chunk_size(this);
897
898 if this.ptr_is_null(mask)? {
899 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
900 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
901 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
903 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
904 let cpuset = cpuset.clone();
905 let byte_count =
907 Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
908 this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
909 this.write_null(dest)?;
910 } else {
911 this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
913 }
914 }
915 "sched_setaffinity" => {
916 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
918 let [pid, cpusetsize, mask] =
919 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
920 let pid = this.read_scalar(pid)?.to_u32()?;
921 let cpusetsize = this.read_target_usize(cpusetsize)?;
922 let mask = this.read_pointer(mask)?;
923
924 let thread_id = match pid {
926 0 => this.active_thread(),
927 _ =>
928 throw_unsup_format!(
929 "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"
930 ),
931 };
932
933 if this.ptr_is_null(mask)? {
934 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
935 } else {
936 let bits_slice =
940 this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
941 let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
943 std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
944 match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
945 Some(cpuset) => {
946 this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
947 this.write_null(dest)?;
948 }
949 None => {
950 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
952 }
953 }
954 }
955 }
956
957 "isatty" => {
959 let [fd] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
960 let result = this.isatty(fd)?;
961 this.write_scalar(result, dest)?;
962 }
963 "pthread_atfork" => {
964 let [prepare, parent, child] =
966 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
967 this.read_pointer(prepare)?;
968 this.read_pointer(parent)?;
969 this.read_pointer(child)?;
970 this.write_null(dest)?;
972 }
973 "getentropy" => {
974 this.check_target_os(
977 &[Os::Linux, Os::MacOs, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
978 link_name,
979 )?;
980 let [buf, bufsize] =
981 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
982 let buf = this.read_pointer(buf)?;
983 let bufsize = this.read_target_usize(bufsize)?;
984
985 if bufsize > 256 {
991 this.set_last_error_and_return(LibcError("EIO"), dest)?;
992 } else {
993 this.gen_random(buf, bufsize)?;
994 this.write_null(dest)?;
995 }
996 }
997
998 "strerror_r" => {
999 let [errnum, buf, buflen] =
1000 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1001 let result = this.strerror_r(errnum, buf, buflen)?;
1002 this.write_scalar(result, dest)?;
1003 }
1004
1005 "getrandom" => {
1006 this.check_target_os(
1009 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
1010 link_name,
1011 )?;
1012 let [ptr, len, flags] =
1013 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1014 let ptr = this.read_pointer(ptr)?;
1015 let len = this.read_target_usize(len)?;
1016 let _flags = this.read_scalar(flags)?.to_i32()?;
1017 this.gen_random(ptr, len)?;
1019 this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
1020 }
1021 "arc4random_buf" => {
1022 this.check_target_os(&[Os::FreeBsd, Os::Illumos, Os::Solaris], link_name)?;
1025 let [ptr, len] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1026 let ptr = this.read_pointer(ptr)?;
1027 let len = this.read_target_usize(len)?;
1028 this.gen_random(ptr, len)?;
1029 }
1030 "_Unwind_RaiseException" => {
1031 this.check_target_os(
1045 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android, Os::MacOs],
1046 link_name,
1047 )?;
1048 let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1050 this.handle_miri_start_unwind(payload)?;
1051 return interp_ok(EmulateItemResult::NeedsUnwind);
1052 }
1053 "getuid" | "geteuid" => {
1054 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1055 this.write_int(UID, dest)?;
1057 }
1058
1059 "pthread_attr_getguardsize" if this.frame_in_std() => {
1062 let [_attr, guard_size] =
1063 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1064 let guard_size_layout = this.machine.layouts.usize;
1065 let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
1066 this.write_scalar(
1067 Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
1068 &guard_size,
1069 )?;
1070
1071 this.write_null(dest)?;
1073 }
1074
1075 "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
1076 let [_] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1077 this.write_null(dest)?;
1078 }
1079 "pthread_attr_setstacksize" if this.frame_in_std() => {
1080 let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1081 this.write_null(dest)?;
1082 }
1083
1084 "pthread_attr_getstack" if this.frame_in_std() => {
1085 let [attr_place, addr_place, size_place] =
1088 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1089 let _attr_place =
1090 this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
1091 let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?;
1092 let size_place = this.deref_pointer_as(size_place, this.machine.layouts.usize)?;
1093
1094 this.write_scalar(
1095 Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
1096 &addr_place,
1097 )?;
1098 this.write_scalar(
1099 Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
1100 &size_place,
1101 )?;
1102
1103 this.write_null(dest)?;
1105 }
1106
1107 "signal" | "sigaltstack" if this.frame_in_std() => {
1108 let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1109 this.write_null(dest)?;
1110 }
1111 "sigaction" | "mprotect" if this.frame_in_std() => {
1112 let [_, _, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1113 this.write_null(dest)?;
1114 }
1115
1116 "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
1117 let [uid, pwd, buf, buflen, result] =
1119 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1120 this.check_no_isolation("`getpwuid_r`")?;
1121
1122 let uid = this.read_scalar(uid)?.to_u32()?;
1123 let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?;
1124 let buf = this.read_pointer(buf)?;
1125 let buflen = this.read_target_usize(buflen)?;
1126 let result = this.deref_pointer_as(result, this.machine.layouts.mut_raw_ptr)?;
1127
1128 if uid != UID {
1130 throw_unsup_format!("`getpwuid_r` on other users is not supported");
1131 }
1132
1133 this.write_uninit(&pwd)?;
1136
1137 #[allow(deprecated)]
1139 let home_dir = std::env::home_dir().unwrap();
1140 let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
1141 let pw_dir = this.project_field_named(&pwd, "pw_dir")?;
1142 this.write_pointer(buf, &pw_dir)?;
1143
1144 if written {
1145 this.write_pointer(pwd.ptr(), &result)?;
1146 this.write_null(dest)?;
1147 } else {
1148 this.write_null(&result)?;
1149 this.write_scalar(this.eval_libc("ERANGE"), dest)?;
1150 }
1151 }
1152
1153 _ => {
1155 let target_os = &this.tcx.sess.target.os;
1156 return match target_os {
1157 Os::Android =>
1158 android::EvalContextExt::emulate_foreign_item_inner(
1159 this, link_name, abi, args, dest,
1160 ),
1161 Os::FreeBsd =>
1162 freebsd::EvalContextExt::emulate_foreign_item_inner(
1163 this, link_name, abi, args, dest,
1164 ),
1165 Os::Linux =>
1166 linux::EvalContextExt::emulate_foreign_item_inner(
1167 this, link_name, abi, args, dest,
1168 ),
1169 Os::MacOs =>
1170 macos::EvalContextExt::emulate_foreign_item_inner(
1171 this, link_name, abi, args, dest,
1172 ),
1173 Os::Solaris | Os::Illumos =>
1174 solarish::EvalContextExt::emulate_foreign_item_inner(
1175 this, link_name, abi, args, dest,
1176 ),
1177 _ => interp_ok(EmulateItemResult::NotSupported),
1178 };
1179 }
1180 };
1181
1182 interp_ok(EmulateItemResult::NeedsReturn)
1183 }
1184}