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;
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 _;
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(
22 args: &[OpTy<'tcx, Provenance>],
23 dest: &PlaceTy<'tcx, Provenance>,
24 ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
25 let this = self.eval_context_mut();
27 // See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern.
29 match link_name.as_str() {
30 // Environment related shims
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
177 // Time related shims
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)?;
185 "posix_memalign" => {
186 let [ret, align, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
187 let ret = this.deref_operand(ret)?;
188 let align = this.read_scalar(align)?.to_machine_usize(this)?;
189 let size = this.read_scalar(size)?.to_machine_usize(this)?;
190 // Align must be power of 2, and also at least ptr-sized (POSIX rules).
191 // But failure to adhere to this is not UB, it's an error condition.
192 if !align.is_power_of_two() || align < this.pointer_size().bytes() {
193 let einval = this.eval_libc_i32("EINVAL")?;
194 this.write_int(einval, dest)?;
197 this.write_null(&ret.into())?;
199 let ptr = this.allocate_ptr(
200 Size::from_bytes(size),
201 Align::from_bytes(align).unwrap(),
202 MiriMemoryKind::C.into(),
204 this.write_pointer(ptr, &ret.into())?;
206 this.write_null(dest)?;
210 // Dynamic symbol loading
212 let [handle, symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
213 this.read_scalar(handle)?.to_machine_usize(this)?;
214 let symbol = this.read_pointer(symbol)?;
215 let symbol_name = this.read_c_str(symbol)?;
216 if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? {
217 let ptr = this.create_fn_alloc_ptr(FnVal::Other(dlsym));
218 this.write_pointer(ptr, dest)?;
220 this.write_null(dest)?;
224 // Querying system information
226 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
227 let name = this.read_scalar(name)?.to_i32()?;
228 // FIXME: Which of these are POSIX, and which are GNU/Linux?
229 // At least the names seem to all also exist on macOS.
230 let sysconfs: &[(&str, fn(&MiriInterpCx<'_, '_>) -> Scalar<Provenance>)] = &[
231 ("_SC_PAGESIZE", |this| Scalar::from_int(PAGE_SIZE, this.pointer_size())),
232 ("_SC_NPROCESSORS_CONF", |this| Scalar::from_int(this.machine.num_cpus, this.pointer_size())),
233 ("_SC_NPROCESSORS_ONLN", |this| Scalar::from_int(this.machine.num_cpus, this.pointer_size())),
234 // 512 seems to be a reasonable default. The value is not critical, in
235 // the sense that getpwuid_r takes and checks the buffer length.
236 ("_SC_GETPW_R_SIZE_MAX", |this| Scalar::from_int(512, this.pointer_size()))
238 let mut result = None;
239 for &(sysconf_name, value) in sysconfs {
240 let sysconf_name = this.eval_libc_i32(sysconf_name)?;
241 if sysconf_name == name {
242 result = Some(value(this));
246 if let Some(result) = result {
247 this.write_scalar(result, dest)?;
249 throw_unsup_format!("unimplemented sysconf name: {}", name)
253 // Thread-local storage
254 "pthread_key_create" => {
255 let [key, dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
256 let key_place = this.deref_operand(key)?;
257 let dtor = this.read_pointer(dtor)?;
259 // Extract the function type out of the signature (that seems easier than constructing it ourselves).
260 let dtor = if !this.ptr_is_null(dtor)? {
261 Some(this.get_ptr_fn(dtor)?.as_instance()?)
266 // Figure out how large a pthread TLS key actually is.
267 // To this end, deref the argument type. This is `libc::pthread_key_t`.
268 let key_type = key.layout.ty
270 .ok_or_else(|| err_ub_format!(
271 "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
274 let key_layout = this.layout_of(key_type)?;
276 // Create key and write it into the memory where `key_ptr` wants it.
277 let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
278 this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place.into())?;
280 // Return success (`0`).
281 this.write_null(dest)?;
283 "pthread_key_delete" => {
284 let [key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
285 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
286 this.machine.tls.delete_tls_key(key)?;
287 // Return success (0)
288 this.write_null(dest)?;
290 "pthread_getspecific" => {
291 let [key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
292 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
293 let active_thread = this.get_active_thread();
294 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
295 this.write_scalar(ptr, dest)?;
297 "pthread_setspecific" => {
298 let [key, new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
299 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
300 let active_thread = this.get_active_thread();
301 let new_data = this.read_scalar(new_ptr)?;
302 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
304 // Return success (`0`).
305 this.write_null(dest)?;
308 // Synchronization primitives
309 "pthread_mutexattr_init" => {
310 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
311 let result = this.pthread_mutexattr_init(attr)?;
312 this.write_scalar(Scalar::from_i32(result), dest)?;
314 "pthread_mutexattr_settype" => {
315 let [attr, kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
316 let result = this.pthread_mutexattr_settype(attr, kind)?;
317 this.write_scalar(Scalar::from_i32(result), dest)?;
319 "pthread_mutexattr_destroy" => {
320 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
321 let result = this.pthread_mutexattr_destroy(attr)?;
322 this.write_scalar(Scalar::from_i32(result), dest)?;
324 "pthread_mutex_init" => {
325 let [mutex, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
326 let result = this.pthread_mutex_init(mutex, attr)?;
327 this.write_scalar(Scalar::from_i32(result), dest)?;
329 "pthread_mutex_lock" => {
330 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
331 let result = this.pthread_mutex_lock(mutex)?;
332 this.write_scalar(Scalar::from_i32(result), dest)?;
334 "pthread_mutex_trylock" => {
335 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
336 let result = this.pthread_mutex_trylock(mutex)?;
337 this.write_scalar(Scalar::from_i32(result), dest)?;
339 "pthread_mutex_unlock" => {
340 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
341 let result = this.pthread_mutex_unlock(mutex)?;
342 this.write_scalar(Scalar::from_i32(result), dest)?;
344 "pthread_mutex_destroy" => {
345 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
346 let result = this.pthread_mutex_destroy(mutex)?;
347 this.write_scalar(Scalar::from_i32(result), dest)?;
349 "pthread_rwlock_rdlock" => {
350 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
351 let result = this.pthread_rwlock_rdlock(rwlock)?;
352 this.write_scalar(Scalar::from_i32(result), dest)?;
354 "pthread_rwlock_tryrdlock" => {
355 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
356 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
357 this.write_scalar(Scalar::from_i32(result), dest)?;
359 "pthread_rwlock_wrlock" => {
360 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
361 let result = this.pthread_rwlock_wrlock(rwlock)?;
362 this.write_scalar(Scalar::from_i32(result), dest)?;
364 "pthread_rwlock_trywrlock" => {
365 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
366 let result = this.pthread_rwlock_trywrlock(rwlock)?;
367 this.write_scalar(Scalar::from_i32(result), dest)?;
369 "pthread_rwlock_unlock" => {
370 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
371 let result = this.pthread_rwlock_unlock(rwlock)?;
372 this.write_scalar(Scalar::from_i32(result), dest)?;
374 "pthread_rwlock_destroy" => {
375 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
376 let result = this.pthread_rwlock_destroy(rwlock)?;
377 this.write_scalar(Scalar::from_i32(result), dest)?;
379 "pthread_condattr_init" => {
380 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
381 let result = this.pthread_condattr_init(attr)?;
382 this.write_scalar(Scalar::from_i32(result), dest)?;
384 "pthread_condattr_destroy" => {
385 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
386 let result = this.pthread_condattr_destroy(attr)?;
387 this.write_scalar(Scalar::from_i32(result), dest)?;
389 "pthread_cond_init" => {
390 let [cond, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
391 let result = this.pthread_cond_init(cond, attr)?;
392 this.write_scalar(Scalar::from_i32(result), dest)?;
394 "pthread_cond_signal" => {
395 let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
396 let result = this.pthread_cond_signal(cond)?;
397 this.write_scalar(Scalar::from_i32(result), dest)?;
399 "pthread_cond_broadcast" => {
400 let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
401 let result = this.pthread_cond_broadcast(cond)?;
402 this.write_scalar(Scalar::from_i32(result), dest)?;
404 "pthread_cond_wait" => {
405 let [cond, mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
406 let result = this.pthread_cond_wait(cond, mutex)?;
407 this.write_scalar(Scalar::from_i32(result), dest)?;
409 "pthread_cond_timedwait" => {
410 let [cond, mutex, abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
411 this.pthread_cond_timedwait(cond, mutex, abstime, dest)?;
413 "pthread_cond_destroy" => {
414 let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
415 let result = this.pthread_cond_destroy(cond)?;
416 this.write_scalar(Scalar::from_i32(result), dest)?;
420 "pthread_create" => {
421 let [thread, attr, start, arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
422 let result = this.pthread_create(thread, attr, start, arg)?;
423 this.write_scalar(Scalar::from_i32(result), dest)?;
426 let [thread, retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
427 let result = this.pthread_join(thread, retval)?;
428 this.write_scalar(Scalar::from_i32(result), dest)?;
430 "pthread_detach" => {
431 let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
432 let result = this.pthread_detach(thread)?;
433 this.write_scalar(Scalar::from_i32(result), dest)?;
436 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
437 let res = this.pthread_self()?;
438 this.write_scalar(res, dest)?;
441 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
442 let result = this.sched_yield()?;
443 this.write_scalar(Scalar::from_i32(result), dest)?;
446 let [req, rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
447 let result = this.nanosleep(req, rem)?;
448 this.write_scalar(Scalar::from_i32(result), dest)?;
453 let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
454 let result = this.isatty(fd)?;
455 this.write_scalar(result, dest)?;
457 "pthread_atfork" => {
458 let [prepare, parent, child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
459 this.read_pointer(prepare)?;
460 this.read_pointer(parent)?;
461 this.read_pointer(child)?;
462 // We do not support forking, so there is nothing to do here.
463 this.write_null(dest)?;
465 "strerror_r" | "__xpg_strerror_r" => {
466 let [errnum, buf, buflen] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
467 let errnum = this.read_scalar(errnum)?;
468 let buf = this.read_pointer(buf)?;
469 let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?;
471 let error = this.try_errnum_to_io_error(errnum)?;
472 let formatted = match error {
473 Some(err) => format!("{err}"),
474 None => format!("<unknown errnum in strerror_r: {errnum}>"),
476 let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?;
477 let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE")? };
478 this.write_int(ret, dest)?;
481 let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?;
482 let result = this.getpid()?;
483 this.write_scalar(Scalar::from_i32(result), dest)?;
486 // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
487 // These shims are enabled only when the caller is in the standard library.
488 "pthread_attr_getguardsize"
489 if this.frame_in_std() => {
490 let [_attr, guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
491 let guard_size = this.deref_operand(guard_size)?;
492 let guard_size_layout = this.libc_ty_layout("size_t")?;
493 this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), &guard_size.into())?;
495 // Return success (`0`).
496 this.write_null(dest)?;
499 | "pthread_attr_init"
500 | "pthread_attr_destroy"
501 if this.frame_in_std() => {
502 let [_] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
503 this.write_null(dest)?;
505 | "pthread_attr_setstacksize"
506 if this.frame_in_std() => {
507 let [_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
508 this.write_null(dest)?;
511 "pthread_attr_getstack"
512 if this.frame_in_std() => {
513 // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here.
514 // Hence we can mostly ignore the input `attr_place`.
515 let [attr_place, addr_place, size_place] =
516 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
517 let _attr_place = this.deref_operand(attr_place)?;
518 let addr_place = this.deref_operand(addr_place)?;
519 let size_place = this.deref_operand(size_place)?;
522 Scalar::from_uint(STACK_ADDR, this.pointer_size()),
526 Scalar::from_uint(STACK_SIZE, this.pointer_size()),
530 // Return success (`0`).
531 this.write_null(dest)?;
536 if this.frame_in_std() => {
537 let [_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
538 this.write_null(dest)?;
542 if this.frame_in_std() => {
543 let [_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
544 this.write_null(dest)?;
548 if this.frame_in_std() => {
549 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
550 // FOr now, just pretend we always have this fixed UID.
551 this.write_int(super::UID, dest)?;
554 "getpwuid_r" if this.frame_in_std() => {
555 let [uid, pwd, buf, buflen, result] =
556 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
557 this.check_no_isolation("`getpwuid_r`")?;
559 let uid = this.read_scalar(uid)?.to_u32()?;
560 let pwd = this.deref_operand(pwd)?;
561 let buf = this.read_pointer(buf)?;
562 let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?;
563 let result = this.deref_operand(result)?;
566 if uid != crate::shims::unix::UID {
567 throw_unsup_format!("`getpwuid_r` on other users is not supported");
570 // Reset all fields to `uninit` to make sure nobody reads them.
571 // (This is a std-only shim so we are okay with such hacks.)
572 this.write_uninit(&pwd.into())?;
574 // We only set the home_dir field.
576 let home_dir = std::env::home_dir().unwrap();
577 let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
578 let pw_dir = this.mplace_field_named(&pwd, "pw_dir")?;
579 this.write_pointer(buf, &pw_dir.into())?;
582 this.write_pointer(pwd.ptr, &result.into())?;
583 this.write_null(dest)?;
585 this.write_null(&result.into())?;
586 this.write_scalar(this.eval_libc("ERANGE")?, dest)?;
590 // Platform-specific shims
592 let target_os = &*this.tcx.sess.target.os;
594 "android" => return shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
595 "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
596 "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
597 "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
598 _ => panic!("unsupported Unix OS {target_os}"),
603 Ok(EmulateByNameResult::NeedsJumping)