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 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)?;
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)?;
203 this.write_null(&ret.into())?;
205 let ptr = this.allocate_ptr(
206 Size::from_bytes(size),
207 Align::from_bytes(align).unwrap(),
208 MiriMemoryKind::C.into(),
210 this.write_pointer(ptr, &ret.into())?;
212 this.write_null(dest)?;
216 // Dynamic symbol loading
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)?;
226 this.write_null(dest)?;
230 // Querying system information
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()))
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));
252 if let Some(result) = result {
253 this.write_scalar(result, dest)?;
255 throw_unsup_format!("unimplemented sysconf name: {}", name)
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)?;
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()?)
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
276 .ok_or_else(|| err_ub_format!(
277 "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
280 let key_layout = this.layout_of(key_type)?;
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())?;
286 // Return success (`0`).
287 this.write_null(dest)?;
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)?;
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)?;
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)?;
310 // Return success (`0`).
311 this.write_null(dest)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
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}>"),
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)?;
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)?;
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())?;
501 // Return success (`0`).
502 this.write_null(dest)?;
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)?;
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)?;
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)?;
528 Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
532 Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
536 // Return success (`0`).
537 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 this.write_null(dest)?;
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)?;
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`")?;
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)?;
572 if uid != crate::shims::unix::UID {
573 throw_unsup_format!("`getpwuid_r` on other users is not supported");
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())?;
580 // We only set the home_dir field.
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())?;
588 this.write_pointer(pwd.ptr, &result.into())?;
589 this.write_null(dest)?;
591 this.write_null(&result.into())?;
592 this.write_scalar(this.eval_libc("ERANGE")?, dest)?;
596 // Platform-specific shims
598 let target_os = &*this.tcx.sess.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}"),
609 Ok(EmulateByNameResult::NeedsJumping)