]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/src/shims/unix/foreign_items.rs
e851d6d5139ce5a666e23ae54003d95f51c18aa1
[rust.git] / src / tools / miri / src / shims / unix / foreign_items.rs
1 use std::ffi::OsStr;
2
3 use log::trace;
4
5 use rustc_middle::ty::layout::LayoutOf;
6 use rustc_span::Symbol;
7 use rustc_target::abi::{Align, Size};
8 use rustc_target::spec::abi::Abi;
9
10 use crate::*;
11 use shims::foreign_items::EmulateByNameResult;
12 use shims::unix::fs::EvalContextExt as _;
13 use shims::unix::sync::EvalContextExt as _;
14 use shims::unix::thread::EvalContextExt as _;
15
16 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
17 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
18     fn emulate_foreign_item_by_name(
19         &mut self,
20         link_name: Symbol,
21         abi: Abi,
22         args: &[OpTy<'tcx, Provenance>],
23         dest: &PlaceTy<'tcx, Provenance>,
24     ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
25         let this = self.eval_context_mut();
26
27         // See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern.
28         #[rustfmt::skip]
29         match link_name.as_str() {
30             // Environment related shims
31             "getenv" => {
32                 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
33                 let result = this.getenv(name)?;
34                 this.write_pointer(result, dest)?;
35             }
36             "unsetenv" => {
37                 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
38                 let result = this.unsetenv(name)?;
39                 this.write_scalar(Scalar::from_i32(result), dest)?;
40             }
41             "setenv" => {
42                 let [name, value, overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
43                 this.read_scalar(overwrite)?.to_i32()?;
44                 let result = this.setenv(name, value)?;
45                 this.write_scalar(Scalar::from_i32(result), dest)?;
46             }
47             "getcwd" => {
48                 let [buf, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
49                 let result = this.getcwd(buf, size)?;
50                 this.write_pointer(result, dest)?;
51             }
52             "chdir" => {
53                 let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
54                 let result = this.chdir(path)?;
55                 this.write_scalar(Scalar::from_i32(result), dest)?;
56             }
57
58             // File related shims
59             "open" | "open64" => {
60                 // `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
61                 this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
62                 let result = this.open(args)?;
63                 this.write_scalar(Scalar::from_i32(result), dest)?;
64             }
65             "close" => {
66                 let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
67                 let result = this.close(fd)?;
68                 this.write_scalar(result, dest)?;
69             }
70             "fcntl" => {
71                 // `fcntl` is variadic. The argument count is checked based on the first argument
72                 // in `this.fcntl()`, so we do not use `check_shim` here.
73                 this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
74                 let result = this.fcntl(args)?;
75                 this.write_scalar(Scalar::from_i32(result), dest)?;
76             }
77             "read" => {
78                 let [fd, buf, count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
79                 let fd = this.read_scalar(fd)?.to_i32()?;
80                 let buf = this.read_pointer(buf)?;
81                 let count = this.read_scalar(count)?.to_machine_usize(this)?;
82                 let result = this.read(fd, buf, count)?;
83                 this.write_scalar(Scalar::from_machine_isize(result, this), dest)?;
84             }
85             "write" => {
86                 let [fd, buf, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
87                 let fd = this.read_scalar(fd)?.to_i32()?;
88                 let buf = this.read_pointer(buf)?;
89                 let count = this.read_scalar(n)?.to_machine_usize(this)?;
90                 trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
91                 let result = this.write(fd, buf, count)?;
92                 // Now, `result` is the value we return back to the program.
93                 this.write_scalar(Scalar::from_machine_isize(result, this), dest)?;
94             }
95             "unlink" => {
96                 let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
97                 let result = this.unlink(path)?;
98                 this.write_scalar(Scalar::from_i32(result), dest)?;
99             }
100             "symlink" => {
101                 let [target, linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
102                 let result = this.symlink(target, linkpath)?;
103                 this.write_scalar(Scalar::from_i32(result), dest)?;
104             }
105             "rename" => {
106                 let [oldpath, newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
107                 let result = this.rename(oldpath, newpath)?;
108                 this.write_scalar(Scalar::from_i32(result), dest)?;
109             }
110             "mkdir" => {
111                 let [path, mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
112                 let result = this.mkdir(path, mode)?;
113                 this.write_scalar(Scalar::from_i32(result), dest)?;
114             }
115             "rmdir" => {
116                 let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
117                 let result = this.rmdir(path)?;
118                 this.write_scalar(Scalar::from_i32(result), dest)?;
119             }
120             "opendir" => {
121                 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
122                 let result = this.opendir(name)?;
123                 this.write_scalar(result, dest)?;
124             }
125             "closedir" => {
126                 let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
127                 let result = this.closedir(dirp)?;
128                 this.write_scalar(Scalar::from_i32(result), dest)?;
129             }
130             "lseek64" => {
131                 let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
132                 let result = this.lseek64(fd, offset, whence)?;
133                 this.write_scalar(result, dest)?;
134             }
135             "ftruncate64" => {
136                 let [fd, length] =
137                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
138                 let result = this.ftruncate64(fd, length)?;
139                 this.write_scalar(result, dest)?;
140             }
141             "fsync" => {
142                 let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
143                 let result = this.fsync(fd)?;
144                 this.write_scalar(Scalar::from_i32(result), dest)?;
145             }
146             "fdatasync" => {
147                 let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
148                 let result = this.fdatasync(fd)?;
149                 this.write_scalar(Scalar::from_i32(result), dest)?;
150             }
151             "readlink" => {
152                 let [pathname, buf, bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
153                 let result = this.readlink(pathname, buf, bufsize)?;
154                 this.write_scalar(Scalar::from_machine_isize(result, this), dest)?;
155             }
156             "posix_fadvise" => {
157                 let [fd, offset, len, advice] =
158                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
159                 this.read_scalar(fd)?.to_i32()?;
160                 this.read_scalar(offset)?.to_machine_isize(this)?;
161                 this.read_scalar(len)?.to_machine_isize(this)?;
162                 this.read_scalar(advice)?.to_i32()?;
163                 // fadvise is only informational, we can ignore it.
164                 this.write_null(dest)?;
165             }
166             "realpath" => {
167                 let [path, resolved_path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
168                 let result = this.realpath(path, resolved_path)?;
169                 this.write_scalar(result, dest)?;
170             }
171             "mkstemp" => {
172                 let [template] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
173                 let result = this.mkstemp(template)?;
174                 this.write_scalar(Scalar::from_i32(result), dest)?;
175             }
176
177             // Time related shims
178             "gettimeofday" => {
179                 let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
180                 let result = this.gettimeofday(tv, tz)?;
181                 this.write_scalar(Scalar::from_i32(result), dest)?;
182             }
183             "clock_gettime" => {
184                 let [clk_id, tp] =
185                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
186                 let result = this.clock_gettime(clk_id, tp)?;
187                 this.write_scalar(result, dest)?;
188             }
189
190             // Allocation
191             "posix_memalign" => {
192                 let [ret, align, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
193                 let ret = this.deref_operand(ret)?;
194                 let align = this.read_scalar(align)?.to_machine_usize(this)?;
195                 let size = this.read_scalar(size)?.to_machine_usize(this)?;
196                 // Align must be power of 2, and also at least ptr-sized (POSIX rules).
197                 // But failure to adhere to this is not UB, it's an error condition.
198                 if !align.is_power_of_two() || align < this.pointer_size().bytes() {
199                     let einval = this.eval_libc_i32("EINVAL")?;
200                     this.write_int(einval, dest)?;
201                 } else {
202                     if size == 0 {
203                         this.write_null(&ret.into())?;
204                     } else {
205                         let ptr = this.allocate_ptr(
206                             Size::from_bytes(size),
207                             Align::from_bytes(align).unwrap(),
208                             MiriMemoryKind::C.into(),
209                         )?;
210                         this.write_pointer(ptr, &ret.into())?;
211                     }
212                     this.write_null(dest)?;
213                 }
214             }
215
216             // Dynamic symbol loading
217             "dlsym" => {
218                 let [handle, symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
219                 this.read_scalar(handle)?.to_machine_usize(this)?;
220                 let symbol = this.read_pointer(symbol)?;
221                 let symbol_name = this.read_c_str(symbol)?;
222                 if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? {
223                     let ptr = this.create_fn_alloc_ptr(FnVal::Other(dlsym));
224                     this.write_pointer(ptr, dest)?;
225                 } else {
226                     this.write_null(dest)?;
227                 }
228             }
229
230             // Querying system information
231             "sysconf" => {
232                 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
233                 let name = this.read_scalar(name)?.to_i32()?;
234                 // FIXME: Which of these are POSIX, and which are GNU/Linux?
235                 // At least the names seem to all also exist on macOS.
236                 let sysconfs: &[(&str, fn(&MiriInterpCx<'_, '_>) -> Scalar<Provenance>)] = &[
237                     ("_SC_PAGESIZE", |this| Scalar::from_int(this.machine.page_size, this.pointer_size())),
238                     ("_SC_NPROCESSORS_CONF", |this| Scalar::from_int(this.machine.num_cpus, this.pointer_size())),
239                     ("_SC_NPROCESSORS_ONLN", |this| Scalar::from_int(this.machine.num_cpus, this.pointer_size())),
240                     // 512 seems to be a reasonable default. The value is not critical, in
241                     // the sense that getpwuid_r takes and checks the buffer length.
242                     ("_SC_GETPW_R_SIZE_MAX", |this| Scalar::from_int(512, this.pointer_size()))
243                 ];
244                 let mut result = None;
245                 for &(sysconf_name, value) in sysconfs {
246                     let sysconf_name = this.eval_libc_i32(sysconf_name)?;
247                     if sysconf_name == name {
248                         result = Some(value(this));
249                         break;
250                     }
251                 }
252                 if let Some(result) = result {
253                     this.write_scalar(result, dest)?;
254                 } else {
255                     throw_unsup_format!("unimplemented sysconf name: {}", name)
256                 }
257             }
258
259             // Thread-local storage
260             "pthread_key_create" => {
261                 let [key, dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
262                 let key_place = this.deref_operand(key)?;
263                 let dtor = this.read_pointer(dtor)?;
264
265                 // Extract the function type out of the signature (that seems easier than constructing it ourselves).
266                 let dtor = if !this.ptr_is_null(dtor)? {
267                     Some(this.get_ptr_fn(dtor)?.as_instance()?)
268                 } else {
269                     None
270                 };
271
272                 // Figure out how large a pthread TLS key actually is.
273                 // To this end, deref the argument type. This is `libc::pthread_key_t`.
274                 let key_type = key.layout.ty
275                     .builtin_deref(true)
276                     .ok_or_else(|| err_ub_format!(
277                         "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
278                     ))?
279                     .ty;
280                 let key_layout = this.layout_of(key_type)?;
281
282                 // Create key and write it into the memory where `key_ptr` wants it.
283                 let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
284                 this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place.into())?;
285
286                 // Return success (`0`).
287                 this.write_null(dest)?;
288             }
289             "pthread_key_delete" => {
290                 let [key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
291                 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
292                 this.machine.tls.delete_tls_key(key)?;
293                 // Return success (0)
294                 this.write_null(dest)?;
295             }
296             "pthread_getspecific" => {
297                 let [key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
298                 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
299                 let active_thread = this.get_active_thread();
300                 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
301                 this.write_scalar(ptr, dest)?;
302             }
303             "pthread_setspecific" => {
304                 let [key, new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
305                 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
306                 let active_thread = this.get_active_thread();
307                 let new_data = this.read_scalar(new_ptr)?;
308                 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
309
310                 // Return success (`0`).
311                 this.write_null(dest)?;
312             }
313
314             // Synchronization primitives
315             "pthread_mutexattr_init" => {
316                 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
317                 let result = this.pthread_mutexattr_init(attr)?;
318                 this.write_scalar(Scalar::from_i32(result), dest)?;
319             }
320             "pthread_mutexattr_settype" => {
321                 let [attr, kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
322                 let result = this.pthread_mutexattr_settype(attr, kind)?;
323                 this.write_scalar(Scalar::from_i32(result), dest)?;
324             }
325             "pthread_mutexattr_destroy" => {
326                 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
327                 let result = this.pthread_mutexattr_destroy(attr)?;
328                 this.write_scalar(Scalar::from_i32(result), dest)?;
329             }
330             "pthread_mutex_init" => {
331                 let [mutex, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
332                 let result = this.pthread_mutex_init(mutex, attr)?;
333                 this.write_scalar(Scalar::from_i32(result), dest)?;
334             }
335             "pthread_mutex_lock" => {
336                 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
337                 let result = this.pthread_mutex_lock(mutex)?;
338                 this.write_scalar(Scalar::from_i32(result), dest)?;
339             }
340             "pthread_mutex_trylock" => {
341                 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
342                 let result = this.pthread_mutex_trylock(mutex)?;
343                 this.write_scalar(Scalar::from_i32(result), dest)?;
344             }
345             "pthread_mutex_unlock" => {
346                 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
347                 let result = this.pthread_mutex_unlock(mutex)?;
348                 this.write_scalar(Scalar::from_i32(result), dest)?;
349             }
350             "pthread_mutex_destroy" => {
351                 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
352                 let result = this.pthread_mutex_destroy(mutex)?;
353                 this.write_scalar(Scalar::from_i32(result), dest)?;
354             }
355             "pthread_rwlock_rdlock" => {
356                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
357                 let result = this.pthread_rwlock_rdlock(rwlock)?;
358                 this.write_scalar(Scalar::from_i32(result), dest)?;
359             }
360             "pthread_rwlock_tryrdlock" => {
361                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
362                 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
363                 this.write_scalar(Scalar::from_i32(result), dest)?;
364             }
365             "pthread_rwlock_wrlock" => {
366                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
367                 let result = this.pthread_rwlock_wrlock(rwlock)?;
368                 this.write_scalar(Scalar::from_i32(result), dest)?;
369             }
370             "pthread_rwlock_trywrlock" => {
371                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
372                 let result = this.pthread_rwlock_trywrlock(rwlock)?;
373                 this.write_scalar(Scalar::from_i32(result), dest)?;
374             }
375             "pthread_rwlock_unlock" => {
376                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
377                 let result = this.pthread_rwlock_unlock(rwlock)?;
378                 this.write_scalar(Scalar::from_i32(result), dest)?;
379             }
380             "pthread_rwlock_destroy" => {
381                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
382                 let result = this.pthread_rwlock_destroy(rwlock)?;
383                 this.write_scalar(Scalar::from_i32(result), dest)?;
384             }
385             "pthread_condattr_init" => {
386                 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
387                 let result = this.pthread_condattr_init(attr)?;
388                 this.write_scalar(Scalar::from_i32(result), dest)?;
389             }
390             "pthread_condattr_destroy" => {
391                 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
392                 let result = this.pthread_condattr_destroy(attr)?;
393                 this.write_scalar(Scalar::from_i32(result), dest)?;
394             }
395             "pthread_cond_init" => {
396                 let [cond, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
397                 let result = this.pthread_cond_init(cond, attr)?;
398                 this.write_scalar(Scalar::from_i32(result), dest)?;
399             }
400             "pthread_cond_signal" => {
401                 let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
402                 let result = this.pthread_cond_signal(cond)?;
403                 this.write_scalar(Scalar::from_i32(result), dest)?;
404             }
405             "pthread_cond_broadcast" => {
406                 let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
407                 let result = this.pthread_cond_broadcast(cond)?;
408                 this.write_scalar(Scalar::from_i32(result), dest)?;
409             }
410             "pthread_cond_wait" => {
411                 let [cond, mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
412                 let result = this.pthread_cond_wait(cond, mutex)?;
413                 this.write_scalar(Scalar::from_i32(result), dest)?;
414             }
415             "pthread_cond_timedwait" => {
416                 let [cond, mutex, abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
417                 this.pthread_cond_timedwait(cond, mutex, abstime, dest)?;
418             }
419             "pthread_cond_destroy" => {
420                 let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
421                 let result = this.pthread_cond_destroy(cond)?;
422                 this.write_scalar(Scalar::from_i32(result), dest)?;
423             }
424
425             // Threading
426             "pthread_create" => {
427                 let [thread, attr, start, arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
428                 let result = this.pthread_create(thread, attr, start, arg)?;
429                 this.write_scalar(Scalar::from_i32(result), dest)?;
430             }
431             "pthread_join" => {
432                 let [thread, retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
433                 let result = this.pthread_join(thread, retval)?;
434                 this.write_scalar(Scalar::from_i32(result), dest)?;
435             }
436             "pthread_detach" => {
437                 let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
438                 let result = this.pthread_detach(thread)?;
439                 this.write_scalar(Scalar::from_i32(result), dest)?;
440             }
441             "pthread_self" => {
442                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
443                 let res = this.pthread_self()?;
444                 this.write_scalar(res, dest)?;
445             }
446             "sched_yield" => {
447                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
448                 let result = this.sched_yield()?;
449                 this.write_scalar(Scalar::from_i32(result), dest)?;
450             }
451             "nanosleep" => {
452                 let [req, rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
453                 let result = this.nanosleep(req, rem)?;
454                 this.write_scalar(Scalar::from_i32(result), dest)?;
455             }
456
457             // Miscellaneous
458             "isatty" => {
459                 let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
460                 let result = this.isatty(fd)?;
461                 this.write_scalar(result, dest)?;
462             }
463             "pthread_atfork" => {
464                 let [prepare, parent, child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
465                 this.read_pointer(prepare)?;
466                 this.read_pointer(parent)?;
467                 this.read_pointer(child)?;
468                 // We do not support forking, so there is nothing to do here.
469                 this.write_null(dest)?;
470             }
471             "strerror_r" | "__xpg_strerror_r" => {
472                 let [errnum, buf, buflen] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
473                 let errnum = this.read_scalar(errnum)?;
474                 let buf = this.read_pointer(buf)?;
475                 let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?;
476
477                 let error = this.try_errnum_to_io_error(errnum)?;
478                 let formatted = match error {
479                     Some(err) => format!("{err}"),
480                     None => format!("<unknown errnum in strerror_r: {errnum}>"),
481                 };
482                 let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?;
483                 let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE")? };
484                 this.write_int(ret, dest)?;
485             }
486             "getpid" => {
487                 let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?;
488                 let result = this.getpid()?;
489                 this.write_scalar(Scalar::from_i32(result), dest)?;
490             }
491
492             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
493             // These shims are enabled only when the caller is in the standard library.
494             "pthread_attr_getguardsize"
495             if this.frame_in_std() => {
496                 let [_attr, guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
497                 let guard_size = this.deref_operand(guard_size)?;
498                 let guard_size_layout = this.libc_ty_layout("size_t")?;
499                 this.write_scalar(Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size.into())?;
500
501                 // Return success (`0`).
502                 this.write_null(dest)?;
503             }
504
505             | "pthread_attr_init"
506             | "pthread_attr_destroy"
507             if this.frame_in_std() => {
508                 let [_] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
509                 this.write_null(dest)?;
510             }
511             | "pthread_attr_setstacksize"
512             if this.frame_in_std() => {
513                 let [_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
514                 this.write_null(dest)?;
515             }
516
517             "pthread_attr_getstack"
518             if this.frame_in_std() => {
519                 // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here.
520                 // Hence we can mostly ignore the input `attr_place`.
521                 let [attr_place, addr_place, size_place] =
522                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
523                 let _attr_place = this.deref_operand(attr_place)?;
524                 let addr_place = this.deref_operand(addr_place)?;
525                 let size_place = this.deref_operand(size_place)?;
526
527                 this.write_scalar(
528                     Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
529                     &addr_place.into(),
530                 )?;
531                 this.write_scalar(
532                     Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
533                     &size_place.into(),
534                 )?;
535
536                 // Return success (`0`).
537                 this.write_null(dest)?;
538             }
539
540             | "signal"
541             | "sigaltstack"
542             if this.frame_in_std() => {
543                 let [_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
544                 this.write_null(dest)?;
545             }
546             | "sigaction"
547             | "mprotect"
548             if this.frame_in_std() => {
549                 let [_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
550                 this.write_null(dest)?;
551             }
552
553             "getuid"
554             if this.frame_in_std() => {
555                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
556                 // FOr now, just pretend we always have this fixed UID.
557                 this.write_int(super::UID, dest)?;
558             }
559
560             "getpwuid_r" if this.frame_in_std() => {
561                 let [uid, pwd, buf, buflen, result] =
562                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
563                 this.check_no_isolation("`getpwuid_r`")?;
564
565                 let uid = this.read_scalar(uid)?.to_u32()?;
566                 let pwd = this.deref_operand(pwd)?;
567                 let buf = this.read_pointer(buf)?;
568                 let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?;
569                 let result = this.deref_operand(result)?;
570
571                 // Must be for "us".
572                 if uid != crate::shims::unix::UID {
573                     throw_unsup_format!("`getpwuid_r` on other users is not supported");
574                 }
575
576                 // Reset all fields to `uninit` to make sure nobody reads them.
577                 // (This is a std-only shim so we are okay with such hacks.)
578                 this.write_uninit(&pwd.into())?;
579
580                 // We only set the home_dir field.
581                 #[allow(deprecated)]
582                 let home_dir = std::env::home_dir().unwrap();
583                 let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
584                 let pw_dir = this.mplace_field_named(&pwd, "pw_dir")?;
585                 this.write_pointer(buf, &pw_dir.into())?;
586
587                 if written {
588                     this.write_pointer(pwd.ptr, &result.into())?;
589                     this.write_null(dest)?;
590                 } else {
591                     this.write_null(&result.into())?;
592                     this.write_scalar(this.eval_libc("ERANGE")?, dest)?;
593                 }
594             }
595
596             // Platform-specific shims
597             _ => {
598                 let target_os = &*this.tcx.sess.target.os;
599                 match target_os {
600                     "android" => return shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
601                     "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
602                     "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
603                     "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
604                     _ => panic!("unsupported Unix OS {target_os}"),
605                 }
606             }
607         };
608
609         Ok(EmulateByNameResult::NeedsJumping)
610     }
611 }