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
311 "open" => {
313 let ([path_raw, flag], varargs) =
316 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
317 let result = this.open(path_raw, flag, varargs)?;
318 this.write_scalar(result, dest)?;
319 }
320 "unlink" => {
321 let [path] = this.check_shim_sig(
323 shim_sig!(extern "C" fn(*const _) -> i32),
324 link_name,
325 abi,
326 args,
327 )?;
328 let result = this.unlink(path)?;
329 this.write_scalar(result, dest)?;
330 }
331 "symlink" => {
332 let [target, linkpath] = this.check_shim_sig(
334 shim_sig!(extern "C" fn(*const _, *const _) -> i32),
335 link_name,
336 abi,
337 args,
338 )?;
339 let result = this.symlink(target, linkpath)?;
340 this.write_scalar(result, dest)?;
341 }
342 "fstat" => {
343 let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
344 let result = this.fstat(fd, buf)?;
345 this.write_scalar(result, dest)?;
346 }
347 "rename" => {
348 let [oldpath, newpath] = this.check_shim_sig(
350 shim_sig!(extern "C" fn(*const _, *const _) -> i32),
351 link_name,
352 abi,
353 args,
354 )?;
355 let result = this.rename(oldpath, newpath)?;
356 this.write_scalar(result, dest)?;
357 }
358 "mkdir" => {
359 let [path, mode] = this.check_shim_sig(
361 shim_sig!(extern "C" fn(*const _, libc::mode_t) -> i32),
362 link_name,
363 abi,
364 args,
365 )?;
366 let result = this.mkdir(path, mode)?;
367 this.write_scalar(result, dest)?;
368 }
369 "rmdir" => {
370 let [path] = this.check_shim_sig(
372 shim_sig!(extern "C" fn(*const _) -> i32),
373 link_name,
374 abi,
375 args,
376 )?;
377 let result = this.rmdir(path)?;
378 this.write_scalar(result, dest)?;
379 }
380 "opendir" => {
381 let [name] = this.check_shim_sig(
382 shim_sig!(extern "C" fn(*const _) -> *mut _),
383 link_name,
384 abi,
385 args,
386 )?;
387 let result = this.opendir(name)?;
388 this.write_scalar(result, dest)?;
389 }
390 "closedir" => {
391 let [dirp] = this.check_shim_sig(
392 shim_sig!(extern "C" fn(*mut _) -> i32),
393 link_name,
394 abi,
395 args,
396 )?;
397 let result = this.closedir(dirp)?;
398 this.write_scalar(result, dest)?;
399 }
400 "readdir" => {
401 let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
402 this.readdir(dirp, dest)?;
403 }
404 "lseek" => {
405 let [fd, offset, whence] = this.check_shim_sig(
407 shim_sig!(extern "C" fn(i32, libc::off_t, i32) -> libc::off_t),
408 link_name,
409 abi,
410 args,
411 )?;
412 let fd = this.read_scalar(fd)?.to_i32()?;
413 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
414 let whence = this.read_scalar(whence)?.to_i32()?;
415 this.lseek(fd, offset, whence, dest)?;
416 }
417 "ftruncate" => {
418 let [fd, length] = this.check_shim_sig(
419 shim_sig!(extern "C" fn(i32, libc::off_t) -> i32),
420 link_name,
421 abi,
422 args,
423 )?;
424 let fd = this.read_scalar(fd)?.to_i32()?;
425 let length = this.read_scalar(length)?.to_int(length.layout.size)?;
426 let result = this.ftruncate64(fd, length)?;
427 this.write_scalar(result, dest)?;
428 }
429 "fsync" => {
430 let [fd] = this.check_shim_sig(
432 shim_sig!(extern "C" fn(i32) -> i32),
433 link_name,
434 abi,
435 args,
436 )?;
437 let result = this.fsync(fd)?;
438 this.write_scalar(result, dest)?;
439 }
440 "fdatasync" => {
441 let [fd] = this.check_shim_sig(
443 shim_sig!(extern "C" fn(i32) -> i32),
444 link_name,
445 abi,
446 args,
447 )?;
448 let result = this.fdatasync(fd)?;
449 this.write_scalar(result, dest)?;
450 }
451 "readlink" => {
452 let [pathname, buf, bufsize] = this.check_shim_sig(
453 shim_sig!(extern "C" fn(*const _, *mut _, usize) -> isize),
454 link_name,
455 abi,
456 args,
457 )?;
458 let result = this.readlink(pathname, buf, bufsize)?;
459 this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
460 }
461 "posix_fadvise" => {
462 let [fd, offset, len, advice] = this.check_shim_sig(
463 shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t, i32) -> i32),
464 link_name,
465 abi,
466 args,
467 )?;
468 this.read_scalar(fd)?.to_i32()?;
469 this.read_scalar(offset)?.to_int(offset.layout.size)?;
470 this.read_scalar(len)?.to_int(len.layout.size)?;
471 this.read_scalar(advice)?.to_i32()?;
472 this.write_null(dest)?;
474 }
475
476 "posix_fallocate" => {
477 this.check_target_os(
479 &[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos, Os::Android],
480 link_name,
481 )?;
482 let [fd, offset, len] = this.check_shim_sig(
483 shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t) -> i32),
484 link_name,
485 abi,
486 args,
487 )?;
488
489 let fd = this.read_scalar(fd)?.to_i32()?;
490 let offset =
492 i64::try_from(this.read_scalar(offset)?.to_int(offset.layout.size)?).unwrap();
493 let len = i64::try_from(this.read_scalar(len)?.to_int(len.layout.size)?).unwrap();
494
495 let result = this.posix_fallocate(fd, offset, len)?;
496 this.write_scalar(result, dest)?;
497 }
498
499 "realpath" => {
500 let [path, resolved_path] = this.check_shim_sig(
501 shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
502 link_name,
503 abi,
504 args,
505 )?;
506 let result = this.realpath(path, resolved_path)?;
507 this.write_scalar(result, dest)?;
508 }
509 "mkstemp" => {
510 let [template] = this.check_shim_sig(
511 shim_sig!(extern "C" fn(*mut _) -> i32),
512 link_name,
513 abi,
514 args,
515 )?;
516 let result = this.mkstemp(template)?;
517 this.write_scalar(result, dest)?;
518 }
519
520 "socketpair" => {
522 let [domain, type_, protocol, sv] = this.check_shim_sig(
523 shim_sig!(extern "C" fn(i32, i32, i32, *mut _) -> i32),
524 link_name,
525 abi,
526 args,
527 )?;
528 let result = this.socketpair(domain, type_, protocol, sv)?;
529 this.write_scalar(result, dest)?;
530 }
531 "pipe" => {
532 let [pipefd] = this.check_shim_sig(
533 shim_sig!(extern "C" fn(*mut _) -> i32),
534 link_name,
535 abi,
536 args,
537 )?;
538 let result = this.pipe2(pipefd, None)?;
539 this.write_scalar(result, dest)?;
540 }
541 "pipe2" => {
542 this.check_target_os(
544 &[Os::Linux, Os::Android, Os::FreeBsd, Os::Solaris, Os::Illumos],
545 link_name,
546 )?;
547 let [pipefd, flags] = this.check_shim_sig(
548 shim_sig!(extern "C" fn(*mut _, i32) -> i32),
549 link_name,
550 abi,
551 args,
552 )?;
553 let result = this.pipe2(pipefd, Some(flags))?;
554 this.write_scalar(result, dest)?;
555 }
556
557 "socket" => {
559 let [domain, type_, protocol] = this.check_shim_sig(
560 shim_sig!(extern "C" fn(i32, i32, i32) -> i32),
561 link_name,
562 abi,
563 args,
564 )?;
565 let result = this.socket(domain, type_, protocol)?;
566 this.write_scalar(result, dest)?;
567 }
568 "bind" => {
569 let [socket, address, address_len] = this.check_shim_sig(
570 shim_sig!(extern "C" fn(i32, *const _, libc::socklen_t) -> i32),
571 link_name,
572 abi,
573 args,
574 )?;
575 let result = this.bind(socket, address, address_len)?;
576 this.write_scalar(result, dest)?;
577 }
578 "listen" => {
579 let [socket, backlog] = this.check_shim_sig(
580 shim_sig!(extern "C" fn(i32, i32) -> i32),
581 link_name,
582 abi,
583 args,
584 )?;
585 let result = this.listen(socket, backlog)?;
586 this.write_scalar(result, dest)?;
587 }
588 "accept" => {
589 let [socket, address, address_len] = this.check_shim_sig(
590 shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32),
591 link_name,
592 abi,
593 args,
594 )?;
595 this.accept4(socket, address, address_len, None, dest)?;
596 }
597 "accept4" => {
598 let [socket, address, address_len, flags] = this.check_shim_sig(
599 shim_sig!(extern "C" fn(i32, *mut _, *mut _, i32) -> i32),
600 link_name,
601 abi,
602 args,
603 )?;
604 this.accept4(socket, address, address_len, Some(flags), dest)?;
605 }
606 "connect" => {
607 let [socket, address, address_len] = this.check_shim_sig(
608 shim_sig!(extern "C" fn(i32, *const _, libc::socklen_t) -> i32),
609 link_name,
610 abi,
611 args,
612 )?;
613 this.connect(socket, address, address_len, dest)?;
614 }
615 "send" => {
616 let [socket, buffer, length, flags] = this.check_shim_sig(
617 shim_sig!(extern "C" fn(i32, *const _, libc::size_t, i32) -> libc::ssize_t),
618 link_name,
619 abi,
620 args,
621 )?;
622 this.send(socket, buffer, length, flags, dest)?;
623 }
624 "recv" => {
625 let [socket, buffer, length, flags] = this.check_shim_sig(
626 shim_sig!(extern "C" fn(i32, *mut _, libc::size_t, i32) -> libc::ssize_t),
627 link_name,
628 abi,
629 args,
630 )?;
631 this.recv(socket, buffer, length, flags, dest)?;
632 }
633 "setsockopt" => {
634 let [socket, level, option_name, option_value, option_len] = this.check_shim_sig(
635 shim_sig!(extern "C" fn(i32, i32, i32, *const _, libc::socklen_t) -> i32),
636 link_name,
637 abi,
638 args,
639 )?;
640 let result =
641 this.setsockopt(socket, level, option_name, option_value, option_len)?;
642 this.write_scalar(result, dest)?;
643 }
644 "getsockname" => {
645 let [socket, address, address_len] = this.check_shim_sig(
646 shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32),
647 link_name,
648 abi,
649 args,
650 )?;
651 let result = this.getsockname(socket, address, address_len)?;
652 this.write_scalar(result, dest)?;
653 }
654 "getpeername" => {
655 let [socket, address, address_len] = this.check_shim_sig(
656 shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32),
657 link_name,
658 abi,
659 args,
660 )?;
661 let result = this.getpeername(socket, address, address_len)?;
662 this.write_scalar(result, dest)?;
663 }
664
665 "gettimeofday" => {
667 let [tv, tz] = this.check_shim_sig(
668 shim_sig!(extern "C" fn(*mut _, *mut _) -> i32),
669 link_name,
670 abi,
671 args,
672 )?;
673 let result = this.gettimeofday(tv, tz)?;
674 this.write_scalar(result, dest)?;
675 }
676 "localtime_r" => {
677 let [timep, result_op] = this.check_shim_sig(
678 shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
679 link_name,
680 abi,
681 args,
682 )?;
683 let result = this.localtime_r(timep, result_op)?;
684 this.write_pointer(result, dest)?;
685 }
686 "clock_gettime" => {
687 let [clk_id, tp] = this.check_shim_sig(
688 shim_sig!(extern "C" fn(libc::clockid_t, *mut _) -> i32),
689 link_name,
690 abi,
691 args,
692 )?;
693 this.clock_gettime(clk_id, tp, dest)?;
694 }
695
696 "posix_memalign" => {
698 let [memptr, align, size] =
699 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
700 let result = this.posix_memalign(memptr, align, size)?;
701 this.write_scalar(result, dest)?;
702 }
703
704 "mmap" => {
705 let [addr, length, prot, flags, fd, offset] =
706 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
707 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
708 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
709 this.write_scalar(ptr, dest)?;
710 }
711 "munmap" => {
712 let [addr, length] =
713 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
714 let result = this.munmap(addr, length)?;
715 this.write_scalar(result, dest)?;
716 }
717
718 "reallocarray" => {
719 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
721 let [ptr, nmemb, size] =
722 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
723 let ptr = this.read_pointer(ptr)?;
724 let nmemb = this.read_target_usize(nmemb)?;
725 let size = this.read_target_usize(size)?;
726 match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
732 None => {
733 this.set_last_error(LibcError("ENOMEM"))?;
734 this.write_null(dest)?;
735 }
736 Some(len) => {
737 let res = this.realloc(ptr, len.bytes())?;
738 this.write_pointer(res, dest)?;
739 }
740 }
741 }
742 "aligned_alloc" => {
743 let [align, size] =
746 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
747 let res = this.aligned_alloc(align, size)?;
748 this.write_pointer(res, dest)?;
749 }
750
751 "dlsym" => {
753 let [handle, symbol] =
754 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
755 this.read_target_usize(handle)?;
756 let symbol = this.read_pointer(symbol)?;
757 let name = this.read_c_str(symbol)?;
758 let Ok(name) = str::from_utf8(name) else {
759 throw_unsup_format!("dlsym: non UTF-8 symbol name not supported")
760 };
761 if is_dyn_sym(name, &this.tcx.sess.target.os) {
762 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
763 this.write_pointer(ptr, dest)?;
764 } else if let Some(&ptr) = this.machine.extern_statics.get(&Symbol::intern(name)) {
765 this.write_pointer(ptr, dest)?;
766 } else {
767 this.write_null(dest)?;
768 }
769 }
770
771 "pthread_key_create" => {
773 let [key, dtor] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
774 let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
775 let dtor = this.read_pointer(dtor)?;
776
777 let dtor = if !this.ptr_is_null(dtor)? {
779 Some((
780 this.get_ptr_fn(dtor)?.as_instance()?,
781 this.machine.current_user_relevant_span(),
782 ))
783 } else {
784 None
785 };
786
787 let key_type = key.layout.ty
790 .builtin_deref(true)
791 .ok_or_else(|| err_ub_format!(
792 "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
793 ))?;
794 let key_layout = this.layout_of(key_type)?;
795
796 let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
798 this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place)?;
799
800 this.write_null(dest)?;
802 }
803 "pthread_key_delete" => {
804 let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
806 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
807 this.machine.tls.delete_tls_key(key)?;
808 this.write_null(dest)?;
810 }
811 "pthread_getspecific" => {
812 let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
814 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
815 let active_thread = this.active_thread();
816 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
817 this.write_scalar(ptr, dest)?;
818 }
819 "pthread_setspecific" => {
820 let [key, new_ptr] =
822 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
823 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
824 let active_thread = this.active_thread();
825 let new_data = this.read_scalar(new_ptr)?;
826 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
827
828 this.write_null(dest)?;
830 }
831
832 "pthread_mutexattr_init" => {
834 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
835 this.pthread_mutexattr_init(attr)?;
836 this.write_null(dest)?;
837 }
838 "pthread_mutexattr_settype" => {
839 let [attr, kind] =
840 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
841 let result = this.pthread_mutexattr_settype(attr, kind)?;
842 this.write_scalar(result, dest)?;
843 }
844 "pthread_mutexattr_destroy" => {
845 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
846 this.pthread_mutexattr_destroy(attr)?;
847 this.write_null(dest)?;
848 }
849 "pthread_mutex_init" => {
850 let [mutex, attr] =
851 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
852 this.pthread_mutex_init(mutex, attr)?;
853 this.write_null(dest)?;
854 }
855 "pthread_mutex_lock" => {
856 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
857 this.pthread_mutex_lock(mutex, dest)?;
858 }
859 "pthread_mutex_trylock" => {
860 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
861 let result = this.pthread_mutex_trylock(mutex)?;
862 this.write_scalar(result, dest)?;
863 }
864 "pthread_mutex_unlock" => {
865 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
866 let result = this.pthread_mutex_unlock(mutex)?;
867 this.write_scalar(result, dest)?;
868 }
869 "pthread_mutex_destroy" => {
870 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
871 this.pthread_mutex_destroy(mutex)?;
872 this.write_int(0, dest)?;
873 }
874 "pthread_rwlock_rdlock" => {
875 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
876 this.pthread_rwlock_rdlock(rwlock, dest)?;
877 }
878 "pthread_rwlock_tryrdlock" => {
879 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
880 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
881 this.write_scalar(result, dest)?;
882 }
883 "pthread_rwlock_wrlock" => {
884 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
885 this.pthread_rwlock_wrlock(rwlock, dest)?;
886 }
887 "pthread_rwlock_trywrlock" => {
888 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
889 let result = this.pthread_rwlock_trywrlock(rwlock)?;
890 this.write_scalar(result, dest)?;
891 }
892 "pthread_rwlock_unlock" => {
893 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
894 this.pthread_rwlock_unlock(rwlock)?;
895 this.write_null(dest)?;
896 }
897 "pthread_rwlock_destroy" => {
898 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
899 this.pthread_rwlock_destroy(rwlock)?;
900 this.write_null(dest)?;
901 }
902 "pthread_condattr_init" => {
903 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
904 this.pthread_condattr_init(attr)?;
905 this.write_null(dest)?;
906 }
907 "pthread_condattr_setclock" => {
908 let [attr, clock_id] =
909 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
910 let result = this.pthread_condattr_setclock(attr, clock_id)?;
911 this.write_scalar(result, dest)?;
912 }
913 "pthread_condattr_getclock" => {
914 let [attr, clock_id] =
915 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
916 this.pthread_condattr_getclock(attr, clock_id)?;
917 this.write_null(dest)?;
918 }
919 "pthread_condattr_destroy" => {
920 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
921 this.pthread_condattr_destroy(attr)?;
922 this.write_null(dest)?;
923 }
924 "pthread_cond_init" => {
925 let [cond, attr] =
926 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
927 this.pthread_cond_init(cond, attr)?;
928 this.write_null(dest)?;
929 }
930 "pthread_cond_signal" => {
931 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
932 this.pthread_cond_signal(cond)?;
933 this.write_null(dest)?;
934 }
935 "pthread_cond_broadcast" => {
936 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
937 this.pthread_cond_broadcast(cond)?;
938 this.write_null(dest)?;
939 }
940 "pthread_cond_wait" => {
941 let [cond, mutex] =
942 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
943 this.pthread_cond_wait(cond, mutex, dest)?;
944 }
945 "pthread_cond_timedwait" => {
946 let [cond, mutex, abstime] =
947 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
948 this.pthread_cond_timedwait(
949 cond, mutex, abstime, dest, false,
950 )?;
951 }
952 "pthread_cond_destroy" => {
953 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
954 this.pthread_cond_destroy(cond)?;
955 this.write_null(dest)?;
956 }
957
958 "pthread_create" => {
960 let [thread, attr, start, arg] =
961 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
962 this.pthread_create(thread, attr, start, arg)?;
963 this.write_null(dest)?;
964 }
965 "pthread_join" => {
966 let [thread, retval] =
967 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
968 this.pthread_join(thread, retval, dest)?;
969 }
970 "pthread_detach" => {
971 let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
972 let res = this.pthread_detach(thread)?;
973 this.write_scalar(res, dest)?;
974 }
975 "pthread_self" => {
976 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
977 let res = this.pthread_self()?;
978 this.write_scalar(res, dest)?;
979 }
980 "sched_yield" => {
981 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
983 this.sched_yield()?;
984 this.write_null(dest)?;
985 }
986 "nanosleep" => {
987 let [duration, rem] =
988 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
989 let result = this.nanosleep(duration, rem)?;
990 this.write_scalar(result, dest)?;
991 }
992 "clock_nanosleep" => {
993 this.check_target_os(
995 &[Os::FreeBsd, Os::Linux, Os::Android, Os::Solaris, Os::Illumos],
996 link_name,
997 )?;
998 let [clock_id, flags, req, rem] =
999 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1000 let result = this.clock_nanosleep(clock_id, flags, req, rem)?;
1001 this.write_scalar(result, dest)?;
1002 }
1003 "sched_getaffinity" => {
1004 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
1006 let [pid, cpusetsize, mask] =
1007 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1008 let pid = this.read_scalar(pid)?.to_u32()?;
1009 let cpusetsize = this.read_target_usize(cpusetsize)?;
1010 let mask = this.read_pointer(mask)?;
1011
1012 let thread_id = match pid {
1014 0 => this.active_thread(),
1015 _ =>
1016 throw_unsup_format!(
1017 "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"
1018 ),
1019 };
1020
1021 let chunk_size = CpuAffinityMask::chunk_size(this);
1023
1024 if this.ptr_is_null(mask)? {
1025 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
1026 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
1027 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
1029 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
1030 let cpuset = cpuset.clone();
1031 let byte_count =
1033 Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
1034 this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
1035 this.write_null(dest)?;
1036 } else {
1037 this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
1039 }
1040 }
1041 "sched_setaffinity" => {
1042 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
1044 let [pid, cpusetsize, mask] =
1045 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1046 let pid = this.read_scalar(pid)?.to_u32()?;
1047 let cpusetsize = this.read_target_usize(cpusetsize)?;
1048 let mask = this.read_pointer(mask)?;
1049
1050 let thread_id = match pid {
1052 0 => this.active_thread(),
1053 _ =>
1054 throw_unsup_format!(
1055 "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"
1056 ),
1057 };
1058
1059 if this.ptr_is_null(mask)? {
1060 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
1061 } else {
1062 let bits_slice =
1066 this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
1067 let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
1069 std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
1070 match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
1071 Some(cpuset) => {
1072 this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
1073 this.write_null(dest)?;
1074 }
1075 None => {
1076 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
1078 }
1079 }
1080 }
1081 }
1082
1083 "isatty" => {
1085 let [fd] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1086 let result = this.isatty(fd)?;
1087 this.write_scalar(result, dest)?;
1088 }
1089 "pthread_atfork" => {
1090 let [prepare, parent, child] =
1092 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1093 this.read_pointer(prepare)?;
1094 this.read_pointer(parent)?;
1095 this.read_pointer(child)?;
1096 this.write_null(dest)?;
1098 }
1099 "getentropy" => {
1100 this.check_target_os(
1103 &[Os::Linux, Os::MacOs, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
1104 link_name,
1105 )?;
1106 let [buf, bufsize] =
1107 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1108 let buf = this.read_pointer(buf)?;
1109 let bufsize = this.read_target_usize(bufsize)?;
1110
1111 if bufsize > 256 {
1117 this.set_last_error_and_return(LibcError("EIO"), dest)?;
1118 } else {
1119 this.gen_random(buf, bufsize)?;
1120 this.write_null(dest)?;
1121 }
1122 }
1123
1124 "strerror_r" => {
1125 let [errnum, buf, buflen] =
1126 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1127 let result = this.strerror_r(errnum, buf, buflen)?;
1128 this.write_scalar(result, dest)?;
1129 }
1130
1131 "getrandom" => {
1132 this.check_target_os(
1135 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
1136 link_name,
1137 )?;
1138 let [ptr, len, flags] =
1139 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1140 let ptr = this.read_pointer(ptr)?;
1141 let len = this.read_target_usize(len)?;
1142 let _flags = this.read_scalar(flags)?.to_i32()?;
1143 this.gen_random(ptr, len)?;
1145 this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
1146 }
1147 "arc4random_buf" => {
1148 this.check_target_os(&[Os::FreeBsd, Os::Illumos, Os::Solaris], link_name)?;
1151 let [ptr, len] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1152 let ptr = this.read_pointer(ptr)?;
1153 let len = this.read_target_usize(len)?;
1154 this.gen_random(ptr, len)?;
1155 }
1156 "_Unwind_RaiseException" => {
1157 this.check_target_os(
1171 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android, Os::MacOs],
1172 link_name,
1173 )?;
1174 let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1176 this.handle_miri_start_unwind(payload)?;
1177 return interp_ok(EmulateItemResult::NeedsUnwind);
1178 }
1179 "getuid" | "geteuid" => {
1180 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1181 this.write_int(UID, dest)?;
1183 }
1184
1185 "pthread_attr_getguardsize" if this.frame_in_std() => {
1188 let [_attr, guard_size] =
1189 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1190 let guard_size_layout = this.machine.layouts.usize;
1191 let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
1192 this.write_scalar(
1193 Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
1194 &guard_size,
1195 )?;
1196
1197 this.write_null(dest)?;
1199 }
1200
1201 "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
1202 let [_] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1203 this.write_null(dest)?;
1204 }
1205 "pthread_attr_setstacksize" if this.frame_in_std() => {
1206 let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1207 this.write_null(dest)?;
1208 }
1209
1210 "pthread_attr_getstack" if this.frame_in_std() => {
1211 let [attr_place, addr_place, size_place] =
1214 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1215 let _attr_place =
1216 this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
1217 let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?;
1218 let size_place = this.deref_pointer_as(size_place, this.machine.layouts.usize)?;
1219
1220 this.write_scalar(
1221 Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
1222 &addr_place,
1223 )?;
1224 this.write_scalar(
1225 Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
1226 &size_place,
1227 )?;
1228
1229 this.write_null(dest)?;
1231 }
1232
1233 "signal" | "sigaltstack" if this.frame_in_std() => {
1234 let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1235 this.write_null(dest)?;
1236 }
1237 "sigaction" | "mprotect" if this.frame_in_std() => {
1238 let [_, _, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1239 this.write_null(dest)?;
1240 }
1241
1242 "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
1243 let [uid, pwd, buf, buflen, result] =
1245 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1246 this.check_no_isolation("`getpwuid_r`")?;
1247
1248 let uid = this.read_scalar(uid)?.to_u32()?;
1249 let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?;
1250 let buf = this.read_pointer(buf)?;
1251 let buflen = this.read_target_usize(buflen)?;
1252 let result = this.deref_pointer_as(result, this.machine.layouts.mut_raw_ptr)?;
1253
1254 if uid != UID {
1256 throw_unsup_format!("`getpwuid_r` on other users is not supported");
1257 }
1258
1259 this.write_uninit(&pwd)?;
1262
1263 #[allow(deprecated)]
1265 let home_dir = std::env::home_dir().unwrap();
1266 let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
1267 let pw_dir = this.project_field_named(&pwd, "pw_dir")?;
1268 this.write_pointer(buf, &pw_dir)?;
1269
1270 if written {
1271 this.write_pointer(pwd.ptr(), &result)?;
1272 this.write_null(dest)?;
1273 } else {
1274 this.write_null(&result)?;
1275 this.write_scalar(this.eval_libc("ERANGE"), dest)?;
1276 }
1277 }
1278
1279 _ => {
1281 let target_os = &this.tcx.sess.target.os;
1282 return match target_os {
1283 Os::Android =>
1284 android::EvalContextExt::emulate_foreign_item_inner(
1285 this, link_name, abi, args, dest,
1286 ),
1287 Os::FreeBsd =>
1288 freebsd::EvalContextExt::emulate_foreign_item_inner(
1289 this, link_name, abi, args, dest,
1290 ),
1291 Os::Linux =>
1292 linux::EvalContextExt::emulate_foreign_item_inner(
1293 this, link_name, abi, args, dest,
1294 ),
1295 Os::MacOs =>
1296 macos::EvalContextExt::emulate_foreign_item_inner(
1297 this, link_name, abi, args, dest,
1298 ),
1299 Os::Solaris | Os::Illumos =>
1300 solarish::EvalContextExt::emulate_foreign_item_inner(
1301 this, link_name, abi, args, dest,
1302 ),
1303 _ => interp_ok(EmulateItemResult::NotSupported),
1304 };
1305 }
1306 };
1307
1308 interp_ok(EmulateItemResult::NeedsReturn)
1309 }
1310}