Skip to main content

miri/shims/unix/
foreign_items.rs

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        // Used for tests.
23        "isatty" => true,
24        // `signal` is set up as a weak symbol in `init_extern_statics` (on Android) so we might as
25        // well allow it in `dlsym`.
26        "signal" => true,
27        // needed at least on macOS to avoid file-based fallback in getrandom
28        "getentropy" | "getrandom" => true,
29        // Give specific OSes a chance to allow their symbols.
30        _ =>
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    // Querying system information
45    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        // FIXME: Which of these are POSIX, and which are GNU/Linux?
50        // At least the names seem to all also exist on macOS.
51        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            // 512 seems to be a reasonable default. The value is not critical, in
61            // the sense that getpwuid_r takes and checks the buffer length.
62            ("_SC_GETPW_R_SIZE_MAX", |this| Scalar::from_int(512, this.pointer_size())),
63            // Miri doesn't have a fixed limit on FDs, but we may be limited in terms of how
64            // many *host* FDs we can open. Just use some arbitrary, pretty big value;
65            // this can be adjusted if it causes problems.
66            // The spec imposes a minimum of `_POSIX_OPEN_MAX` (20).
67            ("_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        // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
112        match link_name.as_str() {
113            // Environment related shims
114            "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                // FIXME: This does not have a direct test (#3179).
147                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                // FIXME: This does not have a direct test (#3179).
158                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                // Not all Unixes have the `uname` symbol, e.g. FreeBSD does not.
179                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            // File descriptors
203            "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                // FIXME: This does not have a direct test (#3179).
230                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                // FIXME: This does not have a direct test (#3179).
244                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                // Currently this function does not exist on all Unixes, e.g. on Solaris.
298                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            // File and file system access
318            "open" => {
319                // `open` is variadic, the third argument is only present when the second argument
320                // has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
321                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                // FIXME: This does not have a direct test (#3179).
328                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                // FIXME: This does not have a direct test (#3179).
339                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                // FIXME: This does not have a direct test (#3179).
365                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                // FIXME: This does not have a direct test (#3179).
376                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                // FIXME: This does not have a direct test (#3179).
387                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                // FIXME: This does not have a direct test (#3179).
422                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                // FIXME: This does not have a direct test (#3179).
447                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                // FIXME: This does not have a direct test (#3179).
458                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                // fadvise is only informational, we can ignore it.
489                this.write_null(dest)?;
490            }
491
492            "posix_fallocate" => {
493                // posix_fallocate is not supported by macos.
494                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                // We don't support platforms which have libc::off_t bigger than 64 bits.
507                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            // Unnamed sockets and pipes
537            "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, /*flags*/ None)?;
555                this.write_scalar(result, dest)?;
556            }
557            "pipe2" => {
558                // Currently this function does not exist on all Unixes, e.g. on macOS.
559                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            // Network sockets
574            "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, /* flags */ 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            // Time
681            "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            // Allocation
712            "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                // Currently this function does not exist on all Unixes, e.g. on macOS.
735                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                // reallocarray checks a possible overflow and returns ENOMEM
742                // if that happens.
743                //
744                // Linux: https://www.unix.com/man-page/linux/3/reallocarray/
745                // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray
746                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                // This is a C11 function, we assume all Unixes have it.
759                // (MSVC explicitly does not support this.)
760                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            // Dynamic symbol loading
767            "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            // Thread-local storage
787            "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                // Extract the function type out of the signature (that seems easier than constructing it ourselves).
793                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                // Figure out how large a pthread TLS key actually is.
803                // To this end, deref the argument type. This is `libc::pthread_key_t`.
804                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                // Create key and write it into the memory where `key_ptr` wants it.
812                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                // Return success (`0`).
816                this.write_null(dest)?;
817            }
818            "pthread_key_delete" => {
819                // FIXME: This does not have a direct test (#3179).
820                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                // Return success (0)
824                this.write_null(dest)?;
825            }
826            "pthread_getspecific" => {
827                // FIXME: This does not have a direct test (#3179).
828                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                // FIXME: This does not have a direct test (#3179).
836                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                // Return success (`0`).
844                this.write_null(dest)?;
845            }
846
847            // Synchronization primitives
848            "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, /* macos_relative_np */ 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            // Threading
974            "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                // FIXME: This does not have a direct test (#3179).
997                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                // Currently this function does not exist on all Unixes, e.g. on macOS.
1009                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                // Currently this function does not exist on all Unixes, e.g. on macOS.
1020                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                // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid
1028                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                // The mask is stored in chunks, and the size must be a whole number of chunks.
1037                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                    // we only copy whole chunks of size_of::<c_ulong>()
1043                    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                    // we only copy whole chunks of size_of::<c_ulong>()
1047                    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                    // The thread whose ID is pid could not be found
1053                    this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
1054                }
1055            }
1056            "sched_setaffinity" => {
1057                // Currently this function does not exist on all Unixes, e.g. on macOS.
1058                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                // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid
1066                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                    // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
1078                    // Any unspecified bytes are treated as zero here (none of the CPUs are configured).
1079                    // This is not exactly documented, so we assume that this is the behavior in practice.
1080                    let bits_slice =
1081                        this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
1082                    // This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES`
1083                    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                            // The intersection between the mask and the available CPUs was empty.
1092                            this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
1093                        }
1094                    }
1095                }
1096            }
1097
1098            // Miscellaneous
1099            "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                // FIXME: This does not have a direct test (#3179).
1106                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                // We do not support forking, so there is nothing to do here.
1112                this.write_null(dest)?;
1113            }
1114            "getentropy" => {
1115                // This function is non-standard but exists with the same signature and behavior on
1116                // Linux, macOS, FreeBSD and Solaris/Illumos.
1117                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                // getentropy sets errno to EIO when the buffer size exceeds 256 bytes.
1127                // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=getentropy&sektion=3&format=html
1128                // Linux: https://man7.org/linux/man-pages/man3/getentropy.3.html
1129                // macOS: https://keith.github.io/xcode-man-pages/getentropy.2.html
1130                // Solaris/Illumos: https://illumos.org/man/3C/getentropy
1131                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 function is non-standard but exists with the same signature and behavior on
1148                // Linux, FreeBSD and Solaris/Illumos.
1149                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                // We ignore the flags, just always use the same PRNG / host RNG.
1159                this.gen_random(ptr, len)?;
1160                this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
1161            }
1162            "arc4random_buf" => {
1163                // This function is non-standard but exists with the same signature and
1164                // same behavior (eg never fails) on FreeBSD and Solaris/Illumos.
1165                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 is not formally part of POSIX, but it is very wide-spread on POSIX systems.
1173                // It was originally specified as part of the Itanium C++ ABI:
1174                // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-throw.
1175                // On Linux it is
1176                // documented as part of the LSB:
1177                // https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/baselib--unwind-raiseexception.html
1178                // Basically every other UNIX uses the exact same api though. Arm also references
1179                // back to the Itanium C++ ABI for the definition of `_Unwind_RaiseException` for
1180                // arm64:
1181                // https://github.com/ARM-software/abi-aa/blob/main/cppabi64/cppabi64.rst#toc-entry-35
1182                // For arm32 they did something custom, but similar enough that the same
1183                // `_Unwind_RaiseException` impl in miri should work:
1184                // https://github.com/ARM-software/abi-aa/blob/main/ehabi32/ehabi32.rst
1185                this.check_target_os(
1186                    &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android, Os::MacOs],
1187                    link_name,
1188                )?;
1189                // This function looks and behaves exactly like miri_start_unwind.
1190                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                // For now, just pretend we always have this fixed UID.
1197                this.write_int(UID, dest)?;
1198            }
1199
1200            // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
1201            // These shims are enabled only when the caller is in the standard library.
1202            "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                // Return success (`0`).
1213                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                // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here.
1227                // Hence we can mostly ignore the input `attr_place`.
1228                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                // Return success (`0`).
1245                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                // getpwuid_r is the standard name, __posix_getpwuid_r is used on solarish
1259                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                // Must be for "us".
1270                if uid != UID {
1271                    throw_unsup_format!("`getpwuid_r` on other users is not supported");
1272                }
1273
1274                // Reset all fields to `uninit` to make sure nobody reads them.
1275                // (This is a std-only shim so we are okay with such hacks.)
1276                this.write_uninit(&pwd)?;
1277
1278                // We only set the home_dir field.
1279                #[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            // Platform-specific shims
1295            _ => {
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}