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 "uname" => {
178 this.check_target_os(
180 &[Os::Linux, Os::Android, Os::MacOs, Os::Solaris, Os::Illumos],
181 link_name,
182 )?;
183 let [uname] = this.check_shim_sig(
184 shim_sig!(extern "C" fn(*mut _) -> i32),
185 link_name,
186 abi,
187 args,
188 )?;
189 let result = this.uname(uname, None)?;
190 this.write_scalar(result, dest)?;
191 }
192 "sysconf" => {
193 let [val] = this.check_shim_sig(
194 shim_sig!(extern "C" fn(i32) -> isize),
195 link_name,
196 abi,
197 args,
198 )?;
199 let result = this.sysconf(val)?;
200 this.write_scalar(result, dest)?;
201 }
202 "read" => {
204 let [fd, buf, count] = this.check_shim_sig(
205 shim_sig!(extern "C" fn(i32, *mut _, usize) -> isize),
206 link_name,
207 abi,
208 args,
209 )?;
210 let fd = this.read_scalar(fd)?.to_i32()?;
211 let buf = this.read_pointer(buf)?;
212 let count = this.read_target_usize(count)?;
213 this.read(fd, buf, count, None, dest)?;
214 }
215 "write" => {
216 let [fd, buf, n] = this.check_shim_sig(
217 shim_sig!(extern "C" fn(i32, *const _, usize) -> isize),
218 link_name,
219 abi,
220 args,
221 )?;
222 let fd = this.read_scalar(fd)?.to_i32()?;
223 let buf = this.read_pointer(buf)?;
224 let count = this.read_target_usize(n)?;
225 trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
226 this.write(fd, buf, count, None, dest)?;
227 }
228 "pread" => {
229 let [fd, buf, count, offset] = this.check_shim_sig(
231 shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off_t) -> isize),
232 link_name,
233 abi,
234 args,
235 )?;
236 let fd = this.read_scalar(fd)?.to_i32()?;
237 let buf = this.read_pointer(buf)?;
238 let count = this.read_target_usize(count)?;
239 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
240 this.read(fd, buf, count, Some(offset), dest)?;
241 }
242 "pwrite" => {
243 let [fd, buf, n, offset] = this.check_shim_sig(
245 shim_sig!(extern "C" fn(i32, *const _, usize, libc::off_t) -> isize),
246 link_name,
247 abi,
248 args,
249 )?;
250 let fd = this.read_scalar(fd)?.to_i32()?;
251 let buf = this.read_pointer(buf)?;
252 let count = this.read_target_usize(n)?;
253 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
254 trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
255 this.write(fd, buf, count, Some(offset), dest)?;
256 }
257 "close" => {
258 let [fd] = this.check_shim_sig(
259 shim_sig!(extern "C" fn(i32) -> i32),
260 link_name,
261 abi,
262 args,
263 )?;
264 let result = this.close(fd)?;
265 this.write_scalar(result, dest)?;
266 }
267 "fcntl" => {
268 let ([fd_num, cmd], varargs) =
269 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
270 let result = this.fcntl(fd_num, cmd, varargs)?;
271 this.write_scalar(result, dest)?;
272 }
273 "dup" => {
274 let [old_fd] = this.check_shim_sig(
275 shim_sig!(extern "C" fn(i32) -> i32),
276 link_name,
277 abi,
278 args,
279 )?;
280 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
281 let new_fd = this.dup(old_fd)?;
282 this.write_scalar(new_fd, dest)?;
283 }
284 "dup2" => {
285 let [old_fd, new_fd] = this.check_shim_sig(
286 shim_sig!(extern "C" fn(i32, i32) -> i32),
287 link_name,
288 abi,
289 args,
290 )?;
291 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
292 let new_fd = this.read_scalar(new_fd)?.to_i32()?;
293 let result = this.dup2(old_fd, new_fd)?;
294 this.write_scalar(result, dest)?;
295 }
296 "flock" => {
297 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::MacOs, Os::Illumos], link_name)?;
299 let [fd, op] = this.check_shim_sig(
300 shim_sig!(extern "C" fn(i32, i32) -> i32),
301 link_name,
302 abi,
303 args,
304 )?;
305 let fd = this.read_scalar(fd)?.to_i32()?;
306 let op = this.read_scalar(op)?.to_i32()?;
307 let result = this.flock(fd, op)?;
308 this.write_scalar(result, dest)?;
309 }
310 "ioctl" => {
311 let ([fd, op], varargs) =
312 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
313 let result = this.ioctl(fd, op, varargs)?;
314 this.write_scalar(result, dest)?;
315 }
316
317 "open" => {
319 let ([path_raw, flag], varargs) =
322 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
323 let result = this.open(path_raw, flag, varargs)?;
324 this.write_scalar(result, dest)?;
325 }
326 "unlink" => {
327 let [path] = this.check_shim_sig(
329 shim_sig!(extern "C" fn(*const _) -> i32),
330 link_name,
331 abi,
332 args,
333 )?;
334 let result = this.unlink(path)?;
335 this.write_scalar(result, dest)?;
336 }
337 "symlink" => {
338 let [target, linkpath] = this.check_shim_sig(
340 shim_sig!(extern "C" fn(*const _, *const _) -> i32),
341 link_name,
342 abi,
343 args,
344 )?;
345 let result = this.symlink(target, linkpath)?;
346 this.write_scalar(result, dest)?;
347 }
348 "fstat" => {
349 let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
350 let result = this.fstat(fd, buf)?;
351 this.write_scalar(result, dest)?;
352 }
353 "lstat" => {
354 let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
355 let result = this.lstat(path, buf)?;
356 this.write_scalar(result, dest)?;
357 }
358 "stat" => {
359 let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
360 let result = this.stat(path, buf)?;
361 this.write_scalar(result, dest)?;
362 }
363 "rename" => {
364 let [oldpath, newpath] = this.check_shim_sig(
366 shim_sig!(extern "C" fn(*const _, *const _) -> i32),
367 link_name,
368 abi,
369 args,
370 )?;
371 let result = this.rename(oldpath, newpath)?;
372 this.write_scalar(result, dest)?;
373 }
374 "mkdir" => {
375 let [path, mode] = this.check_shim_sig(
377 shim_sig!(extern "C" fn(*const _, libc::mode_t) -> i32),
378 link_name,
379 abi,
380 args,
381 )?;
382 let result = this.mkdir(path, mode)?;
383 this.write_scalar(result, dest)?;
384 }
385 "rmdir" => {
386 let [path] = this.check_shim_sig(
388 shim_sig!(extern "C" fn(*const _) -> i32),
389 link_name,
390 abi,
391 args,
392 )?;
393 let result = this.rmdir(path)?;
394 this.write_scalar(result, dest)?;
395 }
396 "opendir" => {
397 let [name] = this.check_shim_sig(
398 shim_sig!(extern "C" fn(*const _) -> *mut _),
399 link_name,
400 abi,
401 args,
402 )?;
403 let result = this.opendir(name)?;
404 this.write_scalar(result, dest)?;
405 }
406 "closedir" => {
407 let [dirp] = this.check_shim_sig(
408 shim_sig!(extern "C" fn(*mut _) -> i32),
409 link_name,
410 abi,
411 args,
412 )?;
413 let result = this.closedir(dirp)?;
414 this.write_scalar(result, dest)?;
415 }
416 "readdir" => {
417 let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
418 this.readdir(dirp, dest)?;
419 }
420 "lseek" => {
421 let [fd, offset, whence] = this.check_shim_sig(
423 shim_sig!(extern "C" fn(i32, libc::off_t, i32) -> libc::off_t),
424 link_name,
425 abi,
426 args,
427 )?;
428 let fd = this.read_scalar(fd)?.to_i32()?;
429 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
430 let whence = this.read_scalar(whence)?.to_i32()?;
431 this.lseek(fd, offset, whence, dest)?;
432 }
433 "ftruncate" => {
434 let [fd, length] = this.check_shim_sig(
435 shim_sig!(extern "C" fn(i32, libc::off_t) -> i32),
436 link_name,
437 abi,
438 args,
439 )?;
440 let fd = this.read_scalar(fd)?.to_i32()?;
441 let length = this.read_scalar(length)?.to_int(length.layout.size)?;
442 let result = this.ftruncate64(fd, length)?;
443 this.write_scalar(result, dest)?;
444 }
445 "fsync" => {
446 let [fd] = this.check_shim_sig(
448 shim_sig!(extern "C" fn(i32) -> i32),
449 link_name,
450 abi,
451 args,
452 )?;
453 let result = this.fsync(fd)?;
454 this.write_scalar(result, dest)?;
455 }
456 "fdatasync" => {
457 let [fd] = this.check_shim_sig(
459 shim_sig!(extern "C" fn(i32) -> i32),
460 link_name,
461 abi,
462 args,
463 )?;
464 let result = this.fdatasync(fd)?;
465 this.write_scalar(result, dest)?;
466 }
467 "readlink" => {
468 let [pathname, buf, bufsize] = this.check_shim_sig(
469 shim_sig!(extern "C" fn(*const _, *mut _, usize) -> isize),
470 link_name,
471 abi,
472 args,
473 )?;
474 let result = this.readlink(pathname, buf, bufsize)?;
475 this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
476 }
477 "posix_fadvise" => {
478 let [fd, offset, len, advice] = this.check_shim_sig(
479 shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t, i32) -> i32),
480 link_name,
481 abi,
482 args,
483 )?;
484 this.read_scalar(fd)?.to_i32()?;
485 this.read_scalar(offset)?.to_int(offset.layout.size)?;
486 this.read_scalar(len)?.to_int(len.layout.size)?;
487 this.read_scalar(advice)?.to_i32()?;
488 this.write_null(dest)?;
490 }
491
492 "posix_fallocate" => {
493 this.check_target_os(
495 &[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos, Os::Android],
496 link_name,
497 )?;
498 let [fd, offset, len] = this.check_shim_sig(
499 shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t) -> i32),
500 link_name,
501 abi,
502 args,
503 )?;
504
505 let fd = this.read_scalar(fd)?.to_i32()?;
506 let offset =
508 i64::try_from(this.read_scalar(offset)?.to_int(offset.layout.size)?).unwrap();
509 let len = i64::try_from(this.read_scalar(len)?.to_int(len.layout.size)?).unwrap();
510
511 let result = this.posix_fallocate(fd, offset, len)?;
512 this.write_scalar(result, dest)?;
513 }
514
515 "realpath" => {
516 let [path, resolved_path] = this.check_shim_sig(
517 shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
518 link_name,
519 abi,
520 args,
521 )?;
522 let result = this.realpath(path, resolved_path)?;
523 this.write_scalar(result, dest)?;
524 }
525 "mkstemp" => {
526 let [template] = this.check_shim_sig(
527 shim_sig!(extern "C" fn(*mut _) -> i32),
528 link_name,
529 abi,
530 args,
531 )?;
532 let result = this.mkstemp(template)?;
533 this.write_scalar(result, dest)?;
534 }
535
536 "socketpair" => {
538 let [domain, type_, protocol, sv] = this.check_shim_sig(
539 shim_sig!(extern "C" fn(i32, i32, i32, *mut _) -> i32),
540 link_name,
541 abi,
542 args,
543 )?;
544 let result = this.socketpair(domain, type_, protocol, sv)?;
545 this.write_scalar(result, dest)?;
546 }
547 "pipe" => {
548 let [pipefd] = this.check_shim_sig(
549 shim_sig!(extern "C" fn(*mut _) -> i32),
550 link_name,
551 abi,
552 args,
553 )?;
554 let result = this.pipe2(pipefd, None)?;
555 this.write_scalar(result, dest)?;
556 }
557 "pipe2" => {
558 this.check_target_os(
560 &[Os::Linux, Os::Android, Os::FreeBsd, Os::Solaris, Os::Illumos],
561 link_name,
562 )?;
563 let [pipefd, flags] = this.check_shim_sig(
564 shim_sig!(extern "C" fn(*mut _, i32) -> i32),
565 link_name,
566 abi,
567 args,
568 )?;
569 let result = this.pipe2(pipefd, Some(flags))?;
570 this.write_scalar(result, dest)?;
571 }
572
573 "socket" => {
575 let [domain, type_, protocol] = this.check_shim_sig(
576 shim_sig!(extern "C" fn(i32, i32, i32) -> i32),
577 link_name,
578 abi,
579 args,
580 )?;
581 let result = this.socket(domain, type_, protocol)?;
582 this.write_scalar(result, dest)?;
583 }
584 "bind" => {
585 let [socket, address, address_len] = this.check_shim_sig(
586 shim_sig!(extern "C" fn(i32, *const _, libc::socklen_t) -> i32),
587 link_name,
588 abi,
589 args,
590 )?;
591 let result = this.bind(socket, address, address_len)?;
592 this.write_scalar(result, dest)?;
593 }
594 "listen" => {
595 let [socket, backlog] = this.check_shim_sig(
596 shim_sig!(extern "C" fn(i32, i32) -> i32),
597 link_name,
598 abi,
599 args,
600 )?;
601 let result = this.listen(socket, backlog)?;
602 this.write_scalar(result, dest)?;
603 }
604 "accept" => {
605 let [socket, address, address_len] = this.check_shim_sig(
606 shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32),
607 link_name,
608 abi,
609 args,
610 )?;
611 this.accept4(socket, address, address_len, None, dest)?;
612 }
613 "accept4" => {
614 let [socket, address, address_len, flags] = this.check_shim_sig(
615 shim_sig!(extern "C" fn(i32, *mut _, *mut _, i32) -> i32),
616 link_name,
617 abi,
618 args,
619 )?;
620 this.accept4(socket, address, address_len, Some(flags), dest)?;
621 }
622 "connect" => {
623 let [socket, address, address_len] = this.check_shim_sig(
624 shim_sig!(extern "C" fn(i32, *const _, libc::socklen_t) -> i32),
625 link_name,
626 abi,
627 args,
628 )?;
629 this.connect(socket, address, address_len, dest)?;
630 }
631 "send" => {
632 let [socket, buffer, length, flags] = this.check_shim_sig(
633 shim_sig!(extern "C" fn(i32, *const _, libc::size_t, i32) -> libc::ssize_t),
634 link_name,
635 abi,
636 args,
637 )?;
638 this.send(socket, buffer, length, flags, dest)?;
639 }
640 "recv" => {
641 let [socket, buffer, length, flags] = this.check_shim_sig(
642 shim_sig!(extern "C" fn(i32, *mut _, libc::size_t, i32) -> libc::ssize_t),
643 link_name,
644 abi,
645 args,
646 )?;
647 this.recv(socket, buffer, length, flags, dest)?;
648 }
649 "setsockopt" => {
650 let [socket, level, option_name, option_value, option_len] = this.check_shim_sig(
651 shim_sig!(extern "C" fn(i32, i32, i32, *const _, libc::socklen_t) -> i32),
652 link_name,
653 abi,
654 args,
655 )?;
656 let result =
657 this.setsockopt(socket, level, option_name, option_value, option_len)?;
658 this.write_scalar(result, dest)?;
659 }
660 "getsockname" => {
661 let [socket, address, address_len] = this.check_shim_sig(
662 shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32),
663 link_name,
664 abi,
665 args,
666 )?;
667 let result = this.getsockname(socket, address, address_len)?;
668 this.write_scalar(result, dest)?;
669 }
670 "getpeername" => {
671 let [socket, address, address_len] = this.check_shim_sig(
672 shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32),
673 link_name,
674 abi,
675 args,
676 )?;
677 this.getpeername(socket, address, address_len, dest)?;
678 }
679
680 "gettimeofday" => {
682 let [tv, tz] = this.check_shim_sig(
683 shim_sig!(extern "C" fn(*mut _, *mut _) -> i32),
684 link_name,
685 abi,
686 args,
687 )?;
688 let result = this.gettimeofday(tv, tz)?;
689 this.write_scalar(result, dest)?;
690 }
691 "localtime_r" => {
692 let [timep, result_op] = this.check_shim_sig(
693 shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
694 link_name,
695 abi,
696 args,
697 )?;
698 let result = this.localtime_r(timep, result_op)?;
699 this.write_pointer(result, dest)?;
700 }
701 "clock_gettime" => {
702 let [clk_id, tp] = this.check_shim_sig(
703 shim_sig!(extern "C" fn(libc::clockid_t, *mut _) -> i32),
704 link_name,
705 abi,
706 args,
707 )?;
708 this.clock_gettime(clk_id, tp, dest)?;
709 }
710
711 "posix_memalign" => {
713 let [memptr, align, size] =
714 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
715 let result = this.posix_memalign(memptr, align, size)?;
716 this.write_scalar(result, dest)?;
717 }
718
719 "mmap" => {
720 let [addr, length, prot, flags, fd, offset] =
721 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
722 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
723 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
724 this.write_scalar(ptr, dest)?;
725 }
726 "munmap" => {
727 let [addr, length] =
728 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
729 let result = this.munmap(addr, length)?;
730 this.write_scalar(result, dest)?;
731 }
732
733 "reallocarray" => {
734 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
736 let [ptr, nmemb, size] =
737 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
738 let ptr = this.read_pointer(ptr)?;
739 let nmemb = this.read_target_usize(nmemb)?;
740 let size = this.read_target_usize(size)?;
741 match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
747 None => {
748 this.set_last_error(LibcError("ENOMEM"))?;
749 this.write_null(dest)?;
750 }
751 Some(len) => {
752 let res = this.realloc(ptr, len.bytes())?;
753 this.write_pointer(res, dest)?;
754 }
755 }
756 }
757 "aligned_alloc" => {
758 let [align, size] =
761 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
762 let res = this.aligned_alloc(align, size)?;
763 this.write_pointer(res, dest)?;
764 }
765
766 "dlsym" => {
768 let [handle, symbol] =
769 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
770 this.read_target_usize(handle)?;
771 let symbol = this.read_pointer(symbol)?;
772 let name = this.read_c_str(symbol)?;
773 let Ok(name) = str::from_utf8(name) else {
774 throw_unsup_format!("dlsym: non UTF-8 symbol name not supported")
775 };
776 if is_dyn_sym(name, &this.tcx.sess.target.os) {
777 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
778 this.write_pointer(ptr, dest)?;
779 } else if let Some(&ptr) = this.machine.extern_statics.get(&Symbol::intern(name)) {
780 this.write_pointer(ptr, dest)?;
781 } else {
782 this.write_null(dest)?;
783 }
784 }
785
786 "pthread_key_create" => {
788 let [key, dtor] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
789 let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
790 let dtor = this.read_pointer(dtor)?;
791
792 let dtor = if !this.ptr_is_null(dtor)? {
794 Some((
795 this.get_ptr_fn(dtor)?.as_instance()?,
796 this.machine.current_user_relevant_span(),
797 ))
798 } else {
799 None
800 };
801
802 let key_type = key.layout.ty
805 .builtin_deref(true)
806 .ok_or_else(|| err_ub_format!(
807 "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
808 ))?;
809 let key_layout = this.layout_of(key_type)?;
810
811 let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
813 this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place)?;
814
815 this.write_null(dest)?;
817 }
818 "pthread_key_delete" => {
819 let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
821 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
822 this.machine.tls.delete_tls_key(key)?;
823 this.write_null(dest)?;
825 }
826 "pthread_getspecific" => {
827 let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
829 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
830 let active_thread = this.active_thread();
831 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
832 this.write_scalar(ptr, dest)?;
833 }
834 "pthread_setspecific" => {
835 let [key, new_ptr] =
837 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
838 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
839 let active_thread = this.active_thread();
840 let new_data = this.read_scalar(new_ptr)?;
841 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
842
843 this.write_null(dest)?;
845 }
846
847 "pthread_mutexattr_init" => {
849 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
850 this.pthread_mutexattr_init(attr)?;
851 this.write_null(dest)?;
852 }
853 "pthread_mutexattr_settype" => {
854 let [attr, kind] =
855 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
856 let result = this.pthread_mutexattr_settype(attr, kind)?;
857 this.write_scalar(result, dest)?;
858 }
859 "pthread_mutexattr_destroy" => {
860 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
861 this.pthread_mutexattr_destroy(attr)?;
862 this.write_null(dest)?;
863 }
864 "pthread_mutex_init" => {
865 let [mutex, attr] =
866 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
867 this.pthread_mutex_init(mutex, attr)?;
868 this.write_null(dest)?;
869 }
870 "pthread_mutex_lock" => {
871 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
872 this.pthread_mutex_lock(mutex, dest)?;
873 }
874 "pthread_mutex_trylock" => {
875 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
876 let result = this.pthread_mutex_trylock(mutex)?;
877 this.write_scalar(result, dest)?;
878 }
879 "pthread_mutex_unlock" => {
880 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
881 let result = this.pthread_mutex_unlock(mutex)?;
882 this.write_scalar(result, dest)?;
883 }
884 "pthread_mutex_destroy" => {
885 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
886 this.pthread_mutex_destroy(mutex)?;
887 this.write_int(0, dest)?;
888 }
889 "pthread_rwlock_rdlock" => {
890 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
891 this.pthread_rwlock_rdlock(rwlock, dest)?;
892 }
893 "pthread_rwlock_tryrdlock" => {
894 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
895 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
896 this.write_scalar(result, dest)?;
897 }
898 "pthread_rwlock_wrlock" => {
899 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
900 this.pthread_rwlock_wrlock(rwlock, dest)?;
901 }
902 "pthread_rwlock_trywrlock" => {
903 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
904 let result = this.pthread_rwlock_trywrlock(rwlock)?;
905 this.write_scalar(result, dest)?;
906 }
907 "pthread_rwlock_unlock" => {
908 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
909 this.pthread_rwlock_unlock(rwlock)?;
910 this.write_null(dest)?;
911 }
912 "pthread_rwlock_destroy" => {
913 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
914 this.pthread_rwlock_destroy(rwlock)?;
915 this.write_null(dest)?;
916 }
917 "pthread_condattr_init" => {
918 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
919 this.pthread_condattr_init(attr)?;
920 this.write_null(dest)?;
921 }
922 "pthread_condattr_setclock" => {
923 let [attr, clock_id] =
924 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
925 let result = this.pthread_condattr_setclock(attr, clock_id)?;
926 this.write_scalar(result, dest)?;
927 }
928 "pthread_condattr_getclock" => {
929 let [attr, clock_id] =
930 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
931 this.pthread_condattr_getclock(attr, clock_id)?;
932 this.write_null(dest)?;
933 }
934 "pthread_condattr_destroy" => {
935 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
936 this.pthread_condattr_destroy(attr)?;
937 this.write_null(dest)?;
938 }
939 "pthread_cond_init" => {
940 let [cond, attr] =
941 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
942 this.pthread_cond_init(cond, attr)?;
943 this.write_null(dest)?;
944 }
945 "pthread_cond_signal" => {
946 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
947 this.pthread_cond_signal(cond)?;
948 this.write_null(dest)?;
949 }
950 "pthread_cond_broadcast" => {
951 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
952 this.pthread_cond_broadcast(cond)?;
953 this.write_null(dest)?;
954 }
955 "pthread_cond_wait" => {
956 let [cond, mutex] =
957 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
958 this.pthread_cond_wait(cond, mutex, dest)?;
959 }
960 "pthread_cond_timedwait" => {
961 let [cond, mutex, abstime] =
962 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
963 this.pthread_cond_timedwait(
964 cond, mutex, abstime, dest, false,
965 )?;
966 }
967 "pthread_cond_destroy" => {
968 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
969 this.pthread_cond_destroy(cond)?;
970 this.write_null(dest)?;
971 }
972
973 "pthread_create" => {
975 let [thread, attr, start, arg] =
976 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
977 this.pthread_create(thread, attr, start, arg)?;
978 this.write_null(dest)?;
979 }
980 "pthread_join" => {
981 let [thread, retval] =
982 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
983 this.pthread_join(thread, retval, dest)?;
984 }
985 "pthread_detach" => {
986 let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
987 let res = this.pthread_detach(thread)?;
988 this.write_scalar(res, dest)?;
989 }
990 "pthread_self" => {
991 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
992 let res = this.pthread_self()?;
993 this.write_scalar(res, dest)?;
994 }
995 "sched_yield" => {
996 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
998 this.sched_yield()?;
999 this.write_null(dest)?;
1000 }
1001 "nanosleep" => {
1002 let [duration, rem] =
1003 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1004 let result = this.nanosleep(duration, rem)?;
1005 this.write_scalar(result, dest)?;
1006 }
1007 "clock_nanosleep" => {
1008 this.check_target_os(
1010 &[Os::FreeBsd, Os::Linux, Os::Android, Os::Solaris, Os::Illumos],
1011 link_name,
1012 )?;
1013 let [clock_id, flags, req, rem] =
1014 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1015 let result = this.clock_nanosleep(clock_id, flags, req, rem)?;
1016 this.write_scalar(result, dest)?;
1017 }
1018 "sched_getaffinity" => {
1019 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
1021 let [pid, cpusetsize, mask] =
1022 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1023 let pid = this.read_scalar(pid)?.to_u32()?;
1024 let cpusetsize = this.read_target_usize(cpusetsize)?;
1025 let mask = this.read_pointer(mask)?;
1026
1027 let thread_id = match pid {
1029 0 => this.active_thread(),
1030 _ =>
1031 throw_unsup_format!(
1032 "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"
1033 ),
1034 };
1035
1036 let chunk_size = CpuAffinityMask::chunk_size(this);
1038
1039 if this.ptr_is_null(mask)? {
1040 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
1041 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
1042 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
1044 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
1045 let cpuset = cpuset.clone();
1046 let byte_count =
1048 Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
1049 this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
1050 this.write_null(dest)?;
1051 } else {
1052 this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
1054 }
1055 }
1056 "sched_setaffinity" => {
1057 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
1059 let [pid, cpusetsize, mask] =
1060 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1061 let pid = this.read_scalar(pid)?.to_u32()?;
1062 let cpusetsize = this.read_target_usize(cpusetsize)?;
1063 let mask = this.read_pointer(mask)?;
1064
1065 let thread_id = match pid {
1067 0 => this.active_thread(),
1068 _ =>
1069 throw_unsup_format!(
1070 "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"
1071 ),
1072 };
1073
1074 if this.ptr_is_null(mask)? {
1075 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
1076 } else {
1077 let bits_slice =
1081 this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
1082 let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
1084 std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
1085 match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
1086 Some(cpuset) => {
1087 this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
1088 this.write_null(dest)?;
1089 }
1090 None => {
1091 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
1093 }
1094 }
1095 }
1096 }
1097
1098 "isatty" => {
1100 let [fd] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1101 let result = this.isatty(fd)?;
1102 this.write_scalar(result, dest)?;
1103 }
1104 "pthread_atfork" => {
1105 let [prepare, parent, child] =
1107 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1108 this.read_pointer(prepare)?;
1109 this.read_pointer(parent)?;
1110 this.read_pointer(child)?;
1111 this.write_null(dest)?;
1113 }
1114 "getentropy" => {
1115 this.check_target_os(
1118 &[Os::Linux, Os::MacOs, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
1119 link_name,
1120 )?;
1121 let [buf, bufsize] =
1122 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1123 let buf = this.read_pointer(buf)?;
1124 let bufsize = this.read_target_usize(bufsize)?;
1125
1126 if bufsize > 256 {
1132 this.set_last_error_and_return(LibcError("EIO"), dest)?;
1133 } else {
1134 this.gen_random(buf, bufsize)?;
1135 this.write_null(dest)?;
1136 }
1137 }
1138
1139 "strerror_r" => {
1140 let [errnum, buf, buflen] =
1141 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1142 let result = this.strerror_r(errnum, buf, buflen)?;
1143 this.write_scalar(result, dest)?;
1144 }
1145
1146 "getrandom" => {
1147 this.check_target_os(
1150 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
1151 link_name,
1152 )?;
1153 let [ptr, len, flags] =
1154 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1155 let ptr = this.read_pointer(ptr)?;
1156 let len = this.read_target_usize(len)?;
1157 let _flags = this.read_scalar(flags)?.to_i32()?;
1158 this.gen_random(ptr, len)?;
1160 this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
1161 }
1162 "arc4random_buf" => {
1163 this.check_target_os(&[Os::FreeBsd, Os::Illumos, Os::Solaris], link_name)?;
1166 let [ptr, len] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1167 let ptr = this.read_pointer(ptr)?;
1168 let len = this.read_target_usize(len)?;
1169 this.gen_random(ptr, len)?;
1170 }
1171 "_Unwind_RaiseException" => {
1172 this.check_target_os(
1186 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android, Os::MacOs],
1187 link_name,
1188 )?;
1189 let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1191 this.handle_miri_start_unwind(payload)?;
1192 return interp_ok(EmulateItemResult::NeedsUnwind);
1193 }
1194 "getuid" | "geteuid" => {
1195 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1196 this.write_int(UID, dest)?;
1198 }
1199
1200 "pthread_attr_getguardsize" if this.frame_in_std() => {
1203 let [_attr, guard_size] =
1204 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1205 let guard_size_layout = this.machine.layouts.usize;
1206 let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
1207 this.write_scalar(
1208 Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
1209 &guard_size,
1210 )?;
1211
1212 this.write_null(dest)?;
1214 }
1215
1216 "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
1217 let [_] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1218 this.write_null(dest)?;
1219 }
1220 "pthread_attr_setstacksize" if this.frame_in_std() => {
1221 let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1222 this.write_null(dest)?;
1223 }
1224
1225 "pthread_attr_getstack" if this.frame_in_std() => {
1226 let [attr_place, addr_place, size_place] =
1229 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1230 let _attr_place =
1231 this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
1232 let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?;
1233 let size_place = this.deref_pointer_as(size_place, this.machine.layouts.usize)?;
1234
1235 this.write_scalar(
1236 Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
1237 &addr_place,
1238 )?;
1239 this.write_scalar(
1240 Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
1241 &size_place,
1242 )?;
1243
1244 this.write_null(dest)?;
1246 }
1247
1248 "signal" | "sigaltstack" if this.frame_in_std() => {
1249 let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1250 this.write_null(dest)?;
1251 }
1252 "sigaction" | "mprotect" if this.frame_in_std() => {
1253 let [_, _, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1254 this.write_null(dest)?;
1255 }
1256
1257 "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
1258 let [uid, pwd, buf, buflen, result] =
1260 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1261 this.check_no_isolation("`getpwuid_r`")?;
1262
1263 let uid = this.read_scalar(uid)?.to_u32()?;
1264 let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?;
1265 let buf = this.read_pointer(buf)?;
1266 let buflen = this.read_target_usize(buflen)?;
1267 let result = this.deref_pointer_as(result, this.machine.layouts.mut_raw_ptr)?;
1268
1269 if uid != UID {
1271 throw_unsup_format!("`getpwuid_r` on other users is not supported");
1272 }
1273
1274 this.write_uninit(&pwd)?;
1277
1278 #[allow(deprecated)]
1280 let home_dir = std::env::home_dir().unwrap();
1281 let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
1282 let pw_dir = this.project_field_named(&pwd, "pw_dir")?;
1283 this.write_pointer(buf, &pw_dir)?;
1284
1285 if written {
1286 this.write_pointer(pwd.ptr(), &result)?;
1287 this.write_null(dest)?;
1288 } else {
1289 this.write_null(&result)?;
1290 this.write_scalar(this.eval_libc("ERANGE"), dest)?;
1291 }
1292 }
1293
1294 _ => {
1296 let target_os = &this.tcx.sess.target.os;
1297 return match target_os {
1298 Os::Android =>
1299 android::EvalContextExt::emulate_foreign_item_inner(
1300 this, link_name, abi, args, dest,
1301 ),
1302 Os::FreeBsd =>
1303 freebsd::EvalContextExt::emulate_foreign_item_inner(
1304 this, link_name, abi, args, dest,
1305 ),
1306 Os::Linux =>
1307 linux::EvalContextExt::emulate_foreign_item_inner(
1308 this, link_name, abi, args, dest,
1309 ),
1310 Os::MacOs =>
1311 macos::EvalContextExt::emulate_foreign_item_inner(
1312 this, link_name, abi, args, dest,
1313 ),
1314 Os::Solaris | Os::Illumos =>
1315 solarish::EvalContextExt::emulate_foreign_item_inner(
1316 this, link_name, abi, args, dest,
1317 ),
1318 _ => interp_ok(EmulateItemResult::NotSupported),
1319 };
1320 }
1321 };
1322
1323 interp_ok(EmulateItemResult::NeedsReturn)
1324 }
1325}