1use std::ffi::OsStr;
2use std::str;
3
4use rustc_abi::{CanonAbi, Size};
5use rustc_middle::ty::Ty;
6use rustc_span::Symbol;
7use rustc_target::callconv::FnAbi;
8use rustc_target::spec::Os;
9
10use self::shims::unix::android::foreign_items as android;
11use self::shims::unix::freebsd::foreign_items as freebsd;
12use self::shims::unix::linux::foreign_items as linux;
13use self::shims::unix::macos::foreign_items as macos;
14use self::shims::unix::solarish::foreign_items as solarish;
15use crate::concurrency::cpu_affinity::CpuAffinityMask;
16use crate::shims::alloc::EvalContextExt as _;
17use crate::shims::unix::*;
18use crate::{shim_sig, *};
19
20pub fn is_dyn_sym(name: &str, target_os: &Os) -> bool {
21 match name {
22 "isatty" => true,
24 "signal" => true,
27 "getentropy" | "getrandom" => true,
29 _ =>
31 match *target_os {
32 Os::Android => android::is_dyn_sym(name),
33 Os::FreeBsd => freebsd::is_dyn_sym(name),
34 Os::Linux => linux::is_dyn_sym(name),
35 Os::MacOs => macos::is_dyn_sym(name),
36 Os::Solaris | Os::Illumos => solarish::is_dyn_sym(name),
37 _ => false,
38 },
39 }
40}
41
42impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
43pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
44 fn sysconf(&mut self, val: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
46 let this = self.eval_context_mut();
47
48 let name = this.read_scalar(val)?.to_i32()?;
49 let sysconfs: &[(&str, fn(&MiriInterpCx<'_>) -> Scalar)] = &[
52 ("_SC_PAGESIZE", |this| Scalar::from_int(this.machine.page_size, this.pointer_size())),
53 ("_SC_PAGE_SIZE", |this| Scalar::from_int(this.machine.page_size, this.pointer_size())),
54 ("_SC_NPROCESSORS_CONF", |this| {
55 Scalar::from_int(this.machine.num_cpus, this.pointer_size())
56 }),
57 ("_SC_NPROCESSORS_ONLN", |this| {
58 Scalar::from_int(this.machine.num_cpus, this.pointer_size())
59 }),
60 ("_SC_GETPW_R_SIZE_MAX", |this| Scalar::from_int(512, this.pointer_size())),
63 ("_SC_OPEN_MAX", |this| Scalar::from_int(2_i32.pow(16), this.pointer_size())),
68 ];
69 for &(sysconf_name, value) in sysconfs {
70 let sysconf_name = this.eval_libc_i32(sysconf_name);
71 if sysconf_name == name {
72 return interp_ok(value(this));
73 }
74 }
75 throw_unsup_format!("unimplemented sysconf name: {}", name)
76 }
77
78 fn strerror_r(
79 &mut self,
80 errnum: &OpTy<'tcx>,
81 buf: &OpTy<'tcx>,
82 buflen: &OpTy<'tcx>,
83 ) -> InterpResult<'tcx, Scalar> {
84 let this = self.eval_context_mut();
85
86 let errnum = this.read_scalar(errnum)?;
87 let buf = this.read_pointer(buf)?;
88 let buflen = this.read_target_usize(buflen)?;
89 let error = this.try_errnum_to_io_error(errnum)?;
90 let formatted = match error {
91 Some(err) => format!("{err}"),
92 None => format!("<unknown errnum in strerror_r: {errnum}>"),
93 };
94 let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?;
95 if complete {
96 interp_ok(Scalar::from_i32(0))
97 } else {
98 interp_ok(Scalar::from_i32(this.eval_libc_i32("ERANGE")))
99 }
100 }
101
102 fn emulate_foreign_item_inner(
103 &mut self,
104 link_name: Symbol,
105 abi: &FnAbi<'tcx, Ty<'tcx>>,
106 args: &[OpTy<'tcx>],
107 dest: &MPlaceTy<'tcx>,
108 ) -> InterpResult<'tcx, EmulateItemResult> {
109 let this = self.eval_context_mut();
110
111 match link_name.as_str() {
113 "getenv" => {
115 let [name] = this.check_shim_sig(
116 shim_sig!(extern "C" fn(*const _) -> *mut _),
117 link_name,
118 abi,
119 args,
120 )?;
121 let result = this.getenv(name)?;
122 this.write_pointer(result, dest)?;
123 }
124 "unsetenv" => {
125 let [name] = this.check_shim_sig(
126 shim_sig!(extern "C" fn(*const _) -> i32),
127 link_name,
128 abi,
129 args,
130 )?;
131 let result = this.unsetenv(name)?;
132 this.write_scalar(result, dest)?;
133 }
134 "setenv" => {
135 let [name, value, overwrite] = this.check_shim_sig(
136 shim_sig!(extern "C" fn(*const _, *const _, i32) -> i32),
137 link_name,
138 abi,
139 args,
140 )?;
141 this.read_scalar(overwrite)?.to_i32()?;
142 let result = this.setenv(name, value)?;
143 this.write_scalar(result, dest)?;
144 }
145 "getcwd" => {
146 let [buf, size] = this.check_shim_sig(
147 shim_sig!(extern "C" fn(*mut _, usize) -> *mut _),
148 link_name,
149 abi,
150 args,
151 )?;
152 let result = this.getcwd(buf, size)?;
153 this.write_pointer(result, dest)?;
154 }
155 "chdir" => {
156 let [path] = this.check_shim_sig(
157 shim_sig!(extern "C" fn(*const _) -> i32),
158 link_name,
159 abi,
160 args,
161 )?;
162 let result = this.chdir(path)?;
163 this.write_scalar(result, dest)?;
164 }
165 "getpid" => {
166 let [] = this.check_shim_sig(
167 shim_sig!(extern "C" fn() -> libc::pid_t),
168 link_name,
169 abi,
170 args,
171 )?;
172 let result = this.getpid()?;
173 this.write_scalar(result, dest)?;
174 }
175 "sysconf" => {
176 let [val] = this.check_shim_sig(
177 shim_sig!(extern "C" fn(i32) -> isize),
178 link_name,
179 abi,
180 args,
181 )?;
182 let result = this.sysconf(val)?;
183 this.write_scalar(result, dest)?;
184 }
185 "read" => {
187 let [fd, buf, count] = this.check_shim_sig(
188 shim_sig!(extern "C" fn(i32, *mut _, usize) -> isize),
189 link_name,
190 abi,
191 args,
192 )?;
193 let fd = this.read_scalar(fd)?.to_i32()?;
194 let buf = this.read_pointer(buf)?;
195 let count = this.read_target_usize(count)?;
196 this.read(fd, buf, count, None, dest)?;
197 }
198 "write" => {
199 let [fd, buf, n] = this.check_shim_sig(
200 shim_sig!(extern "C" fn(i32, *const _, usize) -> isize),
201 link_name,
202 abi,
203 args,
204 )?;
205 let fd = this.read_scalar(fd)?.to_i32()?;
206 let buf = this.read_pointer(buf)?;
207 let count = this.read_target_usize(n)?;
208 trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
209 this.write(fd, buf, count, None, dest)?;
210 }
211 "pread" => {
212 let [fd, buf, count, offset] = this.check_shim_sig(
213 shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off_t) -> isize),
214 link_name,
215 abi,
216 args,
217 )?;
218 let fd = this.read_scalar(fd)?.to_i32()?;
219 let buf = this.read_pointer(buf)?;
220 let count = this.read_target_usize(count)?;
221 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
222 this.read(fd, buf, count, Some(offset), dest)?;
223 }
224 "pwrite" => {
225 let [fd, buf, n, offset] = this.check_shim_sig(
226 shim_sig!(extern "C" fn(i32, *const _, usize, libc::off_t) -> isize),
227 link_name,
228 abi,
229 args,
230 )?;
231 let fd = this.read_scalar(fd)?.to_i32()?;
232 let buf = this.read_pointer(buf)?;
233 let count = this.read_target_usize(n)?;
234 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
235 trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
236 this.write(fd, buf, count, Some(offset), dest)?;
237 }
238 "pread64" => {
239 let [fd, buf, count, offset] = this.check_shim_sig(
240 shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize),
241 link_name,
242 abi,
243 args,
244 )?;
245 let fd = this.read_scalar(fd)?.to_i32()?;
246 let buf = this.read_pointer(buf)?;
247 let count = this.read_target_usize(count)?;
248 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
249 this.read(fd, buf, count, Some(offset), dest)?;
250 }
251 "pwrite64" => {
252 let [fd, buf, n, offset] = this.check_shim_sig(
253 shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize),
254 link_name,
255 abi,
256 args,
257 )?;
258 let fd = this.read_scalar(fd)?.to_i32()?;
259 let buf = this.read_pointer(buf)?;
260 let count = this.read_target_usize(n)?;
261 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
262 trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
263 this.write(fd, buf, count, Some(offset), dest)?;
264 }
265 "close" => {
266 let [fd] = this.check_shim_sig(
267 shim_sig!(extern "C" fn(i32) -> i32),
268 link_name,
269 abi,
270 args,
271 )?;
272 let result = this.close(fd)?;
273 this.write_scalar(result, dest)?;
274 }
275 "fcntl" => {
276 let ([fd_num, cmd], varargs) =
277 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
278 let result = this.fcntl(fd_num, cmd, varargs)?;
279 this.write_scalar(result, dest)?;
280 }
281 "dup" => {
282 let [old_fd] = this.check_shim_sig(
283 shim_sig!(extern "C" fn(i32) -> i32),
284 link_name,
285 abi,
286 args,
287 )?;
288 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
289 let new_fd = this.dup(old_fd)?;
290 this.write_scalar(new_fd, dest)?;
291 }
292 "dup2" => {
293 let [old_fd, new_fd] = this.check_shim_sig(
294 shim_sig!(extern "C" fn(i32, i32) -> i32),
295 link_name,
296 abi,
297 args,
298 )?;
299 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
300 let new_fd = this.read_scalar(new_fd)?.to_i32()?;
301 let result = this.dup2(old_fd, new_fd)?;
302 this.write_scalar(result, dest)?;
303 }
304 "flock" => {
305 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::MacOs, Os::Illumos], link_name)?;
307 let [fd, op] = this.check_shim_sig(
308 shim_sig!(extern "C" fn(i32, i32) -> i32),
309 link_name,
310 abi,
311 args,
312 )?;
313 let fd = this.read_scalar(fd)?.to_i32()?;
314 let op = this.read_scalar(op)?.to_i32()?;
315 let result = this.flock(fd, op)?;
316 this.write_scalar(result, dest)?;
317 }
318
319 "open" | "open64" => {
321 let ([path_raw, flag], varargs) =
324 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
325 let result = this.open(path_raw, flag, varargs)?;
326 this.write_scalar(result, dest)?;
327 }
328 "unlink" => {
329 let [path] = this.check_shim_sig(
330 shim_sig!(extern "C" fn(*const _) -> i32),
331 link_name,
332 abi,
333 args,
334 )?;
335 let result = this.unlink(path)?;
336 this.write_scalar(result, dest)?;
337 }
338 "symlink" => {
339 let [target, linkpath] = this.check_shim_sig(
340 shim_sig!(extern "C" fn(*const _, *const _) -> i32),
341 link_name,
342 abi,
343 args,
344 )?;
345 let result = this.symlink(target, linkpath)?;
346 this.write_scalar(result, dest)?;
347 }
348 "rename" => {
349 let [oldpath, newpath] = this.check_shim_sig(
350 shim_sig!(extern "C" fn(*const _, *const _) -> i32),
351 link_name,
352 abi,
353 args,
354 )?;
355 let result = this.rename(oldpath, newpath)?;
356 this.write_scalar(result, dest)?;
357 }
358 "mkdir" => {
359 let [path, mode] = this.check_shim_sig(
360 shim_sig!(extern "C" fn(*const _, libc::mode_t) -> i32),
361 link_name,
362 abi,
363 args,
364 )?;
365 let result = this.mkdir(path, mode)?;
366 this.write_scalar(result, dest)?;
367 }
368 "rmdir" => {
369 let [path] = this.check_shim_sig(
370 shim_sig!(extern "C" fn(*const _) -> i32),
371 link_name,
372 abi,
373 args,
374 )?;
375 let result = this.rmdir(path)?;
376 this.write_scalar(result, dest)?;
377 }
378 "opendir" => {
379 let [name] = this.check_shim_sig(
380 shim_sig!(extern "C" fn(*const _) -> *mut _),
381 link_name,
382 abi,
383 args,
384 )?;
385 let result = this.opendir(name)?;
386 this.write_scalar(result, dest)?;
387 }
388 "closedir" => {
389 let [dirp] = this.check_shim_sig(
390 shim_sig!(extern "C" fn(*mut _) -> i32),
391 link_name,
392 abi,
393 args,
394 )?;
395 let result = this.closedir(dirp)?;
396 this.write_scalar(result, dest)?;
397 }
398 "lseek64" => {
399 let [fd, offset, whence] = this.check_shim_sig(
400 shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t),
401 link_name,
402 abi,
403 args,
404 )?;
405 let fd = this.read_scalar(fd)?.to_i32()?;
406 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
407 let whence = this.read_scalar(whence)?.to_i32()?;
408 this.lseek64(fd, offset, whence, dest)?;
409 }
410 "lseek" => {
411 let [fd, offset, whence] = this.check_shim_sig(
412 shim_sig!(extern "C" fn(i32, libc::off_t, i32) -> libc::off_t),
413 link_name,
414 abi,
415 args,
416 )?;
417 let fd = this.read_scalar(fd)?.to_i32()?;
418 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
419 let whence = this.read_scalar(whence)?.to_i32()?;
420 this.lseek64(fd, offset, whence, dest)?;
421 }
422 "ftruncate64" => {
423 let [fd, length] = this.check_shim_sig(
424 shim_sig!(extern "C" fn(i32, libc::off64_t) -> i32),
425 link_name,
426 abi,
427 args,
428 )?;
429 let fd = this.read_scalar(fd)?.to_i32()?;
430 let length = this.read_scalar(length)?.to_int(length.layout.size)?;
431 let result = this.ftruncate64(fd, length)?;
432 this.write_scalar(result, dest)?;
433 }
434 "ftruncate" => {
435 let [fd, length] = this.check_shim_sig(
436 shim_sig!(extern "C" fn(i32, libc::off_t) -> i32),
437 link_name,
438 abi,
439 args,
440 )?;
441 let fd = this.read_scalar(fd)?.to_i32()?;
442 let length = this.read_scalar(length)?.to_int(length.layout.size)?;
443 let result = this.ftruncate64(fd, length)?;
444 this.write_scalar(result, dest)?;
445 }
446 "fsync" => {
447 let [fd] = this.check_shim_sig(
448 shim_sig!(extern "C" fn(i32) -> i32),
449 link_name,
450 abi,
451 args,
452 )?;
453 let result = this.fsync(fd)?;
454 this.write_scalar(result, dest)?;
455 }
456 "fdatasync" => {
457 let [fd] = this.check_shim_sig(
458 shim_sig!(extern "C" fn(i32) -> i32),
459 link_name,
460 abi,
461 args,
462 )?;
463 let result = this.fdatasync(fd)?;
464 this.write_scalar(result, dest)?;
465 }
466 "readlink" => {
467 let [pathname, buf, bufsize] = this.check_shim_sig(
468 shim_sig!(extern "C" fn(*const _, *mut _, usize) -> isize),
469 link_name,
470 abi,
471 args,
472 )?;
473 let result = this.readlink(pathname, buf, bufsize)?;
474 this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
475 }
476 "posix_fadvise" => {
477 let [fd, offset, len, advice] = this.check_shim_sig(
478 shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t, i32) -> i32),
479 link_name,
480 abi,
481 args,
482 )?;
483 this.read_scalar(fd)?.to_i32()?;
484 this.read_scalar(offset)?.to_int(offset.layout.size)?;
485 this.read_scalar(len)?.to_int(len.layout.size)?;
486 this.read_scalar(advice)?.to_i32()?;
487 this.write_null(dest)?;
489 }
490
491 "posix_fallocate" => {
492 this.check_target_os(
494 &[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos, Os::Android],
495 link_name,
496 )?;
497 let [fd, offset, len] = this.check_shim_sig(
498 shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t) -> i32),
499 link_name,
500 abi,
501 args,
502 )?;
503
504 let fd = this.read_scalar(fd)?.to_i32()?;
505 let offset =
507 i64::try_from(this.read_scalar(offset)?.to_int(offset.layout.size)?).unwrap();
508 let len = i64::try_from(this.read_scalar(len)?.to_int(len.layout.size)?).unwrap();
509
510 let result = this.posix_fallocate(fd, offset, len)?;
511 this.write_scalar(result, dest)?;
512 }
513
514 "posix_fallocate64" => {
515 this.check_target_os(&[Os::Linux, Os::Android], link_name)?;
517 let [fd, offset, len] = this.check_shim_sig(
518 shim_sig!(extern "C" fn(i32, libc::off64_t, libc::off64_t) -> i32),
519 link_name,
520 abi,
521 args,
522 )?;
523
524 let fd = this.read_scalar(fd)?.to_i32()?;
525 let offset = this.read_scalar(offset)?.to_i64()?;
526 let len = this.read_scalar(len)?.to_i64()?;
527
528 let result = this.posix_fallocate(fd, offset, len)?;
529 this.write_scalar(result, dest)?;
530 }
531
532 "realpath" => {
533 let [path, resolved_path] = this.check_shim_sig(
534 shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
535 link_name,
536 abi,
537 args,
538 )?;
539 let result = this.realpath(path, resolved_path)?;
540 this.write_scalar(result, dest)?;
541 }
542 "mkstemp" => {
543 let [template] = this.check_shim_sig(
544 shim_sig!(extern "C" fn(*mut _) -> i32),
545 link_name,
546 abi,
547 args,
548 )?;
549 let result = this.mkstemp(template)?;
550 this.write_scalar(result, dest)?;
551 }
552
553 "socketpair" => {
555 let [domain, type_, protocol, sv] = this.check_shim_sig(
556 shim_sig!(extern "C" fn(i32, i32, i32, *mut _) -> i32),
557 link_name,
558 abi,
559 args,
560 )?;
561 let result = this.socketpair(domain, type_, protocol, sv)?;
562 this.write_scalar(result, dest)?;
563 }
564 "pipe" => {
565 let [pipefd] = this.check_shim_sig(
566 shim_sig!(extern "C" fn(*mut _) -> i32),
567 link_name,
568 abi,
569 args,
570 )?;
571 let result = this.pipe2(pipefd, None)?;
572 this.write_scalar(result, dest)?;
573 }
574 "pipe2" => {
575 this.check_target_os(
577 &[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos],
578 link_name,
579 )?;
580 let [pipefd, flags] = this.check_shim_sig(
581 shim_sig!(extern "C" fn(*mut _, i32) -> i32),
582 link_name,
583 abi,
584 args,
585 )?;
586 let result = this.pipe2(pipefd, Some(flags))?;
587 this.write_scalar(result, dest)?;
588 }
589
590 "gettimeofday" => {
592 let [tv, tz] = this.check_shim_sig(
593 shim_sig!(extern "C" fn(*mut _, *mut _) -> i32),
594 link_name,
595 abi,
596 args,
597 )?;
598 let result = this.gettimeofday(tv, tz)?;
599 this.write_scalar(result, dest)?;
600 }
601 "localtime_r" => {
602 let [timep, result_op] = this.check_shim_sig(
603 shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _),
604 link_name,
605 abi,
606 args,
607 )?;
608 let result = this.localtime_r(timep, result_op)?;
609 this.write_pointer(result, dest)?;
610 }
611 "clock_gettime" => {
612 let [clk_id, tp] = this.check_shim_sig(
613 shim_sig!(extern "C" fn(libc::clockid_t, *mut _) -> i32),
614 link_name,
615 abi,
616 args,
617 )?;
618 this.clock_gettime(clk_id, tp, dest)?;
619 }
620
621 "posix_memalign" => {
623 let [memptr, align, size] =
624 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
625 let result = this.posix_memalign(memptr, align, size)?;
626 this.write_scalar(result, dest)?;
627 }
628
629 "mmap" => {
630 let [addr, length, prot, flags, fd, offset] =
631 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
632 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
633 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
634 this.write_scalar(ptr, dest)?;
635 }
636 "munmap" => {
637 let [addr, length] =
638 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
639 let result = this.munmap(addr, length)?;
640 this.write_scalar(result, dest)?;
641 }
642
643 "reallocarray" => {
644 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
646 let [ptr, nmemb, size] =
647 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
648 let ptr = this.read_pointer(ptr)?;
649 let nmemb = this.read_target_usize(nmemb)?;
650 let size = this.read_target_usize(size)?;
651 match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
657 None => {
658 this.set_last_error(LibcError("ENOMEM"))?;
659 this.write_null(dest)?;
660 }
661 Some(len) => {
662 let res = this.realloc(ptr, len.bytes())?;
663 this.write_pointer(res, dest)?;
664 }
665 }
666 }
667 "aligned_alloc" => {
668 let [align, size] =
671 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
672 let res = this.aligned_alloc(align, size)?;
673 this.write_pointer(res, dest)?;
674 }
675
676 "dlsym" => {
678 let [handle, symbol] =
679 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
680 this.read_target_usize(handle)?;
681 let symbol = this.read_pointer(symbol)?;
682 let name = this.read_c_str(symbol)?;
683 if let Ok(name) = str::from_utf8(name)
684 && is_dyn_sym(name, &this.tcx.sess.target.os)
685 {
686 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
687 this.write_pointer(ptr, dest)?;
688 } else {
689 this.write_null(dest)?;
690 }
691 }
692
693 "pthread_key_create" => {
695 let [key, dtor] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
696 let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
697 let dtor = this.read_pointer(dtor)?;
698
699 let dtor = if !this.ptr_is_null(dtor)? {
701 Some(this.get_ptr_fn(dtor)?.as_instance()?)
702 } else {
703 None
704 };
705
706 let key_type = key.layout.ty
709 .builtin_deref(true)
710 .ok_or_else(|| err_ub_format!(
711 "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
712 ))?;
713 let key_layout = this.layout_of(key_type)?;
714
715 let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
717 this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place)?;
718
719 this.write_null(dest)?;
721 }
722 "pthread_key_delete" => {
723 let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
724 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
725 this.machine.tls.delete_tls_key(key)?;
726 this.write_null(dest)?;
728 }
729 "pthread_getspecific" => {
730 let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
731 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
732 let active_thread = this.active_thread();
733 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
734 this.write_scalar(ptr, dest)?;
735 }
736 "pthread_setspecific" => {
737 let [key, new_ptr] =
738 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
739 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
740 let active_thread = this.active_thread();
741 let new_data = this.read_scalar(new_ptr)?;
742 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
743
744 this.write_null(dest)?;
746 }
747
748 "pthread_mutexattr_init" => {
750 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
751 this.pthread_mutexattr_init(attr)?;
752 this.write_null(dest)?;
753 }
754 "pthread_mutexattr_settype" => {
755 let [attr, kind] =
756 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
757 let result = this.pthread_mutexattr_settype(attr, kind)?;
758 this.write_scalar(result, dest)?;
759 }
760 "pthread_mutexattr_destroy" => {
761 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
762 this.pthread_mutexattr_destroy(attr)?;
763 this.write_null(dest)?;
764 }
765 "pthread_mutex_init" => {
766 let [mutex, attr] =
767 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
768 this.pthread_mutex_init(mutex, attr)?;
769 this.write_null(dest)?;
770 }
771 "pthread_mutex_lock" => {
772 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
773 this.pthread_mutex_lock(mutex, dest)?;
774 }
775 "pthread_mutex_trylock" => {
776 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
777 let result = this.pthread_mutex_trylock(mutex)?;
778 this.write_scalar(result, dest)?;
779 }
780 "pthread_mutex_unlock" => {
781 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
782 let result = this.pthread_mutex_unlock(mutex)?;
783 this.write_scalar(result, dest)?;
784 }
785 "pthread_mutex_destroy" => {
786 let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
787 this.pthread_mutex_destroy(mutex)?;
788 this.write_int(0, dest)?;
789 }
790 "pthread_rwlock_rdlock" => {
791 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
792 this.pthread_rwlock_rdlock(rwlock, dest)?;
793 }
794 "pthread_rwlock_tryrdlock" => {
795 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
796 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
797 this.write_scalar(result, dest)?;
798 }
799 "pthread_rwlock_wrlock" => {
800 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
801 this.pthread_rwlock_wrlock(rwlock, dest)?;
802 }
803 "pthread_rwlock_trywrlock" => {
804 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
805 let result = this.pthread_rwlock_trywrlock(rwlock)?;
806 this.write_scalar(result, dest)?;
807 }
808 "pthread_rwlock_unlock" => {
809 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
810 this.pthread_rwlock_unlock(rwlock)?;
811 this.write_null(dest)?;
812 }
813 "pthread_rwlock_destroy" => {
814 let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
815 this.pthread_rwlock_destroy(rwlock)?;
816 this.write_null(dest)?;
817 }
818 "pthread_condattr_init" => {
819 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
820 this.pthread_condattr_init(attr)?;
821 this.write_null(dest)?;
822 }
823 "pthread_condattr_setclock" => {
824 let [attr, clock_id] =
825 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
826 let result = this.pthread_condattr_setclock(attr, clock_id)?;
827 this.write_scalar(result, dest)?;
828 }
829 "pthread_condattr_getclock" => {
830 let [attr, clock_id] =
831 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
832 this.pthread_condattr_getclock(attr, clock_id)?;
833 this.write_null(dest)?;
834 }
835 "pthread_condattr_destroy" => {
836 let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
837 this.pthread_condattr_destroy(attr)?;
838 this.write_null(dest)?;
839 }
840 "pthread_cond_init" => {
841 let [cond, attr] =
842 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
843 this.pthread_cond_init(cond, attr)?;
844 this.write_null(dest)?;
845 }
846 "pthread_cond_signal" => {
847 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
848 this.pthread_cond_signal(cond)?;
849 this.write_null(dest)?;
850 }
851 "pthread_cond_broadcast" => {
852 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
853 this.pthread_cond_broadcast(cond)?;
854 this.write_null(dest)?;
855 }
856 "pthread_cond_wait" => {
857 let [cond, mutex] =
858 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
859 this.pthread_cond_wait(cond, mutex, dest)?;
860 }
861 "pthread_cond_timedwait" => {
862 let [cond, mutex, abstime] =
863 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
864 this.pthread_cond_timedwait(
865 cond, mutex, abstime, dest, false,
866 )?;
867 }
868 "pthread_cond_destroy" => {
869 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
870 this.pthread_cond_destroy(cond)?;
871 this.write_null(dest)?;
872 }
873
874 "pthread_create" => {
876 let [thread, attr, start, arg] =
877 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
878 this.pthread_create(thread, attr, start, arg)?;
879 this.write_null(dest)?;
880 }
881 "pthread_join" => {
882 let [thread, retval] =
883 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
884 this.pthread_join(thread, retval, dest)?;
885 }
886 "pthread_detach" => {
887 let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
888 let res = this.pthread_detach(thread)?;
889 this.write_scalar(res, dest)?;
890 }
891 "pthread_self" => {
892 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
893 let res = this.pthread_self()?;
894 this.write_scalar(res, dest)?;
895 }
896 "sched_yield" => {
897 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
898 this.sched_yield()?;
899 this.write_null(dest)?;
900 }
901 "nanosleep" => {
902 let [duration, rem] =
903 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
904 let result = this.nanosleep(duration, rem)?;
905 this.write_scalar(result, dest)?;
906 }
907 "clock_nanosleep" => {
908 this.check_target_os(
910 &[Os::FreeBsd, Os::Linux, Os::Android, Os::Solaris, Os::Illumos],
911 link_name,
912 )?;
913 let [clock_id, flags, req, rem] =
914 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
915 let result = this.clock_nanosleep(clock_id, flags, req, rem)?;
916 this.write_scalar(result, dest)?;
917 }
918 "sched_getaffinity" => {
919 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
921 let [pid, cpusetsize, mask] =
922 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
923 let pid = this.read_scalar(pid)?.to_u32()?;
924 let cpusetsize = this.read_target_usize(cpusetsize)?;
925 let mask = this.read_pointer(mask)?;
926
927 let thread_id = match pid {
929 0 => this.active_thread(),
930 _ =>
931 throw_unsup_format!(
932 "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"
933 ),
934 };
935
936 let chunk_size = CpuAffinityMask::chunk_size(this);
938
939 if this.ptr_is_null(mask)? {
940 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
941 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
942 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
944 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
945 let cpuset = cpuset.clone();
946 let byte_count =
948 Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
949 this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
950 this.write_null(dest)?;
951 } else {
952 this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
954 }
955 }
956 "sched_setaffinity" => {
957 this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
959 let [pid, cpusetsize, mask] =
960 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
961 let pid = this.read_scalar(pid)?.to_u32()?;
962 let cpusetsize = this.read_target_usize(cpusetsize)?;
963 let mask = this.read_pointer(mask)?;
964
965 let thread_id = match pid {
967 0 => this.active_thread(),
968 _ =>
969 throw_unsup_format!(
970 "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"
971 ),
972 };
973
974 if this.ptr_is_null(mask)? {
975 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
976 } else {
977 let bits_slice =
981 this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
982 let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
984 std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
985 match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
986 Some(cpuset) => {
987 this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
988 this.write_null(dest)?;
989 }
990 None => {
991 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
993 }
994 }
995 }
996 }
997
998 "isatty" => {
1000 let [fd] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1001 let result = this.isatty(fd)?;
1002 this.write_scalar(result, dest)?;
1003 }
1004 "pthread_atfork" => {
1005 let [prepare, parent, child] =
1006 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1007 this.read_pointer(prepare)?;
1008 this.read_pointer(parent)?;
1009 this.read_pointer(child)?;
1010 this.write_null(dest)?;
1012 }
1013 "getentropy" => {
1014 this.check_target_os(
1017 &[Os::Linux, Os::MacOs, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
1018 link_name,
1019 )?;
1020 let [buf, bufsize] =
1021 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1022 let buf = this.read_pointer(buf)?;
1023 let bufsize = this.read_target_usize(bufsize)?;
1024
1025 if bufsize > 256 {
1031 this.set_last_error_and_return(LibcError("EIO"), dest)?;
1032 } else {
1033 this.gen_random(buf, bufsize)?;
1034 this.write_null(dest)?;
1035 }
1036 }
1037
1038 "strerror_r" => {
1039 let [errnum, buf, buflen] =
1040 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1041 let result = this.strerror_r(errnum, buf, buflen)?;
1042 this.write_scalar(result, dest)?;
1043 }
1044
1045 "getrandom" => {
1046 this.check_target_os(
1049 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
1050 link_name,
1051 )?;
1052 let [ptr, len, flags] =
1053 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1054 let ptr = this.read_pointer(ptr)?;
1055 let len = this.read_target_usize(len)?;
1056 let _flags = this.read_scalar(flags)?.to_i32()?;
1057 this.gen_random(ptr, len)?;
1059 this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
1060 }
1061 "arc4random_buf" => {
1062 this.check_target_os(&[Os::FreeBsd, Os::Illumos, Os::Solaris], link_name)?;
1065 let [ptr, len] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1066 let ptr = this.read_pointer(ptr)?;
1067 let len = this.read_target_usize(len)?;
1068 this.gen_random(ptr, len)?;
1069 }
1070 "_Unwind_RaiseException" => {
1071 this.check_target_os(
1085 &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android, Os::MacOs],
1086 link_name,
1087 )?;
1088 let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1090 this.handle_miri_start_unwind(payload)?;
1091 return interp_ok(EmulateItemResult::NeedsUnwind);
1092 }
1093 "getuid" | "geteuid" => {
1094 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1095 this.write_int(UID, dest)?;
1097 }
1098
1099 "pthread_attr_getguardsize" if this.frame_in_std() => {
1102 let [_attr, guard_size] =
1103 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1104 let guard_size_layout = this.machine.layouts.usize;
1105 let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
1106 this.write_scalar(
1107 Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
1108 &guard_size,
1109 )?;
1110
1111 this.write_null(dest)?;
1113 }
1114
1115 "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
1116 let [_] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1117 this.write_null(dest)?;
1118 }
1119 "pthread_attr_setstacksize" if this.frame_in_std() => {
1120 let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1121 this.write_null(dest)?;
1122 }
1123
1124 "pthread_attr_getstack" if this.frame_in_std() => {
1125 let [attr_place, addr_place, size_place] =
1128 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1129 let _attr_place =
1130 this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
1131 let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?;
1132 let size_place = this.deref_pointer_as(size_place, this.machine.layouts.usize)?;
1133
1134 this.write_scalar(
1135 Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
1136 &addr_place,
1137 )?;
1138 this.write_scalar(
1139 Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
1140 &size_place,
1141 )?;
1142
1143 this.write_null(dest)?;
1145 }
1146
1147 "signal" | "sigaltstack" if this.frame_in_std() => {
1148 let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1149 this.write_null(dest)?;
1150 }
1151 "sigaction" | "mprotect" if this.frame_in_std() => {
1152 let [_, _, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1153 this.write_null(dest)?;
1154 }
1155
1156 "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
1157 let [uid, pwd, buf, buflen, result] =
1159 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1160 this.check_no_isolation("`getpwuid_r`")?;
1161
1162 let uid = this.read_scalar(uid)?.to_u32()?;
1163 let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?;
1164 let buf = this.read_pointer(buf)?;
1165 let buflen = this.read_target_usize(buflen)?;
1166 let result = this.deref_pointer_as(result, this.machine.layouts.mut_raw_ptr)?;
1167
1168 if uid != UID {
1170 throw_unsup_format!("`getpwuid_r` on other users is not supported");
1171 }
1172
1173 this.write_uninit(&pwd)?;
1176
1177 #[allow(deprecated)]
1179 let home_dir = std::env::home_dir().unwrap();
1180 let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
1181 let pw_dir = this.project_field_named(&pwd, "pw_dir")?;
1182 this.write_pointer(buf, &pw_dir)?;
1183
1184 if written {
1185 this.write_pointer(pwd.ptr(), &result)?;
1186 this.write_null(dest)?;
1187 } else {
1188 this.write_null(&result)?;
1189 this.write_scalar(this.eval_libc("ERANGE"), dest)?;
1190 }
1191 }
1192
1193 _ => {
1195 let target_os = &this.tcx.sess.target.os;
1196 return match target_os {
1197 Os::Android =>
1198 android::EvalContextExt::emulate_foreign_item_inner(
1199 this, link_name, abi, args, dest,
1200 ),
1201 Os::FreeBsd =>
1202 freebsd::EvalContextExt::emulate_foreign_item_inner(
1203 this, link_name, abi, args, dest,
1204 ),
1205 Os::Linux =>
1206 linux::EvalContextExt::emulate_foreign_item_inner(
1207 this, link_name, abi, args, dest,
1208 ),
1209 Os::MacOs =>
1210 macos::EvalContextExt::emulate_foreign_item_inner(
1211 this, link_name, abi, args, dest,
1212 ),
1213 Os::Solaris | Os::Illumos =>
1214 solarish::EvalContextExt::emulate_foreign_item_inner(
1215 this, link_name, abi, args, dest,
1216 ),
1217 _ => interp_ok(EmulateItemResult::NotSupported),
1218 };
1219 }
1220 };
1221
1222 interp_ok(EmulateItemResult::NeedsReturn)
1223 }
1224}