1use std::ffi::OsStr;
2use std::str;
3use std::time::Duration;
4
5use rustc_abi::{CanonAbi, Size};
6use rustc_middle::ty::Ty;
7use rustc_span::Symbol;
8use rustc_target::callconv::FnAbi;
9use rustc_target::spec::{Env, Os};
10
11use self::shims::unix::android::foreign_items as android;
12use self::shims::unix::freebsd::foreign_items as freebsd;
13use self::shims::unix::linux::foreign_items as linux;
14use self::shims::unix::macos::foreign_items as macos;
15use self::shims::unix::netbsd::foreign_items as netbsd;
16use self::shims::unix::solarish::foreign_items as solarish;
17use crate::concurrency::cpu_affinity::CpuAffinityMask;
18use crate::shims::alloc::EvalContextExt as _;
19use crate::shims::unix::*;
20use crate::{shim_sig, *};
21
22pub fn is_dyn_sym(name: &str, target_os: &Os) -> bool {
23 match name {
24 "strlen" => true,
26 "signal" => true,
29 "getentropy" | "getrandom" => true,
31 "futimens" => true,
34 "preadv" | "pwritev" if !matches!(*target_os, Os::Solaris) => true,
38 _ =>
40 match *target_os {
41 Os::Android => android::is_dyn_sym(name),
42 Os::FreeBsd => freebsd::is_dyn_sym(name),
43 Os::Linux => linux::is_dyn_sym(name),
44 Os::MacOs => macos::is_dyn_sym(name),
45 Os::Solaris | Os::Illumos => solarish::is_dyn_sym(name),
46 Os::NetBsd => netbsd::is_dyn_sym(name),
47 _ => false,
48 },
49 }
50}
51
52impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
53pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
54 fn sysconf(&mut self, val: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
56 let this = self.eval_context_mut();
57
58 let name = this.read_scalar(val)?.to_i32()?;
59 static SYSCONFS: &[(&str, fn(&MiriInterpCx<'_>) -> i64)] = &[
62 ("_SC_PAGESIZE", |this| this.machine.page_size.try_into().unwrap()),
63 ("_SC_PAGE_SIZE", |this| this.machine.page_size.try_into().unwrap()),
64 ("_SC_NPROCESSORS_CONF", |this| this.machine.num_cpus.into()),
65 ("_SC_NPROCESSORS_ONLN", |this| this.machine.num_cpus.into()),
66 ("_SC_GETPW_R_SIZE_MAX", |_this| 512),
69 ("_SC_OPEN_MAX", |_this| 2_i32.pow(16).into()),
74 ("_SC_HOST_NAME_MAX", |_this| 255),
76 ];
77 for &(sysconf_name, value) in SYSCONFS {
78 let sysconf_name = this.eval_libc_i32(sysconf_name);
79 if sysconf_name == name {
80 let value = Scalar::from_target_isize(value(this), this);
81 return interp_ok(value);
82 }
83 }
84 throw_unsup_format!("unimplemented sysconf name: {}", name)
85 }
86
87 fn strerror_r(
88 &mut self,
89 errnum: &OpTy<'tcx>,
90 buf: &OpTy<'tcx>,
91 buflen: &OpTy<'tcx>,
92 ) -> InterpResult<'tcx, Scalar> {
93 let this = self.eval_context_mut();
94
95 let errnum = this.read_scalar(errnum)?;
96 let buf = this.read_pointer(buf)?;
97 let buflen = this.read_target_usize(buflen)?;
98 let error = this.try_errnum_to_io_error(errnum)?;
99 let formatted = match error {
100 Some(err) => format!("{err}"),
101 None => format!("<unknown errnum in strerror_r: {errnum}>"),
102 };
103 let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?;
104 if complete {
105 interp_ok(Scalar::from_i32(0))
106 } else {
107 interp_ok(Scalar::from_i32(this.eval_libc_i32("ERANGE")))
108 }
109 }
110
111 fn emulate_foreign_item_inner(
112 &mut self,
113 link_name: Symbol,
114 abi: &FnAbi<'tcx, Ty<'tcx>>,
115 args: &[OpTy<'tcx>],
116 dest: &MPlaceTy<'tcx>,
117 ) -> InterpResult<'tcx, EmulateItemResult> {
118 let this = self.eval_context_mut();
119
120 if this.machine.communicate() {
121 this.poll_and_unblock(Some(Duration::ZERO))?;
128 }
129
130 match link_name.as_str() {
132 "getenv" => {
134 let [name] = this
135 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> *_), (link_name, abi, args))?;
136 let result = this.getenv(name)?;
137 this.write_pointer(result, dest)?;
138 }
139 "unsetenv" => {
140 let [name] = this
141 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
142 let result = this.unsetenv(name)?;
143 this.write_scalar(result, dest)?;
144 }
145 "setenv" => {
146 let [name, value, overwrite] = this.check_shim_sig(
147 shim_sig!(extern "C" fn(*_, *_, i32) -> i32),
148 (link_name, abi, args),
149 )?;
150 this.read_scalar(overwrite)?.to_i32()?;
151 let result = this.setenv(name, value)?;
152 this.write_scalar(result, dest)?;
153 }
154 "getcwd" => {
155 let [buf, size] = this.check_shim_sig(
157 shim_sig!(extern "C" fn(*_, usize) -> *_),
158 (link_name, abi, args),
159 )?;
160 let result = this.getcwd(buf, size)?;
161 this.write_pointer(result, dest)?;
162 }
163 "gethostname" => {
164 let [name, len] = this.check_shim_sig(
165 shim_sig!(extern "C" fn(*_, usize) -> i32),
166 (link_name, abi, args),
167 )?;
168 let result = this.gethostname(name, len)?;
169 this.write_scalar(result, dest)?;
170 }
171 "chdir" => {
172 let [path] = this
174 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
175 let result = this.chdir(path)?;
176 this.write_scalar(result, dest)?;
177 }
178 "getpid" => {
179 let [] = this.check_shim_sig(
180 shim_sig!(extern "C" fn() -> libc::pid_t),
181 (link_name, abi, args),
182 )?;
183 let result = this.getpid()?;
184 this.write_scalar(result, dest)?;
185 }
186 "uname" => {
187 this.check_target_os(
189 &[Os::Linux, Os::Android, Os::MacOs, Os::Solaris, Os::Illumos],
190 link_name,
191 )?;
192
193 let [uname] = this
194 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
195 let result = this.uname(uname, None)?;
196 this.write_scalar(result, dest)?;
197 }
198 "sysconf" => {
199 let [val] = this.check_shim_sig(
200 shim_sig!(extern "C" fn(i32) -> isize),
201 (link_name, abi, args),
202 )?;
203 let result = this.sysconf(val)?;
204 this.write_scalar(result, dest)?;
205 }
206 "read" => {
208 let [fd, buf, count] = this.check_shim_sig(
209 shim_sig!(extern "C" fn(i32, *_, usize) -> isize),
210 (link_name, abi, args),
211 )?;
212 let fd = this.read_scalar(fd)?.to_i32()?;
213 let buf = this.read_pointer(buf)?;
214 let count = this.read_target_usize(count)?;
215 this.read(fd, buf, count, None, dest)?;
216 }
217 "write" => {
218 let [fd, buf, n] = this.check_shim_sig(
219 shim_sig!(extern "C" fn(i32, *_, usize) -> isize),
220 (link_name, abi, args),
221 )?;
222 let fd = this.read_scalar(fd)?.to_i32()?;
223 let buf = this.read_pointer(buf)?;
224 let count = this.read_target_usize(n)?;
225 trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
226 this.write(fd, buf, count, None, dest)?;
227 }
228 "readv" => {
229 let [fd, iov, iovcnt] = this.check_shim_sig(
230 shim_sig!(extern "C" fn(i32, *_, i32) -> isize),
231 (link_name, abi, args),
232 )?;
233 this.readv(fd, iov, iovcnt, None, dest)?;
234 }
235 "writev" => {
236 let [fd, iov, iovcnt] = this.check_shim_sig(
237 shim_sig!(extern "C" fn(i32, *_, i32) -> isize),
238 (link_name, abi, args),
239 )?;
240 this.writev(fd, iov, iovcnt, None, dest)?;
241 }
242 "pread" => {
243 let [fd, buf, count, offset] = this.check_shim_sig(
244 shim_sig!(extern "C" fn(i32, *_, usize, libc::off_t) -> isize),
245 (link_name, abi, args),
246 )?;
247 let fd = this.read_scalar(fd)?.to_i32()?;
248 let buf = this.read_pointer(buf)?;
249 let count = this.read_target_usize(count)?;
250 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
251 this.read(fd, buf, count, Some(offset), dest)?;
252 }
253 "pwrite" => {
254 let [fd, buf, n, offset] = this.check_shim_sig(
255 shim_sig!(extern "C" fn(i32, *_, usize, libc::off_t) -> isize),
256 (link_name, abi, 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 pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
263 this.write(fd, buf, count, Some(offset), dest)?;
264 }
265 "preadv" => {
266 let [fd, iov, iovcnt, offset] = this.check_shim_sig(
267 shim_sig!(extern "C" fn(i32, *_, i32, libc::off_t) -> isize),
268 (link_name, abi, args),
269 )?;
270 this.readv(fd, iov, iovcnt, Some(offset), dest)?;
271 }
272 "pwritev" => {
273 let [fd, iov, iovcnt, offset] = this.check_shim_sig(
274 shim_sig!(extern "C" fn(i32, *_, i32, libc::off_t) -> isize),
275 (link_name, abi, args),
276 )?;
277 this.writev(fd, iov, iovcnt, Some(offset), dest)?;
278 }
279
280 "close" => {
281 let [fd] = this
282 .check_shim_sig(shim_sig!(extern "C" fn(i32) -> i32), (link_name, abi, args))?;
283 let fd = this.read_scalar(fd)?.to_i32()?;
284 let result = this.close(fd)?;
285 this.write_scalar(result, dest)?;
286 }
287 "fcntl" => {
288 let ([fd_num, cmd], varargs) = this.check_shim_sig_variadic(
289 shim_sig!(extern "C" fn(i32, i32, ...) -> i32),
290 (link_name, abi, args),
291 )?;
292 let result = this.fcntl(fd_num, cmd, varargs)?;
293 this.write_scalar(result, dest)?;
294 }
295 "dup" => {
296 let [old_fd] = this
297 .check_shim_sig(shim_sig!(extern "C" fn(i32) -> i32), (link_name, abi, args))?;
298 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
299 let new_fd = this.dup(old_fd)?;
300 this.write_scalar(new_fd, dest)?;
301 }
302 "dup2" => {
303 let [old_fd, new_fd] = this.check_shim_sig(
304 shim_sig!(extern "C" fn(i32, i32) -> i32),
305 (link_name, abi, args),
306 )?;
307 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
308 let new_fd = this.read_scalar(new_fd)?.to_i32()?;
309 let result = this.dup2(old_fd, new_fd)?;
310 this.write_scalar(result, dest)?;
311 }
312 "flock" => {
313 this.check_target_os(
315 &[Os::Linux, Os::Android, Os::FreeBsd, Os::MacOs, Os::Illumos],
316 link_name,
317 )?;
318
319 let [fd, op] = this.check_shim_sig(
320 shim_sig!(extern "C" fn(i32, i32) -> i32),
321 (link_name, abi, args),
322 )?;
323 let fd = this.read_scalar(fd)?.to_i32()?;
324 let op = this.read_scalar(op)?.to_i32()?;
325 let result = this.flock(fd, op)?;
326 this.write_scalar(result, dest)?;
327 }
328 "ioctl" => {
329 let op_is_ulong = match this.tcx.sess.target.os {
332 Os::FreeBsd | Os::NetBsd | Os::MacOs => true,
333 Os::Linux if this.tcx.sess.target.env == Env::Gnu => true,
334 _ => false,
335 };
336 let ([fd, op], varargs) = this.check_shim_sig_variadic(
337 if op_is_ulong {
338 shim_sig!(extern "C" fn(i32, usize, ...) -> i32)
339 } else {
340 shim_sig!(extern "C" fn(i32, i32, ...) -> i32)
341 },
342 (link_name, abi, args),
343 )?;
344 let result = this.ioctl(fd, op, varargs)?;
345 this.write_scalar(result, dest)?;
346 }
347
348 "open" => {
350 let ([path_raw, flag], varargs) = this.check_shim_sig_variadic(
353 shim_sig!(extern "C" fn(*_, i32, ...) -> i32),
354 (link_name, abi, args),
355 )?;
356 let result = this.open(path_raw, flag, varargs)?;
357 this.write_scalar(result, dest)?;
358 }
359 "unlink" => {
360 let [path] = this
362 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
363 let result = this.unlink(path)?;
364 this.write_scalar(result, dest)?;
365 }
366 "symlink" => {
367 let [target, linkpath] = this.check_shim_sig(
369 shim_sig!(extern "C" fn(*_, *_) -> i32),
370 (link_name, abi, args),
371 )?;
372 let result = this.symlink(target, linkpath)?;
373 this.write_scalar(result, dest)?;
374 }
375 "linkat" => {
376 let [oldfd, oldpath, newfd, newpath, flags] = this.check_shim_sig(
377 shim_sig!(extern "C" fn(i32, *_, i32, *_, i32) -> i32),
378 (link_name, abi, args),
379 )?;
380 let result = this.linkat(oldfd, oldpath, newfd, newpath, flags)?;
381 this.write_scalar(result, dest)?;
382 }
383 "fstat" => {
384 let [fd, buf] = this.check_shim_sig(
385 shim_sig!(extern "C" fn(i32, *_) -> i32),
386 (link_name, abi, args),
387 )?;
388 let result = this.fstat(fd, buf)?;
389 this.write_scalar(result, dest)?;
390 }
391 "lstat" => {
392 let [path, buf] = this.check_shim_sig(
393 shim_sig!(extern "C" fn(*_, *_) -> i32),
394 (link_name, abi, args),
395 )?;
396 let result = this.lstat(path, buf)?;
397 this.write_scalar(result, dest)?;
398 }
399 "stat" => {
400 let [path, buf] = this.check_shim_sig(
401 shim_sig!(extern "C" fn(*_, *_) -> i32),
402 (link_name, abi, args),
403 )?;
404 let result = this.stat(path, buf)?;
405 this.write_scalar(result, dest)?;
406 }
407 "chmod" => {
408 let [path, mode] = this.check_shim_sig(
409 shim_sig!(extern "C" fn(*_, libc::mode_t) -> i32),
410 (link_name, abi, args),
411 )?;
412 let result = this.chmod(path, mode)?;
413 this.write_scalar(result, dest)?;
414 }
415 "fchmod" => {
416 let [fd, mode] = this.check_shim_sig(
417 shim_sig!(extern "C" fn(i32, libc::mode_t) -> i32),
418 (link_name, abi, args),
419 )?;
420 let result = this.fchmod(fd, mode)?;
421 this.write_scalar(result, dest)?;
422 }
423 "rename" => {
424 let [oldpath, newpath] = this.check_shim_sig(
426 shim_sig!(extern "C" fn(*_, *_) -> i32),
427 (link_name, abi, args),
428 )?;
429 let result = this.rename(oldpath, newpath)?;
430 this.write_scalar(result, dest)?;
431 }
432 "mkdir" => {
433 let [path, mode] = this.check_shim_sig(
435 shim_sig!(extern "C" fn(*_, libc::mode_t) -> i32),
436 (link_name, abi, args),
437 )?;
438 let result = this.mkdir(path, mode)?;
439 this.write_scalar(result, dest)?;
440 }
441 "rmdir" => {
442 let [path] = this
444 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
445 let result = this.rmdir(path)?;
446 this.write_scalar(result, dest)?;
447 }
448 "opendir" => {
449 let [name] = this
450 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> *_), (link_name, abi, args))?;
451 let result = this.opendir(name)?;
452 this.write_scalar(result, dest)?;
453 }
454 "closedir" => {
455 let [dirp] = this
456 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
457 let result = this.closedir(dirp)?;
458 this.write_scalar(result, dest)?;
459 }
460 "readdir" => {
461 let [dirp] = this
462 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> *_), (link_name, abi, args))?;
463 this.readdir(dirp, dest)?;
464 }
465 "lseek" => {
466 let [fd, offset, whence] = this.check_shim_sig(
468 shim_sig!(extern "C" fn(i32, libc::off_t, i32) -> libc::off_t),
469 (link_name, abi, args),
470 )?;
471 let fd = this.read_scalar(fd)?.to_i32()?;
472 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
473 let whence = this.read_scalar(whence)?.to_i32()?;
474 this.lseek(fd, offset, whence, dest)?;
475 }
476 "ftruncate" => {
477 let [fd, length] = this.check_shim_sig(
478 shim_sig!(extern "C" fn(i32, libc::off_t) -> i32),
479 (link_name, abi, args),
480 )?;
481 let fd = this.read_scalar(fd)?.to_i32()?;
482 let length = this.read_scalar(length)?.to_int(length.layout.size)?;
483 let result = this.ftruncate64(fd, length)?;
484 this.write_scalar(result, dest)?;
485 }
486 "fsync" => {
487 let [fd] = this
489 .check_shim_sig(shim_sig!(extern "C" fn(i32) -> i32), (link_name, abi, args))?;
490 let result = this.fsync(fd)?;
491 this.write_scalar(result, dest)?;
492 }
493 "fdatasync" => {
494 let [fd] = this
496 .check_shim_sig(shim_sig!(extern "C" fn(i32) -> i32), (link_name, abi, args))?;
497 let result = this.fdatasync(fd)?;
498 this.write_scalar(result, dest)?;
499 }
500 "futimens" => {
501 let [fd, times] = this.check_shim_sig(
502 shim_sig!(extern "C" fn(i32, *_) -> i32),
503 (link_name, abi, args),
504 )?;
505 let result = this.futimens(fd, times)?;
506 this.write_scalar(result, dest)?;
507 }
508 "readlink" => {
509 let [pathname, buf, bufsize] = this.check_shim_sig(
510 shim_sig!(extern "C" fn(*_, *_, usize) -> isize),
511 (link_name, abi, args),
512 )?;
513 let result = this.readlink(pathname, buf, bufsize)?;
514 this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
515 }
516 "posix_fadvise" => {
517 let [fd, offset, len, advice] = this.check_shim_sig(
518 shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t, i32) -> i32),
519 (link_name, abi, args),
520 )?;
521 this.read_scalar(fd)?.to_i32()?;
522 this.read_scalar(offset)?.to_int(offset.layout.size)?;
523 this.read_scalar(len)?.to_int(len.layout.size)?;
524 this.read_scalar(advice)?.to_i32()?;
525 this.write_null(dest)?;
527 }
528
529 "posix_fallocate" => {
530 this.check_target_os(
532 &[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos, Os::Android],
533 link_name,
534 )?;
535
536 let [fd, offset, len] = this.check_shim_sig(
537 shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t) -> i32),
538 (link_name, abi, args),
539 )?;
540
541 let fd = this.read_scalar(fd)?.to_i32()?;
542 let offset =
544 i64::try_from(this.read_scalar(offset)?.to_int(offset.layout.size)?).unwrap();
545 let len = i64::try_from(this.read_scalar(len)?.to_int(len.layout.size)?).unwrap();
546
547 let result = this.posix_fallocate(fd, offset, len)?;
548 this.write_scalar(result, dest)?;
549 }
550
551 "realpath" => {
552 let [path, resolved_path] = this.check_shim_sig(
553 shim_sig!(extern "C" fn(*_, *_) -> *_),
554 (link_name, abi, args),
555 )?;
556 let result = this.realpath(path, resolved_path)?;
557 this.write_scalar(result, dest)?;
558 }
559 "mkstemp" => {
560 let [template] = this
561 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
562 let result = this.mkstemp(template)?;
563 this.write_scalar(result, dest)?;
564 }
565
566 "poll" => {
568 let [fds, nfds, timeout] = this.check_shim_sig(
569 shim_sig!(extern "C" fn(*_, libc::nfds_t, i32) -> i32),
570 (link_name, abi, args),
571 )?;
572 this.poll(fds, nfds, timeout, dest)?;
573 }
574
575 "socketpair" => {
577 let [domain, type_, protocol, sv] = this.check_shim_sig(
578 shim_sig!(extern "C" fn(i32, i32, i32, *_) -> i32),
579 (link_name, abi, args),
580 )?;
581 let result = this.socketpair(domain, type_, protocol, sv)?;
582 this.write_scalar(result, dest)?;
583 }
584 "pipe" => {
585 let [pipefd] = this
586 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
587 let result = this.pipe2(pipefd, None)?;
588 this.write_scalar(result, dest)?;
589 }
590 "pipe2" => {
591 this.check_target_os(
593 &[Os::Linux, Os::Android, Os::FreeBsd, Os::Solaris, Os::Illumos],
594 link_name,
595 )?;
596
597 let [pipefd, flags] = this.check_shim_sig(
598 shim_sig!(extern "C" fn(*_, i32) -> i32),
599 (link_name, abi, args),
600 )?;
601 let result = this.pipe2(pipefd, Some(flags))?;
602 this.write_scalar(result, dest)?;
603 }
604
605 "socket" => {
607 let [domain, type_, protocol] = this.check_shim_sig(
608 shim_sig!(extern "C" fn(i32, i32, i32) -> i32),
609 (link_name, abi, args),
610 )?;
611 let result = this.socket(domain, type_, protocol)?;
612 this.write_scalar(result, dest)?;
613 }
614 "bind" => {
615 let [socket, address, address_len] = this.check_shim_sig(
616 shim_sig!(extern "C" fn(i32, *_, libc::socklen_t) -> i32),
617 (link_name, abi, args),
618 )?;
619 let result = this.bind(socket, address, address_len)?;
620 this.write_scalar(result, dest)?;
621 }
622 "listen" => {
623 let [socket, backlog] = this.check_shim_sig(
624 shim_sig!(extern "C" fn(i32, i32) -> i32),
625 (link_name, abi, args),
626 )?;
627 let result = this.listen(socket, backlog)?;
628 this.write_scalar(result, dest)?;
629 }
630 "accept" => {
631 let [socket, address, address_len] = this.check_shim_sig(
632 shim_sig!(extern "C" fn(i32, *_, *_) -> i32),
633 (link_name, abi, args),
634 )?;
635 this.accept4(socket, address, address_len, None, dest)?;
636 }
637 "accept4" => {
638 let [socket, address, address_len, flags] = this.check_shim_sig(
639 shim_sig!(extern "C" fn(i32, *_, *_, i32) -> i32),
640 (link_name, abi, args),
641 )?;
642 this.accept4(socket, address, address_len, Some(flags), dest)?;
643 }
644 "connect" => {
645 let [socket, address, address_len] = this.check_shim_sig(
646 shim_sig!(extern "C" fn(i32, *_, libc::socklen_t) -> i32),
647 (link_name, abi, args),
648 )?;
649 this.connect(socket, address, address_len, dest)?;
650 }
651 "send" => {
652 let [socket, buffer, length, flags] = this.check_shim_sig(
653 shim_sig!(extern "C" fn(i32, *_, libc::size_t, i32) -> libc::ssize_t),
654 (link_name, abi, args),
655 )?;
656 this.send(socket, buffer, length, flags, dest)?;
657 }
658 "recv" => {
659 let [socket, buffer, length, flags] = this.check_shim_sig(
660 shim_sig!(extern "C" fn(i32, *_, libc::size_t, i32) -> libc::ssize_t),
661 (link_name, abi, args),
662 )?;
663 this.recv(socket, buffer, length, flags, dest)?;
664 }
665 "setsockopt" => {
666 let [socket, level, option_name, option_value, option_len] = this.check_shim_sig(
667 shim_sig!(extern "C" fn(i32, i32, i32, *_, libc::socklen_t) -> i32),
668 (link_name, abi, args),
669 )?;
670 let result =
671 this.setsockopt(socket, level, option_name, option_value, option_len)?;
672 this.write_scalar(result, dest)?;
673 }
674 "getsockopt" => {
675 let [socket, level, option_name, option_value, option_len] = this.check_shim_sig(
676 shim_sig!(extern "C" fn(i32, i32, i32, *_, *_) -> i32),
677 (link_name, abi, args),
678 )?;
679 let result =
680 this.getsockopt(socket, level, option_name, option_value, option_len)?;
681 this.write_scalar(result, dest)?;
682 }
683 "getsockname" => {
684 let [socket, address, address_len] = this.check_shim_sig(
685 shim_sig!(extern "C" fn(i32, *_, *_) -> i32),
686 (link_name, abi, args),
687 )?;
688 let result = this.getsockname(socket, address, address_len)?;
689 this.write_scalar(result, dest)?;
690 }
691 "getpeername" => {
692 let [socket, address, address_len] = this.check_shim_sig(
693 shim_sig!(extern "C" fn(i32, *_, *_) -> i32),
694 (link_name, abi, args),
695 )?;
696 this.getpeername(socket, address, address_len, dest)?;
697 }
698 "shutdown" => {
699 let [sockfd, how] = this.check_shim_sig(
700 shim_sig!(extern "C" fn(i32, i32) -> i32),
701 (link_name, abi, args),
702 )?;
703 let result = this.shutdown(sockfd, how)?;
704 this.write_scalar(result, dest)?;
705 }
706 "getaddrinfo" => {
707 let [node, service, hints, res] = this.check_shim_sig(
708 shim_sig!(extern "C" fn(*_, *_, *_, *_) -> i32),
709 (link_name, abi, args),
710 )?;
711 let result = this.getaddrinfo(node, service, hints, res)?;
712 this.write_scalar(result, dest)?;
713 }
714 "freeaddrinfo" => {
715 let [res] = this
716 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> ()), (link_name, abi, args))?;
717 this.freeaddrinfo(res)?;
718 }
719
720 "gettimeofday" => {
722 let [tv, tz] = this.check_shim_sig(
723 shim_sig!(extern "C" fn(*_, *_) -> i32),
724 (link_name, abi, args),
725 )?;
726 let result = this.gettimeofday(tv, tz)?;
727 this.write_scalar(result, dest)?;
728 }
729 "localtime_r" => {
730 let [timep, result_op] = this.check_shim_sig(
731 shim_sig!(extern "C" fn(*_, *_) -> *_),
732 (link_name, abi, args),
733 )?;
734 let result = this.localtime_r(timep, result_op)?;
735 this.write_pointer(result, dest)?;
736 }
737 "clock_gettime" => {
738 let [clk_id, tp] = this.check_shim_sig(
739 shim_sig!(extern "C" fn(libc::clockid_t, *_) -> i32),
740 (link_name, abi, args),
741 )?;
742 this.clock_gettime(clk_id, tp, dest)?;
743 }
744
745 "posix_memalign" => {
747 let [memptr, align, size] = this.check_shim_sig(
748 shim_sig!(extern "C" fn(*_, usize, usize) -> i32),
749 (link_name, abi, args),
750 )?;
751 let result = this.posix_memalign(memptr, align, size)?;
752 this.write_scalar(result, dest)?;
753 }
754
755 "mmap" => {
756 let [addr, length, prot, flags, fd, offset] = this.check_shim_sig(
757 shim_sig!(extern "C" fn(*_, usize, i32, i32, i32, libc::off_t) -> *_),
758 (link_name, abi, args),
759 )?;
760 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
761 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
762 this.write_scalar(ptr, dest)?;
763 }
764 "munmap" => {
765 let [addr, length] = this.check_shim_sig(
766 shim_sig!(extern "C" fn(*_, usize) -> i32),
767 (link_name, abi, args),
768 )?;
769 let result = this.munmap(addr, length)?;
770 this.write_scalar(result, dest)?;
771 }
772 "mprotect" => {
773 let [addr, length, prot] = this.check_shim_sig(
774 shim_sig!(extern "C" fn(*_, usize, i32) -> i32),
775 (link_name, abi, args),
776 )?;
777 let result = this.mprotect(addr, length, prot)?;
778 this.write_scalar(result, dest)?;
779 }
780 "madvise" => {
781 let [addr, length, advice] = this.check_shim_sig(
782 shim_sig!(extern "C" fn(*_, usize, i32) -> i32),
783 (link_name, abi, args),
784 )?;
785 let result = this.madvise(addr, length, advice)?;
786 this.write_scalar(result, dest)?;
787 }
788
789 "reallocarray" => {
790 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
792
793 let [ptr, nmemb, size] = this.check_shim_sig(
794 shim_sig!(extern "C" fn(*_, usize, usize) -> *_),
795 (link_name, abi, args),
796 )?;
797 let ptr = this.read_pointer(ptr)?;
798 let nmemb = this.read_target_usize(nmemb)?;
799 let size = this.read_target_usize(size)?;
800 match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
806 None => {
807 this.set_last_error(LibcError("ENOMEM"))?;
808 this.write_null(dest)?;
809 }
810 Some(len) => {
811 let res = this.realloc(ptr, len.bytes())?;
812 this.write_pointer(res, dest)?;
813 }
814 }
815 }
816 "aligned_alloc" => {
817 let [align, size] = this.check_shim_sig(
820 shim_sig!(extern "C" fn(usize, usize) -> *_),
821 (link_name, abi, args),
822 )?;
823 let res = this.aligned_alloc(align, size)?;
824 this.write_pointer(res, dest)?;
825 }
826
827 "dlsym" => {
829 let [handle, symbol] = this.check_shim_sig(
830 shim_sig!(extern "C" fn(*_, *_) -> *_),
831 (link_name, abi, args),
832 )?;
833 this.read_target_usize(handle)?;
834 let symbol = this.read_pointer(symbol)?;
835 let name = this.read_c_str(symbol)?;
836 let Ok(name) = str::from_utf8(name) else {
837 throw_unsup_format!("dlsym: non UTF-8 symbol name not supported")
838 };
839 if is_dyn_sym(name, &this.tcx.sess.target.os) {
840 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
841 this.write_pointer(ptr, dest)?;
842 } else if let Some(&ptr) = this.machine.extern_statics.get(&Symbol::intern(name)) {
843 this.write_pointer(ptr, dest)?;
844 } else {
845 this.write_null(dest)?;
846 }
847 }
848
849 "pthread_key_create" => {
851 let [key, dtor] = this.check_shim_sig(
852 shim_sig!(extern "C" fn(*_, fn(..) -> _) -> i32),
853 (link_name, abi, args),
854 )?;
855 let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
856 let dtor = this.read_pointer(dtor)?;
857
858 let dtor = if !this.ptr_is_null(dtor)? {
860 Some((
861 this.get_ptr_fn(dtor)?.as_instance()?,
862 this.machine.current_user_relevant_span(),
863 ))
864 } else {
865 None
866 };
867
868 let key_type = key.layout.ty
871 .builtin_deref(true)
872 .ok_or_else(|| err_ub_format!(
873 "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
874 ))?;
875 let key_layout = this.layout_of(key_type)?;
876
877 let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
879 this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place)?;
880
881 this.write_null(dest)?;
883 }
884 "pthread_key_delete" => {
885 let [key] = this.check_shim_sig(
887 shim_sig!(extern "C" fn(libc::pthread_key_t) -> i32),
888 (link_name, abi, args),
889 )?;
890 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
891 this.machine.tls.delete_tls_key(key)?;
892 this.write_null(dest)?;
894 }
895 "pthread_getspecific" => {
896 let [key] = this.check_shim_sig(
898 shim_sig!(extern "C" fn(libc::pthread_key_t) -> *_),
899 (link_name, abi, args),
900 )?;
901 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
902 let active_thread = this.active_thread();
903 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
904 this.write_scalar(ptr, dest)?;
905 }
906 "pthread_setspecific" => {
907 let [key, new_ptr] = this.check_shim_sig(
908 shim_sig!(extern "C" fn(libc::pthread_key_t, *_) -> i32),
909 (link_name, abi, args),
910 )?;
911 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
912 let active_thread = this.active_thread();
913 let new_data = this.read_scalar(new_ptr)?;
914 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
915
916 this.write_null(dest)?;
918 }
919
920 "pthread_mutexattr_init" => {
922 let [attr] = this
923 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
924 this.pthread_mutexattr_init(attr)?;
925 this.write_null(dest)?;
926 }
927 "pthread_mutexattr_settype" => {
928 let [attr, kind] = this.check_shim_sig(
929 shim_sig!(extern "C" fn(*_, i32) -> i32),
930 (link_name, abi, args),
931 )?;
932 let result = this.pthread_mutexattr_settype(attr, kind)?;
933 this.write_scalar(result, dest)?;
934 }
935 "pthread_mutexattr_destroy" => {
936 let [attr] = this
937 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
938 this.pthread_mutexattr_destroy(attr)?;
939 this.write_null(dest)?;
940 }
941 "pthread_mutex_init" => {
942 let [mutex, attr] = this.check_shim_sig(
943 shim_sig!(extern "C" fn(*_, *_) -> i32),
944 (link_name, abi, args),
945 )?;
946 this.pthread_mutex_init(mutex, attr)?;
947 this.write_null(dest)?;
948 }
949 "pthread_mutex_lock" => {
950 let [mutex] = this
951 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
952 this.pthread_mutex_lock(mutex, dest)?;
953 }
954 "pthread_mutex_trylock" => {
955 let [mutex] = this
956 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
957 let result = this.pthread_mutex_trylock(mutex)?;
958 this.write_scalar(result, dest)?;
959 }
960 "pthread_mutex_unlock" => {
961 let [mutex] = this
962 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
963 let result = this.pthread_mutex_unlock(mutex)?;
964 this.write_scalar(result, dest)?;
965 }
966 "pthread_mutex_destroy" => {
967 let [mutex] = this
968 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
969 this.pthread_mutex_destroy(mutex)?;
970 this.write_int(0, dest)?;
971 }
972 "pthread_rwlock_rdlock" => {
973 let [rwlock] = this
974 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
975 this.pthread_rwlock_rdlock(rwlock, dest)?;
976 }
977 "pthread_rwlock_tryrdlock" => {
978 let [rwlock] = this
979 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
980 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
981 this.write_scalar(result, dest)?;
982 }
983 "pthread_rwlock_wrlock" => {
984 let [rwlock] = this
985 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
986 this.pthread_rwlock_wrlock(rwlock, dest)?;
987 }
988 "pthread_rwlock_trywrlock" => {
989 let [rwlock] = this
990 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
991 let result = this.pthread_rwlock_trywrlock(rwlock)?;
992 this.write_scalar(result, dest)?;
993 }
994 "pthread_rwlock_unlock" => {
995 let [rwlock] = this
996 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
997 this.pthread_rwlock_unlock(rwlock)?;
998 this.write_null(dest)?;
999 }
1000 "pthread_rwlock_destroy" => {
1001 let [rwlock] = this
1002 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
1003 this.pthread_rwlock_destroy(rwlock)?;
1004 this.write_null(dest)?;
1005 }
1006 "pthread_condattr_init" => {
1007 let [attr] = this
1008 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
1009 this.pthread_condattr_init(attr)?;
1010 this.write_null(dest)?;
1011 }
1012 "pthread_condattr_setclock" => {
1013 let [attr, clock_id] = this.check_shim_sig(
1014 shim_sig!(extern "C" fn(*_, i32) -> i32),
1015 (link_name, abi, args),
1016 )?;
1017 let result = this.pthread_condattr_setclock(attr, clock_id)?;
1018 this.write_scalar(result, dest)?;
1019 }
1020 "pthread_condattr_getclock" => {
1021 let [attr, clock_id] = this.check_shim_sig(
1022 shim_sig!(extern "C" fn(*_, *_) -> i32),
1023 (link_name, abi, args),
1024 )?;
1025 this.pthread_condattr_getclock(attr, clock_id)?;
1026 this.write_null(dest)?;
1027 }
1028 "pthread_condattr_destroy" => {
1029 let [attr] = this
1030 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
1031 this.pthread_condattr_destroy(attr)?;
1032 this.write_null(dest)?;
1033 }
1034 "pthread_cond_init" => {
1035 let [cond, attr] = this.check_shim_sig(
1036 shim_sig!(extern "C" fn(*_, *_) -> i32),
1037 (link_name, abi, args),
1038 )?;
1039 this.pthread_cond_init(cond, attr)?;
1040 this.write_null(dest)?;
1041 }
1042 "pthread_cond_signal" => {
1043 let [cond] = this
1044 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
1045 this.pthread_cond_signal(cond)?;
1046 this.write_null(dest)?;
1047 }
1048 "pthread_cond_broadcast" => {
1049 let [cond] = this
1050 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
1051 this.pthread_cond_broadcast(cond)?;
1052 this.write_null(dest)?;
1053 }
1054 "pthread_cond_wait" => {
1055 let [cond, mutex] = this.check_shim_sig(
1056 shim_sig!(extern "C" fn(*_, *_) -> i32),
1057 (link_name, abi, args),
1058 )?;
1059 this.pthread_cond_wait(cond, mutex, dest)?;
1060 }
1061 "pthread_cond_timedwait" => {
1062 let [cond, mutex, abstime] = this.check_shim_sig(
1063 shim_sig!(extern "C" fn(*_, *_, *_) -> i32),
1064 (link_name, abi, args),
1065 )?;
1066 this.pthread_cond_timedwait(
1067 cond, mutex, abstime, dest, false,
1068 )?;
1069 }
1070 "pthread_cond_destroy" => {
1071 let [cond] = this
1072 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), (link_name, abi, args))?;
1073 this.pthread_cond_destroy(cond)?;
1074 this.write_null(dest)?;
1075 }
1076
1077 "pthread_create" => {
1079 let [thread, attr, start, arg] = this.check_shim_sig(
1080 shim_sig!(extern "C" fn(*_, *_, fn(..) -> _, *_) -> i32),
1081 (link_name, abi, args),
1082 )?;
1083 this.pthread_create(thread, attr, start, arg)?;
1084 this.write_null(dest)?;
1085 }
1086 "pthread_join" => {
1087 let [thread, retval] = this.check_shim_sig(
1088 shim_sig!(extern "C" fn(libc::pthread_t, *_) -> i32),
1089 (link_name, abi, args),
1090 )?;
1091 this.pthread_join(thread, retval, dest)?;
1092 }
1093 "pthread_detach" => {
1094 let [thread] = this.check_shim_sig(
1095 shim_sig!(extern "C" fn(libc::pthread_t) -> i32),
1096 (link_name, abi, args),
1097 )?;
1098 let res = this.pthread_detach(thread)?;
1099 this.write_scalar(res, dest)?;
1100 }
1101 "pthread_self" => {
1102 let [] = this.check_shim_sig(
1103 shim_sig!(extern "C" fn() -> libc::pthread_t),
1104 (link_name, abi, args),
1105 )?;
1106 let res = this.pthread_self()?;
1107 this.write_scalar(res, dest)?;
1108 }
1109 "sched_yield" => {
1110 let [] =
1112 this.check_shim_sig(shim_sig!(extern "C" fn() -> i32), (link_name, abi, args))?;
1113 this.sched_yield()?;
1114 this.write_null(dest)?;
1115 }
1116 "nanosleep" => {
1117 let [duration, rem] = this.check_shim_sig(
1118 shim_sig!(extern "C" fn(*_, *_) -> i32),
1119 (link_name, abi, args),
1120 )?;
1121 let result = this.nanosleep(duration, rem)?;
1122 this.write_scalar(result, dest)?;
1123 }
1124 "clock_nanosleep" => {
1125 this.check_target_os(
1127 &[Os::FreeBsd, Os::Linux, Os::Android, Os::Solaris, Os::Illumos],
1128 link_name,
1129 )?;
1130
1131 let [clock_id, flags, req, rem] = this.check_shim_sig(
1132 shim_sig!(extern "C" fn(libc::clockid_t, i32, *_, *_) -> i32),
1133 (link_name, abi, args),
1134 )?;
1135 let result = this.clock_nanosleep(clock_id, flags, req, rem)?;
1136 this.write_scalar(result, dest)?;
1137 }
1138 "sched_getaffinity" => {
1139 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
1141
1142 let [pid, cpusetsize, mask] = this.check_shim_sig(
1143 shim_sig!(extern "C" fn(libc::pid_t, usize, *_) -> i32),
1144 (link_name, abi, args),
1145 )?;
1146 let pid = this.read_scalar(pid)?.to_u32()?;
1147 let cpusetsize = this.read_target_usize(cpusetsize)?;
1148 let mask = this.read_pointer(mask)?;
1149
1150 if this.machine.thread_cpu_affinity.is_none() {
1151 throw_unsup_format!(
1152 "`sched_getaffinity` is not supported on #![no_core] programs"
1153 )
1154 }
1155
1156 let thread_id = if pid == 0 {
1157 this.active_thread()
1158 } else if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android) {
1159 let Some(thread_id) = this.get_thread_id_from_linux_tid(pid) else {
1161 this.set_errno_and_return_neg1(LibcError("ESRCH"), dest)?;
1162 return interp_ok(EmulateItemResult::NeedsReturn);
1163 };
1164 thread_id
1165 } else {
1166 throw_unsup_format!(
1167 "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread) on non-Linux platforms"
1168 )
1169 };
1170
1171 let chunk_size = CpuAffinityMask::chunk_size(this);
1173
1174 if this.ptr_is_null(mask)? {
1175 this.set_errno_and_return_neg1(LibcError("EFAULT"), dest)?;
1176 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
1177 this.set_errno_and_return_neg1(LibcError("EINVAL"), dest)?;
1179 } else if let Some(cpuset) =
1180 this.machine.thread_cpu_affinity.as_ref().unwrap().get(&thread_id)
1181 {
1182 let cpuset = cpuset.clone();
1183 let byte_count =
1185 Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
1186 this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
1187 this.write_null(dest)?;
1188 } else {
1189 this.set_errno_and_return_neg1(LibcError("ESRCH"), dest)?;
1191 }
1192 }
1193 "sched_setaffinity" => {
1194 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
1196
1197 let [pid, cpusetsize, mask] = this.check_shim_sig(
1198 shim_sig!(extern "C" fn(libc::pid_t, usize, *_) -> i32),
1199 (link_name, abi, args),
1200 )?;
1201 let pid = this.read_scalar(pid)?.to_u32()?;
1202 let cpusetsize = this.read_target_usize(cpusetsize)?;
1203 let mask = this.read_pointer(mask)?;
1204
1205 if this.machine.thread_cpu_affinity.is_none() {
1206 throw_unsup_format!(
1207 "`sched_setaffinity` is not supported on #![no_core] programs"
1208 )
1209 }
1210
1211 let thread_id = if pid == 0 {
1212 this.active_thread()
1213 } else if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android) {
1214 let Some(thread_id) = this.get_thread_id_from_linux_tid(pid) else {
1216 this.set_errno_and_return_neg1(LibcError("ESRCH"), dest)?;
1217 return interp_ok(EmulateItemResult::NeedsReturn);
1218 };
1219 thread_id
1220 } else {
1221 throw_unsup_format!(
1222 "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread) on non-Linux platforms"
1223 )
1224 };
1225
1226 if this.ptr_is_null(mask)? {
1227 this.set_errno_and_return_neg1(LibcError("EFAULT"), dest)?;
1228 } else {
1229 let bits_slice =
1233 this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
1234 let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
1236 std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
1237 match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
1238 Some(cpuset) => {
1239 this.machine
1240 .thread_cpu_affinity
1241 .as_mut()
1242 .unwrap()
1243 .insert(thread_id, cpuset);
1244 this.write_null(dest)?;
1245 }
1246 None => {
1247 this.set_errno_and_return_neg1(LibcError("EINVAL"), dest)?;
1249 }
1250 }
1251 }
1252 }
1253
1254 "isatty" => {
1256 let [fd] = this
1257 .check_shim_sig(shim_sig!(extern "C" fn(i32) -> i32), (link_name, abi, args))?;
1258 let result = this.isatty(fd)?;
1259 this.write_scalar(result, dest)?;
1260 }
1261 "pthread_atfork" => {
1262 let [prepare, parent, child] = this.check_shim_sig(
1264 shim_sig!(extern "C" fn(fn(..) -> _, fn(..) -> _, fn(..) -> _) -> i32),
1265 (link_name, abi, args),
1266 )?;
1267 this.read_pointer(prepare)?;
1268 this.read_pointer(parent)?;
1269 this.read_pointer(child)?;
1270 this.write_null(dest)?;
1272 }
1273 "strerror_r" => {
1274 let [errnum, buf, buflen] = this.check_shim_sig(
1275 shim_sig!(extern "C" fn(i32, *_, usize) -> i32),
1276 (link_name, abi, args),
1277 )?;
1278 let result = this.strerror_r(errnum, buf, buflen)?;
1279 this.write_scalar(result, dest)?;
1280 }
1281 "getentropy" => {
1282 this.check_target_os(
1285 &[Os::Linux, Os::MacOs, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
1286 link_name,
1287 )?;
1288
1289 let [buf, bufsize] = this.check_shim_sig(
1290 shim_sig!(extern "C" fn(*_, usize) -> i32),
1291 (link_name, abi, args),
1292 )?;
1293 let buf = this.read_pointer(buf)?;
1294 let bufsize = this.read_target_usize(bufsize)?;
1295
1296 if bufsize > 256 {
1302 this.set_errno_and_return_neg1(LibcError("EIO"), dest)?;
1303 } else {
1304 this.gen_random(buf, bufsize)?;
1305 this.write_null(dest)?;
1306 }
1307 }
1308 "getrandom" => {
1309 this.check_target_os(
1312 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
1313 link_name,
1314 )?;
1315
1316 let [ptr, len, flags] = this.check_shim_sig(
1317 shim_sig!(extern "C" fn(*_, usize, u32) -> isize),
1318 (link_name, abi, args),
1319 )?;
1320 let ptr = this.read_pointer(ptr)?;
1321 let len = this.read_target_usize(len)?;
1322 let _flags = this.read_scalar(flags)?.to_i32()?;
1323 this.gen_random(ptr, len)?;
1325 this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
1326 }
1327 "arc4random_buf" => {
1328 this.check_target_os(&[Os::FreeBsd, Os::Illumos, Os::Solaris], link_name)?;
1331
1332 let [ptr, len] = this.check_shim_sig(
1333 shim_sig!(extern "C" fn(*_, usize) -> ()),
1334 (link_name, abi, args),
1335 )?;
1336 let ptr = this.read_pointer(ptr)?;
1337 let len = this.read_target_usize(len)?;
1338 this.gen_random(ptr, len)?;
1339 }
1340 "_Unwind_RaiseException" => {
1341 this.check_target_os(
1355 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android, Os::MacOs],
1356 link_name,
1357 )?;
1358
1359 let [payload] = this.check_shim_sig(
1361 shim_sig!(extern "C" fn(*_) -> panic_unwind::imp::uw::_Unwind_Reason_Code),
1364 (link_name, abi, args),
1365 )?;
1366 this.handle_miri_start_unwind(payload)?;
1367 return interp_ok(EmulateItemResult::NeedsUnwind);
1368 }
1369 "getuid" | "geteuid" => {
1370 let [] = this.check_shim_sig(
1371 shim_sig!(extern "C" fn() -> libc::uid_t),
1372 (link_name, abi, args),
1373 )?;
1374 this.write_int(UID, dest)?;
1376 }
1377
1378 "pthread_attr_getguardsize" if this.frame_in_std() => {
1381 let [_attr, guard_size] =
1382 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
1383 let guard_size_layout = this.machine.layouts.usize;
1384 let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
1385 this.write_scalar(
1386 Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
1387 &guard_size,
1388 )?;
1389
1390 this.write_null(dest)?;
1392 }
1393
1394 "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
1395 let [_] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
1396 this.write_null(dest)?;
1397 }
1398 "pthread_attr_setstacksize" if this.frame_in_std() => {
1399 let [_, _] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
1400 this.write_null(dest)?;
1401 }
1402
1403 "pthread_attr_getstack" if this.frame_in_std() => {
1404 let [attr_place, addr_place, size_place] =
1407 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
1408 let _attr_place =
1409 this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
1410 let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?;
1411 let size_place = this.deref_pointer_as(size_place, this.machine.layouts.usize)?;
1412
1413 this.write_scalar(
1414 Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
1415 &addr_place,
1416 )?;
1417 this.write_scalar(
1418 Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
1419 &size_place,
1420 )?;
1421
1422 this.write_null(dest)?;
1424 }
1425
1426 "signal" | "sigaltstack" if this.frame_in_std() => {
1427 let [_, _] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
1428 this.write_null(dest)?;
1429 }
1430 "sigaction" if this.frame_in_std() => {
1431 let [_, _, _] =
1432 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
1433 this.write_null(dest)?;
1434 }
1435
1436 "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
1437 let [uid, pwd, buf, buflen, result] =
1439 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
1440 this.check_no_isolation("`getpwuid_r`")?;
1441
1442 let uid = this.read_scalar(uid)?.to_u32()?;
1443 let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?;
1444 let buf = this.read_pointer(buf)?;
1445 let buflen = this.read_target_usize(buflen)?;
1446 let result = this.deref_pointer_as(result, this.machine.layouts.mut_raw_ptr)?;
1447
1448 if uid != UID {
1450 throw_unsup_format!("`getpwuid_r` on other users is not supported");
1451 }
1452
1453 this.write_uninit(&pwd)?;
1456
1457 #[allow(deprecated)]
1459 let home_dir = std::env::home_dir().unwrap();
1460 let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
1461 let pw_dir = this.project_field_named(&pwd, "pw_dir")?;
1462 this.write_pointer(buf, &pw_dir)?;
1463
1464 if written {
1465 this.write_pointer(pwd.ptr(), &result)?;
1466 this.write_null(dest)?;
1467 } else {
1468 this.write_null(&result)?;
1469 this.write_scalar(this.eval_libc("ERANGE"), dest)?;
1470 }
1471 }
1472
1473 _ => {
1475 let target_os = &this.tcx.sess.target.os;
1476 return match target_os {
1477 Os::Android =>
1478 android::EvalContextExt::emulate_foreign_item_inner(
1479 this, link_name, abi, args, dest,
1480 ),
1481 Os::FreeBsd =>
1482 freebsd::EvalContextExt::emulate_foreign_item_inner(
1483 this, link_name, abi, args, dest,
1484 ),
1485 Os::Linux =>
1486 linux::EvalContextExt::emulate_foreign_item_inner(
1487 this, link_name, abi, args, dest,
1488 ),
1489 Os::MacOs =>
1490 macos::EvalContextExt::emulate_foreign_item_inner(
1491 this, link_name, abi, args, dest,
1492 ),
1493 Os::Solaris | Os::Illumos =>
1494 solarish::EvalContextExt::emulate_foreign_item_inner(
1495 this, link_name, abi, args, dest,
1496 ),
1497 Os::NetBsd =>
1498 netbsd::EvalContextExt::emulate_foreign_item_inner(
1499 this, link_name, abi, args, dest,
1500 ),
1501 _ => interp_ok(EmulateItemResult::NotSupported),
1502 };
1503 }
1504 };
1505
1506 interp_ok(EmulateItemResult::NeedsReturn)
1507 }
1508}