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                let [buf, size] = this.check_shim_sig(
147                    shim_sig!(extern "C" fn(*mut _, usize) -> *mut _),
148                    link_name,
149                    abi,
150                    args,
151                )?;
152                let result = this.getcwd(buf, size)?;
153                this.write_pointer(result, dest)?;
154            }
155            "chdir" => {
156                let [path] = this.check_shim_sig(
157                    shim_sig!(extern "C" fn(*const _) -> i32),
158                    link_name,
159                    abi,
160                    args,
161                )?;
162                let result = this.chdir(path)?;
163                this.write_scalar(result, dest)?;
164            }
165            "getpid" => {
166                let [] = this.check_shim_sig(
167                    shim_sig!(extern "C" fn() -> libc::pid_t),
168                    link_name,
169                    abi,
170                    args,
171                )?;
172                let result = this.getpid()?;
173                this.write_scalar(result, dest)?;
174            }
175            "sysconf" => {
176                let [val] = this.check_shim_sig(
177                    shim_sig!(extern "C" fn(i32) -> isize),
178                    link_name,
179                    abi,
180                    args,
181                )?;
182                let result = this.sysconf(val)?;
183                this.write_scalar(result, dest)?;
184            }
185            // File descriptors
186            "read" => {
187                let [fd, buf, count] = this.check_shim_sig(
188                    shim_sig!(extern "C" fn(i32, *mut _, usize) -> isize),
189                    link_name,
190                    abi,
191                    args,
192                )?;
193                let fd = this.read_scalar(fd)?.to_i32()?;
194                let buf = this.read_pointer(buf)?;
195                let count = this.read_target_usize(count)?;
196                this.read(fd, buf, count, None, dest)?;
197            }
198            "write" => {
199                let [fd, buf, n] = this.check_shim_sig(
200                    shim_sig!(extern "C" fn(i32, *const _, usize) -> isize),
201                    link_name,
202                    abi,
203                    args,
204                )?;
205                let fd = this.read_scalar(fd)?.to_i32()?;
206                let buf = this.read_pointer(buf)?;
207                let count = this.read_target_usize(n)?;
208                trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
209                this.write(fd, buf, count, None, dest)?;
210            }
211            "pread" => {
212                let [fd, buf, count, offset] = this.check_shim_sig(
213                    shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off_t) -> isize),
214                    link_name,
215                    abi,
216                    args,
217                )?;
218                let fd = this.read_scalar(fd)?.to_i32()?;
219                let buf = this.read_pointer(buf)?;
220                let count = this.read_target_usize(count)?;
221                let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
222                this.read(fd, buf, count, Some(offset), dest)?;
223            }
224            "pwrite" => {
225                let [fd, buf, n, offset] = this.check_shim_sig(
226                    shim_sig!(extern "C" fn(i32, *const _, usize, libc::off_t) -> isize),
227                    link_name,
228                    abi,
229                    args,
230                )?;
231                let fd = this.read_scalar(fd)?.to_i32()?;
232                let buf = this.read_pointer(buf)?;
233                let count = this.read_target_usize(n)?;
234                let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
235                trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
236                this.write(fd, buf, count, Some(offset), dest)?;
237            }
238            "pread64" => {
239                let [fd, buf, count, offset] = this.check_shim_sig(
240                    shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize),
241                    link_name,
242                    abi,
243                    args,
244                )?;
245                let fd = this.read_scalar(fd)?.to_i32()?;
246                let buf = this.read_pointer(buf)?;
247                let count = this.read_target_usize(count)?;
248                let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
249                this.read(fd, buf, count, Some(offset), dest)?;
250            }
251            "pwrite64" => {
252                let [fd, buf, n, offset] = this.check_shim_sig(
253                    shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize),
254                    link_name,
255                    abi,
256                    args,
257                )?;
258                let fd = this.read_scalar(fd)?.to_i32()?;
259                let buf = this.read_pointer(buf)?;
260                let count = this.read_target_usize(n)?;
261                let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
262                trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
263                this.write(fd, buf, count, Some(offset), dest)?;
264            }
265            "close" => {
266                let [fd] = this.check_shim_sig(
267                    shim_sig!(extern "C" fn(i32) -> i32),
268                    link_name,
269                    abi,
270                    args,
271                )?;
272                let result = this.close(fd)?;
273                this.write_scalar(result, dest)?;
274            }
275            "fcntl" => {
276                let ([fd_num, cmd], varargs) =
277                    this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
278                let result = this.fcntl(fd_num, cmd, varargs)?;
279                this.write_scalar(result, dest)?;
280            }
281            "dup" => {
282                let [old_fd] = this.check_shim_sig(
283                    shim_sig!(extern "C" fn(i32) -> i32),
284                    link_name,
285                    abi,
286                    args,
287                )?;
288                let old_fd = this.read_scalar(old_fd)?.to_i32()?;
289                let new_fd = this.dup(old_fd)?;
290                this.write_scalar(new_fd, dest)?;
291            }
292            "dup2" => {
293                let [old_fd, new_fd] = this.check_shim_sig(
294                    shim_sig!(extern "C" fn(i32, i32) -> i32),
295                    link_name,
296                    abi,
297                    args,
298                )?;
299                let old_fd = this.read_scalar(old_fd)?.to_i32()?;
300                let new_fd = this.read_scalar(new_fd)?.to_i32()?;
301                let result = this.dup2(old_fd, new_fd)?;
302                this.write_scalar(result, dest)?;
303            }
304            "flock" => {
305                // Currently this function does not exist on all Unixes, e.g. on Solaris.
306                this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::MacOs, Os::Illumos], link_name)?;
307                let [fd, op] = this.check_shim_sig(
308                    shim_sig!(extern "C" fn(i32, i32) -> i32),
309                    link_name,
310                    abi,
311                    args,
312                )?;
313                let fd = this.read_scalar(fd)?.to_i32()?;
314                let op = this.read_scalar(op)?.to_i32()?;
315                let result = this.flock(fd, op)?;
316                this.write_scalar(result, dest)?;
317            }
318
319            // File and file system access
320            "open" | "open64" => {
321                // `open` is variadic, the third argument is only present when the second argument
322                // has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
323                let ([path_raw, flag], varargs) =
324                    this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
325                let result = this.open(path_raw, flag, varargs)?;
326                this.write_scalar(result, dest)?;
327            }
328            "unlink" => {
329                let [path] = this.check_shim_sig(
330                    shim_sig!(extern "C" fn(*const _) -> i32),
331                    link_name,
332                    abi,
333                    args,
334                )?;
335                let result = this.unlink(path)?;
336                this.write_scalar(result, dest)?;
337            }
338            "symlink" => {
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            "rename" => {
349                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(
360                    shim_sig!(extern "C" fn(*const _, libc::mode_t) -> i32),
361                    link_name,
362                    abi,
363                    args,
364                )?;
365                let result = this.mkdir(path, mode)?;
366                this.write_scalar(result, dest)?;
367            }
368            "rmdir" => {
369                let [path] = this.check_shim_sig(
370                    shim_sig!(extern "C" fn(*const _) -> i32),
371                    link_name,
372                    abi,
373                    args,
374                )?;
375                let result = this.rmdir(path)?;
376                this.write_scalar(result, dest)?;
377            }
378            "opendir" => {
379                let [name] = this.check_shim_sig(
380                    shim_sig!(extern "C" fn(*const _) -> *mut _),
381                    link_name,
382                    abi,
383                    args,
384                )?;
385                let result = this.opendir(name)?;
386                this.write_scalar(result, dest)?;
387            }
388            "closedir" => {
389                let [dirp] = this.check_shim_sig(
390                    shim_sig!(extern "C" fn(*mut _) -> i32),
391                    link_name,
392                    abi,
393                    args,
394                )?;
395                let result = this.closedir(dirp)?;
396                this.write_scalar(result, dest)?;
397            }
398            "lseek64" => {
399                let [fd, offset, whence] = this.check_shim_sig(
400                    shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t),
401                    link_name,
402                    abi,
403                    args,
404                )?;
405                let fd = this.read_scalar(fd)?.to_i32()?;
406                let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
407                let whence = this.read_scalar(whence)?.to_i32()?;
408                this.lseek64(fd, offset, whence, dest)?;
409            }
410            "lseek" => {
411                let [fd, offset, whence] = this.check_shim_sig(
412                    shim_sig!(extern "C" fn(i32, libc::off_t, i32) -> libc::off_t),
413                    link_name,
414                    abi,
415                    args,
416                )?;
417                let fd = this.read_scalar(fd)?.to_i32()?;
418                let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
419                let whence = this.read_scalar(whence)?.to_i32()?;
420                this.lseek64(fd, offset, whence, dest)?;
421            }
422            "ftruncate64" => {
423                let [fd, length] = this.check_shim_sig(
424                    shim_sig!(extern "C" fn(i32, libc::off64_t) -> i32),
425                    link_name,
426                    abi,
427                    args,
428                )?;
429                let fd = this.read_scalar(fd)?.to_i32()?;
430                let length = this.read_scalar(length)?.to_int(length.layout.size)?;
431                let result = this.ftruncate64(fd, length)?;
432                this.write_scalar(result, dest)?;
433            }
434            "ftruncate" => {
435                let [fd, length] = this.check_shim_sig(
436                    shim_sig!(extern "C" fn(i32, libc::off_t) -> i32),
437                    link_name,
438                    abi,
439                    args,
440                )?;
441                let fd = this.read_scalar(fd)?.to_i32()?;
442                let length = this.read_scalar(length)?.to_int(length.layout.size)?;
443                let result = this.ftruncate64(fd, length)?;
444                this.write_scalar(result, dest)?;
445            }
446            "fsync" => {
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                let [fd] = this.check_shim_sig(
458                    shim_sig!(extern "C" fn(i32) -> i32),
459                    link_name,
460                    abi,
461                    args,
462                )?;
463                let result = this.fdatasync(fd)?;
464                this.write_scalar(result, dest)?;
465            }
466            "readlink" => {
467                let [pathname, buf, bufsize] = this.check_shim_sig(
468                    shim_sig!(extern "C" fn(*const _, *mut _, usize) -> isize),
469                    link_name,
470                    abi,
471                    args,
472                )?;
473                let result = this.readlink(pathname, buf, bufsize)?;
474                this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
475            }
476            "posix_fadvise" => {
477                let [fd, offset, len, advice] = this.check_shim_sig(
478                    shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t, i32) -> i32),
479                    link_name,
480                    abi,
481                    args,
482                )?;
483                this.read_scalar(fd)?.to_i32()?;
484                this.read_scalar(offset)?.to_int(offset.layout.size)?;
485                this.read_scalar(len)?.to_int(len.layout.size)?;
486                this.read_scalar(advice)?.to_i32()?;
487                // fadvise is only informational, we can ignore it.
488                this.write_null(dest)?;
489            }
490
491            "posix_fallocate" => {
492                // posix_fallocate is not supported by macos.
493                this.check_target_os(
494                    &[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos, Os::Android],
495                    link_name,
496                )?;
497                let [fd, offset, len] = this.check_shim_sig(
498                    shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t) -> i32),
499                    link_name,
500                    abi,
501                    args,
502                )?;
503
504                let fd = this.read_scalar(fd)?.to_i32()?;
505                // We don't support platforms which have libc::off_t bigger than 64 bits.
506                let offset =
507                    i64::try_from(this.read_scalar(offset)?.to_int(offset.layout.size)?).unwrap();
508                let len = i64::try_from(this.read_scalar(len)?.to_int(len.layout.size)?).unwrap();
509
510                let result = this.posix_fallocate(fd, offset, len)?;
511                this.write_scalar(result, dest)?;
512            }
513
514            "posix_fallocate64" => {
515                // posix_fallocate64 is only supported on Linux and Android
516                this.check_target_os(&[Os::Linux, Os::Android], link_name)?;
517                let [fd, offset, len] = this.check_shim_sig(
518                    shim_sig!(extern "C" fn(i32, libc::off64_t, libc::off64_t) -> i32),
519                    link_name,
520                    abi,
521                    args,
522                )?;
523
524                let fd = this.read_scalar(fd)?.to_i32()?;
525                let offset = this.read_scalar(offset)?.to_i64()?;
526                let len = this.read_scalar(len)?.to_i64()?;
527
528                let result = this.posix_fallocate(fd, offset, len)?;
529                this.write_scalar(result, dest)?;
530            }
531
532            "realpath" => {
533                let [path, resolved_path] = this.check_shim_sig(
534                    shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
535                    link_name,
536                    abi,
537                    args,
538                )?;
539                let result = this.realpath(path, resolved_path)?;
540                this.write_scalar(result, dest)?;
541            }
542            "mkstemp" => {
543                let [template] = this.check_shim_sig(
544                    shim_sig!(extern "C" fn(*mut _) -> i32),
545                    link_name,
546                    abi,
547                    args,
548                )?;
549                let result = this.mkstemp(template)?;
550                this.write_scalar(result, dest)?;
551            }
552
553            // Unnamed sockets and pipes
554            "socketpair" => {
555                let [domain, type_, protocol, sv] = this.check_shim_sig(
556                    shim_sig!(extern "C" fn(i32, i32, i32, *mut _) -> i32),
557                    link_name,
558                    abi,
559                    args,
560                )?;
561                let result = this.socketpair(domain, type_, protocol, sv)?;
562                this.write_scalar(result, dest)?;
563            }
564            "pipe" => {
565                let [pipefd] = this.check_shim_sig(
566                    shim_sig!(extern "C" fn(*mut _) -> i32),
567                    link_name,
568                    abi,
569                    args,
570                )?;
571                let result = this.pipe2(pipefd, /*flags*/ None)?;
572                this.write_scalar(result, dest)?;
573            }
574            "pipe2" => {
575                // Currently this function does not exist on all Unixes, e.g. on macOS.
576                this.check_target_os(
577                    &[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos],
578                    link_name,
579                )?;
580                let [pipefd, flags] = this.check_shim_sig(
581                    shim_sig!(extern "C" fn(*mut _, i32) -> i32),
582                    link_name,
583                    abi,
584                    args,
585                )?;
586                let result = this.pipe2(pipefd, Some(flags))?;
587                this.write_scalar(result, dest)?;
588            }
589
590            // Time
591            "gettimeofday" => {
592                let [tv, tz] = this.check_shim_sig(
593                    shim_sig!(extern "C" fn(*mut _, *mut _) -> i32),
594                    link_name,
595                    abi,
596                    args,
597                )?;
598                let result = this.gettimeofday(tv, tz)?;
599                this.write_scalar(result, dest)?;
600            }
601            "localtime_r" => {
602                let [timep, result_op] = this.check_shim_sig(
603                    shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
604                    link_name,
605                    abi,
606                    args,
607                )?;
608                let result = this.localtime_r(timep, result_op)?;
609                this.write_pointer(result, dest)?;
610            }
611            "clock_gettime" => {
612                let [clk_id, tp] = this.check_shim_sig(
613                    shim_sig!(extern "C" fn(libc::clockid_t, *mut _) -> i32),
614                    link_name,
615                    abi,
616                    args,
617                )?;
618                this.clock_gettime(clk_id, tp, dest)?;
619            }
620
621            // Allocation
622            "posix_memalign" => {
623                let [memptr, align, size] =
624                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
625                let result = this.posix_memalign(memptr, align, size)?;
626                this.write_scalar(result, dest)?;
627            }
628
629            "mmap" => {
630                let [addr, length, prot, flags, fd, offset] =
631                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
632                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
633                let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
634                this.write_scalar(ptr, dest)?;
635            }
636            "munmap" => {
637                let [addr, length] =
638                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
639                let result = this.munmap(addr, length)?;
640                this.write_scalar(result, dest)?;
641            }
642
643            "reallocarray" => {
644                // Currently this function does not exist on all Unixes, e.g. on macOS.
645                this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
646                let [ptr, nmemb, size] =
647                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
648                let ptr = this.read_pointer(ptr)?;
649                let nmemb = this.read_target_usize(nmemb)?;
650                let size = this.read_target_usize(size)?;
651                // reallocarray checks a possible overflow and returns ENOMEM
652                // if that happens.
653                //
654                // Linux: https://www.unix.com/man-page/linux/3/reallocarray/
655                // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray
656                match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
657                    None => {
658                        this.set_last_error(LibcError("ENOMEM"))?;
659                        this.write_null(dest)?;
660                    }
661                    Some(len) => {
662                        let res = this.realloc(ptr, len.bytes())?;
663                        this.write_pointer(res, dest)?;
664                    }
665                }
666            }
667            "aligned_alloc" => {
668                // This is a C11 function, we assume all Unixes have it.
669                // (MSVC explicitly does not support this.)
670                let [align, size] =
671                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
672                let res = this.aligned_alloc(align, size)?;
673                this.write_pointer(res, dest)?;
674            }
675
676            // Dynamic symbol loading
677            "dlsym" => {
678                let [handle, symbol] =
679                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
680                this.read_target_usize(handle)?;
681                let symbol = this.read_pointer(symbol)?;
682                let name = this.read_c_str(symbol)?;
683                if let Ok(name) = str::from_utf8(name)
684                    && is_dyn_sym(name, &this.tcx.sess.target.os)
685                {
686                    let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
687                    this.write_pointer(ptr, dest)?;
688                } else {
689                    this.write_null(dest)?;
690                }
691            }
692
693            // Thread-local storage
694            "pthread_key_create" => {
695                let [key, dtor] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
696                let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
697                let dtor = this.read_pointer(dtor)?;
698
699                // Extract the function type out of the signature (that seems easier than constructing it ourselves).
700                let dtor = if !this.ptr_is_null(dtor)? {
701                    Some(this.get_ptr_fn(dtor)?.as_instance()?)
702                } else {
703                    None
704                };
705
706                // Figure out how large a pthread TLS key actually is.
707                // To this end, deref the argument type. This is `libc::pthread_key_t`.
708                let key_type = key.layout.ty
709                    .builtin_deref(true)
710                    .ok_or_else(|| err_ub_format!(
711                        "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
712                    ))?;
713                let key_layout = this.layout_of(key_type)?;
714
715                // Create key and write it into the memory where `key_ptr` wants it.
716                let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
717                this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place)?;
718
719                // Return success (`0`).
720                this.write_null(dest)?;
721            }
722            "pthread_key_delete" => {
723                let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
724                let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
725                this.machine.tls.delete_tls_key(key)?;
726                // Return success (0)
727                this.write_null(dest)?;
728            }
729            "pthread_getspecific" => {
730                let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
731                let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
732                let active_thread = this.active_thread();
733                let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
734                this.write_scalar(ptr, dest)?;
735            }
736            "pthread_setspecific" => {
737                let [key, new_ptr] =
738                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
739                let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
740                let active_thread = this.active_thread();
741                let new_data = this.read_scalar(new_ptr)?;
742                this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
743
744                // Return success (`0`).
745                this.write_null(dest)?;
746            }
747
748            // Synchronization primitives
749            "pthread_mutexattr_init" => {
750                let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
751                this.pthread_mutexattr_init(attr)?;
752                this.write_null(dest)?;
753            }
754            "pthread_mutexattr_settype" => {
755                let [attr, kind] =
756                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
757                let result = this.pthread_mutexattr_settype(attr, kind)?;
758                this.write_scalar(result, dest)?;
759            }
760            "pthread_mutexattr_destroy" => {
761                let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
762                this.pthread_mutexattr_destroy(attr)?;
763                this.write_null(dest)?;
764            }
765            "pthread_mutex_init" => {
766                let [mutex, attr] =
767                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
768                this.pthread_mutex_init(mutex, attr)?;
769                this.write_null(dest)?;
770            }
771            "pthread_mutex_lock" => {
772                let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
773                this.pthread_mutex_lock(mutex, dest)?;
774            }
775            "pthread_mutex_trylock" => {
776                let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
777                let result = this.pthread_mutex_trylock(mutex)?;
778                this.write_scalar(result, dest)?;
779            }
780            "pthread_mutex_unlock" => {
781                let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
782                let result = this.pthread_mutex_unlock(mutex)?;
783                this.write_scalar(result, dest)?;
784            }
785            "pthread_mutex_destroy" => {
786                let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
787                this.pthread_mutex_destroy(mutex)?;
788                this.write_int(0, dest)?;
789            }
790            "pthread_rwlock_rdlock" => {
791                let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
792                this.pthread_rwlock_rdlock(rwlock, dest)?;
793            }
794            "pthread_rwlock_tryrdlock" => {
795                let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
796                let result = this.pthread_rwlock_tryrdlock(rwlock)?;
797                this.write_scalar(result, dest)?;
798            }
799            "pthread_rwlock_wrlock" => {
800                let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
801                this.pthread_rwlock_wrlock(rwlock, dest)?;
802            }
803            "pthread_rwlock_trywrlock" => {
804                let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
805                let result = this.pthread_rwlock_trywrlock(rwlock)?;
806                this.write_scalar(result, dest)?;
807            }
808            "pthread_rwlock_unlock" => {
809                let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
810                this.pthread_rwlock_unlock(rwlock)?;
811                this.write_null(dest)?;
812            }
813            "pthread_rwlock_destroy" => {
814                let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
815                this.pthread_rwlock_destroy(rwlock)?;
816                this.write_null(dest)?;
817            }
818            "pthread_condattr_init" => {
819                let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
820                this.pthread_condattr_init(attr)?;
821                this.write_null(dest)?;
822            }
823            "pthread_condattr_setclock" => {
824                let [attr, clock_id] =
825                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
826                let result = this.pthread_condattr_setclock(attr, clock_id)?;
827                this.write_scalar(result, dest)?;
828            }
829            "pthread_condattr_getclock" => {
830                let [attr, clock_id] =
831                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
832                this.pthread_condattr_getclock(attr, clock_id)?;
833                this.write_null(dest)?;
834            }
835            "pthread_condattr_destroy" => {
836                let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
837                this.pthread_condattr_destroy(attr)?;
838                this.write_null(dest)?;
839            }
840            "pthread_cond_init" => {
841                let [cond, attr] =
842                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
843                this.pthread_cond_init(cond, attr)?;
844                this.write_null(dest)?;
845            }
846            "pthread_cond_signal" => {
847                let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
848                this.pthread_cond_signal(cond)?;
849                this.write_null(dest)?;
850            }
851            "pthread_cond_broadcast" => {
852                let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
853                this.pthread_cond_broadcast(cond)?;
854                this.write_null(dest)?;
855            }
856            "pthread_cond_wait" => {
857                let [cond, mutex] =
858                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
859                this.pthread_cond_wait(cond, mutex, dest)?;
860            }
861            "pthread_cond_timedwait" => {
862                let [cond, mutex, abstime] =
863                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
864                this.pthread_cond_timedwait(
865                    cond, mutex, abstime, dest, /* macos_relative_np */ false,
866                )?;
867            }
868            "pthread_cond_destroy" => {
869                let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
870                this.pthread_cond_destroy(cond)?;
871                this.write_null(dest)?;
872            }
873
874            // Threading
875            "pthread_create" => {
876                let [thread, attr, start, arg] =
877                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
878                this.pthread_create(thread, attr, start, arg)?;
879                this.write_null(dest)?;
880            }
881            "pthread_join" => {
882                let [thread, retval] =
883                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
884                this.pthread_join(thread, retval, dest)?;
885            }
886            "pthread_detach" => {
887                let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
888                let res = this.pthread_detach(thread)?;
889                this.write_scalar(res, dest)?;
890            }
891            "pthread_self" => {
892                let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
893                let res = this.pthread_self()?;
894                this.write_scalar(res, dest)?;
895            }
896            "sched_yield" => {
897                let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
898                this.sched_yield()?;
899                this.write_null(dest)?;
900            }
901            "nanosleep" => {
902                let [duration, rem] =
903                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
904                let result = this.nanosleep(duration, rem)?;
905                this.write_scalar(result, dest)?;
906            }
907            "clock_nanosleep" => {
908                // Currently this function does not exist on all Unixes, e.g. on macOS.
909                this.check_target_os(
910                    &[Os::FreeBsd, Os::Linux, Os::Android, Os::Solaris, Os::Illumos],
911                    link_name,
912                )?;
913                let [clock_id, flags, req, rem] =
914                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
915                let result = this.clock_nanosleep(clock_id, flags, req, rem)?;
916                this.write_scalar(result, dest)?;
917            }
918            "sched_getaffinity" => {
919                // Currently this function does not exist on all Unixes, e.g. on macOS.
920                this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
921                let [pid, cpusetsize, mask] =
922                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
923                let pid = this.read_scalar(pid)?.to_u32()?;
924                let cpusetsize = this.read_target_usize(cpusetsize)?;
925                let mask = this.read_pointer(mask)?;
926
927                // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid
928                let thread_id = match pid {
929                    0 => this.active_thread(),
930                    _ =>
931                        throw_unsup_format!(
932                            "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"
933                        ),
934                };
935
936                // The mask is stored in chunks, and the size must be a whole number of chunks.
937                let chunk_size = CpuAffinityMask::chunk_size(this);
938
939                if this.ptr_is_null(mask)? {
940                    this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
941                } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
942                    // we only copy whole chunks of size_of::<c_ulong>()
943                    this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
944                } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
945                    let cpuset = cpuset.clone();
946                    // we only copy whole chunks of size_of::<c_ulong>()
947                    let byte_count =
948                        Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
949                    this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
950                    this.write_null(dest)?;
951                } else {
952                    // The thread whose ID is pid could not be found
953                    this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
954                }
955            }
956            "sched_setaffinity" => {
957                // Currently this function does not exist on all Unixes, e.g. on macOS.
958                this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
959                let [pid, cpusetsize, mask] =
960                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
961                let pid = this.read_scalar(pid)?.to_u32()?;
962                let cpusetsize = this.read_target_usize(cpusetsize)?;
963                let mask = this.read_pointer(mask)?;
964
965                // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid
966                let thread_id = match pid {
967                    0 => this.active_thread(),
968                    _ =>
969                        throw_unsup_format!(
970                            "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"
971                        ),
972                };
973
974                if this.ptr_is_null(mask)? {
975                    this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
976                } else {
977                    // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
978                    // Any unspecified bytes are treated as zero here (none of the CPUs are configured).
979                    // This is not exactly documented, so we assume that this is the behavior in practice.
980                    let bits_slice =
981                        this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
982                    // This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES`
983                    let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
984                        std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
985                    match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
986                        Some(cpuset) => {
987                            this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
988                            this.write_null(dest)?;
989                        }
990                        None => {
991                            // The intersection between the mask and the available CPUs was empty.
992                            this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
993                        }
994                    }
995                }
996            }
997
998            // Miscellaneous
999            "isatty" => {
1000                let [fd] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1001                let result = this.isatty(fd)?;
1002                this.write_scalar(result, dest)?;
1003            }
1004            "pthread_atfork" => {
1005                let [prepare, parent, child] =
1006                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1007                this.read_pointer(prepare)?;
1008                this.read_pointer(parent)?;
1009                this.read_pointer(child)?;
1010                // We do not support forking, so there is nothing to do here.
1011                this.write_null(dest)?;
1012            }
1013            "getentropy" => {
1014                // This function is non-standard but exists with the same signature and behavior on
1015                // Linux, macOS, FreeBSD and Solaris/Illumos.
1016                this.check_target_os(
1017                    &[Os::Linux, Os::MacOs, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
1018                    link_name,
1019                )?;
1020                let [buf, bufsize] =
1021                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1022                let buf = this.read_pointer(buf)?;
1023                let bufsize = this.read_target_usize(bufsize)?;
1024
1025                // getentropy sets errno to EIO when the buffer size exceeds 256 bytes.
1026                // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=getentropy&sektion=3&format=html
1027                // Linux: https://man7.org/linux/man-pages/man3/getentropy.3.html
1028                // macOS: https://keith.github.io/xcode-man-pages/getentropy.2.html
1029                // Solaris/Illumos: https://illumos.org/man/3C/getentropy
1030                if bufsize > 256 {
1031                    this.set_last_error_and_return(LibcError("EIO"), dest)?;
1032                } else {
1033                    this.gen_random(buf, bufsize)?;
1034                    this.write_null(dest)?;
1035                }
1036            }
1037
1038            "strerror_r" => {
1039                let [errnum, buf, buflen] =
1040                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1041                let result = this.strerror_r(errnum, buf, buflen)?;
1042                this.write_scalar(result, dest)?;
1043            }
1044
1045            "getrandom" => {
1046                // This function is non-standard but exists with the same signature and behavior on
1047                // Linux, FreeBSD and Solaris/Illumos.
1048                this.check_target_os(
1049                    &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
1050                    link_name,
1051                )?;
1052                let [ptr, len, flags] =
1053                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1054                let ptr = this.read_pointer(ptr)?;
1055                let len = this.read_target_usize(len)?;
1056                let _flags = this.read_scalar(flags)?.to_i32()?;
1057                // We ignore the flags, just always use the same PRNG / host RNG.
1058                this.gen_random(ptr, len)?;
1059                this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
1060            }
1061            "arc4random_buf" => {
1062                // This function is non-standard but exists with the same signature and
1063                // same behavior (eg never fails) on FreeBSD and Solaris/Illumos.
1064                this.check_target_os(&[Os::FreeBsd, Os::Illumos, Os::Solaris], link_name)?;
1065                let [ptr, len] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1066                let ptr = this.read_pointer(ptr)?;
1067                let len = this.read_target_usize(len)?;
1068                this.gen_random(ptr, len)?;
1069            }
1070            "_Unwind_RaiseException" => {
1071                // This is not formally part of POSIX, but it is very wide-spread on POSIX systems.
1072                // It was originally specified as part of the Itanium C++ ABI:
1073                // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-throw.
1074                // On Linux it is
1075                // documented as part of the LSB:
1076                // https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/baselib--unwind-raiseexception.html
1077                // Basically every other UNIX uses the exact same api though. Arm also references
1078                // back to the Itanium C++ ABI for the definition of `_Unwind_RaiseException` for
1079                // arm64:
1080                // https://github.com/ARM-software/abi-aa/blob/main/cppabi64/cppabi64.rst#toc-entry-35
1081                // For arm32 they did something custom, but similar enough that the same
1082                // `_Unwind_RaiseException` impl in miri should work:
1083                // https://github.com/ARM-software/abi-aa/blob/main/ehabi32/ehabi32.rst
1084                this.check_target_os(
1085                    &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android, Os::MacOs],
1086                    link_name,
1087                )?;
1088                // This function looks and behaves excatly like miri_start_unwind.
1089                let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1090                this.handle_miri_start_unwind(payload)?;
1091                return interp_ok(EmulateItemResult::NeedsUnwind);
1092            }
1093            "getuid" | "geteuid" => {
1094                let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1095                // For now, just pretend we always have this fixed UID.
1096                this.write_int(UID, dest)?;
1097            }
1098
1099            // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
1100            // These shims are enabled only when the caller is in the standard library.
1101            "pthread_attr_getguardsize" if this.frame_in_std() => {
1102                let [_attr, guard_size] =
1103                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1104                let guard_size_layout = this.machine.layouts.usize;
1105                let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
1106                this.write_scalar(
1107                    Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
1108                    &guard_size,
1109                )?;
1110
1111                // Return success (`0`).
1112                this.write_null(dest)?;
1113            }
1114
1115            "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
1116                let [_] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1117                this.write_null(dest)?;
1118            }
1119            "pthread_attr_setstacksize" if this.frame_in_std() => {
1120                let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1121                this.write_null(dest)?;
1122            }
1123
1124            "pthread_attr_getstack" if this.frame_in_std() => {
1125                // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here.
1126                // Hence we can mostly ignore the input `attr_place`.
1127                let [attr_place, addr_place, size_place] =
1128                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1129                let _attr_place =
1130                    this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
1131                let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?;
1132                let size_place = this.deref_pointer_as(size_place, this.machine.layouts.usize)?;
1133
1134                this.write_scalar(
1135                    Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
1136                    &addr_place,
1137                )?;
1138                this.write_scalar(
1139                    Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
1140                    &size_place,
1141                )?;
1142
1143                // Return success (`0`).
1144                this.write_null(dest)?;
1145            }
1146
1147            "signal" | "sigaltstack" if this.frame_in_std() => {
1148                let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1149                this.write_null(dest)?;
1150            }
1151            "sigaction" | "mprotect" if this.frame_in_std() => {
1152                let [_, _, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1153                this.write_null(dest)?;
1154            }
1155
1156            "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
1157                // getpwuid_r is the standard name, __posix_getpwuid_r is used on solarish
1158                let [uid, pwd, buf, buflen, result] =
1159                    this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1160                this.check_no_isolation("`getpwuid_r`")?;
1161
1162                let uid = this.read_scalar(uid)?.to_u32()?;
1163                let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?;
1164                let buf = this.read_pointer(buf)?;
1165                let buflen = this.read_target_usize(buflen)?;
1166                let result = this.deref_pointer_as(result, this.machine.layouts.mut_raw_ptr)?;
1167
1168                // Must be for "us".
1169                if uid != UID {
1170                    throw_unsup_format!("`getpwuid_r` on other users is not supported");
1171                }
1172
1173                // Reset all fields to `uninit` to make sure nobody reads them.
1174                // (This is a std-only shim so we are okay with such hacks.)
1175                this.write_uninit(&pwd)?;
1176
1177                // We only set the home_dir field.
1178                #[allow(deprecated)]
1179                let home_dir = std::env::home_dir().unwrap();
1180                let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
1181                let pw_dir = this.project_field_named(&pwd, "pw_dir")?;
1182                this.write_pointer(buf, &pw_dir)?;
1183
1184                if written {
1185                    this.write_pointer(pwd.ptr(), &result)?;
1186                    this.write_null(dest)?;
1187                } else {
1188                    this.write_null(&result)?;
1189                    this.write_scalar(this.eval_libc("ERANGE"), dest)?;
1190                }
1191            }
1192
1193            // Platform-specific shims
1194            _ => {
1195                let target_os = &this.tcx.sess.target.os;
1196                return match target_os {
1197                    Os::Android =>
1198                        android::EvalContextExt::emulate_foreign_item_inner(
1199                            this, link_name, abi, args, dest,
1200                        ),
1201                    Os::FreeBsd =>
1202                        freebsd::EvalContextExt::emulate_foreign_item_inner(
1203                            this, link_name, abi, args, dest,
1204                        ),
1205                    Os::Linux =>
1206                        linux::EvalContextExt::emulate_foreign_item_inner(
1207                            this, link_name, abi, args, dest,
1208                        ),
1209                    Os::MacOs =>
1210                        macos::EvalContextExt::emulate_foreign_item_inner(
1211                            this, link_name, abi, args, dest,
1212                        ),
1213                    Os::Solaris | Os::Illumos =>
1214                        solarish::EvalContextExt::emulate_foreign_item_inner(
1215                            this, link_name, abi, args, dest,
1216                        ),
1217                    _ => interp_ok(EmulateItemResult::NotSupported),
1218                };
1219            }
1220        };
1221
1222        interp_ok(EmulateItemResult::NeedsReturn)
1223    }
1224}