1use std::ffi::OsStr;
2use std::str;
3
4use rustc_abi::{ExternAbi, Size};
5use rustc_middle::ty::Ty;
6use rustc_middle::ty::layout::LayoutOf;
7use rustc_span::Symbol;
8use rustc_target::callconv::{Conv, FnAbi};
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::*;
19
20pub fn is_dyn_sym(name: &str, target_os: &str) -> bool {
21 match name {
22 "isatty" => true,
24 "signal" => true,
27 "getentropy" | "getrandom" => true,
29 _ =>
31 match target_os {
32 "android" => android::is_dyn_sym(name),
33 "freebsd" => freebsd::is_dyn_sym(name),
34 "linux" => linux::is_dyn_sym(name),
35 "macos" => macos::is_dyn_sym(name),
36 "solaris" | "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_abi(
116 link_name,
117 abi,
118 ExternAbi::C { unwind: false },
119 [this.machine.layouts.const_raw_ptr.ty],
120 this.machine.layouts.mut_raw_ptr.ty,
121 args,
122 )?;
123 let result = this.getenv(name)?;
124 this.write_pointer(result, dest)?;
125 }
126 "unsetenv" => {
127 let [name] = this.check_shim_abi(
128 link_name,
129 abi,
130 ExternAbi::C { unwind: false },
131 [this.machine.layouts.const_raw_ptr.ty],
132 this.tcx.types.i32,
133 args,
134 )?;
135 let result = this.unsetenv(name)?;
136 this.write_scalar(result, dest)?;
137 }
138 "setenv" => {
139 let [name, value, overwrite] = this.check_shim_abi(
140 link_name,
141 abi,
142 ExternAbi::C { unwind: false },
143 [
144 this.machine.layouts.const_raw_ptr.ty,
145 this.machine.layouts.const_raw_ptr.ty,
146 this.tcx.types.i32,
147 ],
148 this.tcx.types.i32,
149 args,
150 )?;
151 this.read_scalar(overwrite)?.to_i32()?;
152 let result = this.setenv(name, value)?;
153 this.write_scalar(result, dest)?;
154 }
155 "getcwd" => {
156 let [buf, size] = this.check_shim_abi(
157 link_name,
158 abi,
159 ExternAbi::C { unwind: false },
160 [this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.usize],
161 this.machine.layouts.mut_raw_ptr.ty,
162 args,
163 )?;
164 let result = this.getcwd(buf, size)?;
165 this.write_pointer(result, dest)?;
166 }
167 "chdir" => {
168 let [path] = this.check_shim_abi(
169 link_name,
170 abi,
171 ExternAbi::C { unwind: false },
172 [this.machine.layouts.const_raw_ptr.ty],
173 this.tcx.types.i32,
174 args,
175 )?;
176 let result = this.chdir(path)?;
177 this.write_scalar(result, dest)?;
178 }
179 "getpid" => {
180 let [] = this.check_shim_abi(
181 link_name,
182 abi,
183 ExternAbi::C { unwind: false },
184 [],
185 this.libc_ty_layout("pid_t").ty,
186 args,
187 )?;
188 let result = this.getpid()?;
189 this.write_scalar(result, dest)?;
190 }
191 "sysconf" => {
192 let [val] = this.check_shim_abi(
193 link_name,
194 abi,
195 ExternAbi::C { unwind: false },
196 [this.tcx.types.i32],
197 this.tcx.types.isize,
198 args,
199 )?;
200 let result = this.sysconf(val)?;
201 this.write_scalar(result, dest)?;
202 }
203 "read" => {
205 let [fd, buf, count] = this.check_shim_abi(
206 link_name,
207 abi,
208 ExternAbi::C { unwind: false },
209 [this.tcx.types.i32, this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.usize],
210 this.tcx.types.isize,
211 args,
212 )?;
213 let fd = this.read_scalar(fd)?.to_i32()?;
214 let buf = this.read_pointer(buf)?;
215 let count = this.read_target_usize(count)?;
216 this.read(fd, buf, count, None, dest)?;
217 }
218 "write" => {
219 let [fd, buf, n] = this.check_shim_abi(
220 link_name,
221 abi,
222 ExternAbi::C { unwind: false },
223 [
224 this.tcx.types.i32,
225 this.machine.layouts.const_raw_ptr.ty,
226 this.tcx.types.usize,
227 ],
228 this.tcx.types.isize,
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 trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
235 this.write(fd, buf, count, None, dest)?;
236 }
237 "pread" => {
238 let off_t = this.libc_ty_layout("off_t");
239 let [fd, buf, count, offset] = this.check_shim_abi(
240 link_name,
241 abi,
242 ExternAbi::C { unwind: false },
243 [
244 this.tcx.types.i32,
245 this.machine.layouts.mut_raw_ptr.ty,
246 this.tcx.types.usize,
247 off_t.ty,
248 ],
249 this.tcx.types.isize,
250 args,
251 )?;
252 let fd = this.read_scalar(fd)?.to_i32()?;
253 let buf = this.read_pointer(buf)?;
254 let count = this.read_target_usize(count)?;
255 let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
256 this.read(fd, buf, count, Some(offset), dest)?;
257 }
258 "pwrite" => {
259 let off_t = this.libc_ty_layout("off_t");
260 let [fd, buf, n, offset] = this.check_shim_abi(
261 link_name,
262 abi,
263 ExternAbi::C { unwind: false },
264 [
265 this.tcx.types.i32,
266 this.machine.layouts.const_raw_ptr.ty,
267 this.tcx.types.usize,
268 off_t.ty,
269 ],
270 this.tcx.types.isize,
271 args,
272 )?;
273 let fd = this.read_scalar(fd)?.to_i32()?;
274 let buf = this.read_pointer(buf)?;
275 let count = this.read_target_usize(n)?;
276 let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
277 trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
278 this.write(fd, buf, count, Some(offset), dest)?;
279 }
280 "pread64" => {
281 let off64_t = this.libc_ty_layout("off64_t");
282 let [fd, buf, count, offset] = this.check_shim_abi(
283 link_name,
284 abi,
285 ExternAbi::C { unwind: false },
286 [
287 this.tcx.types.i32,
288 this.machine.layouts.mut_raw_ptr.ty,
289 this.tcx.types.usize,
290 off64_t.ty,
291 ],
292 this.tcx.types.isize,
293 args,
294 )?;
295 let fd = this.read_scalar(fd)?.to_i32()?;
296 let buf = this.read_pointer(buf)?;
297 let count = this.read_target_usize(count)?;
298 let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
299 this.read(fd, buf, count, Some(offset), dest)?;
300 }
301 "pwrite64" => {
302 let off64_t = this.libc_ty_layout("off64_t");
303 let [fd, buf, n, offset] = this.check_shim_abi(
304 link_name,
305 abi,
306 ExternAbi::C { unwind: false },
307 [
308 this.tcx.types.i32,
309 this.machine.layouts.const_raw_ptr.ty,
310 this.tcx.types.usize,
311 off64_t.ty,
312 ],
313 this.tcx.types.isize,
314 args,
315 )?;
316 let fd = this.read_scalar(fd)?.to_i32()?;
317 let buf = this.read_pointer(buf)?;
318 let count = this.read_target_usize(n)?;
319 let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
320 trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
321 this.write(fd, buf, count, Some(offset), dest)?;
322 }
323 "close" => {
324 let [fd] = this.check_shim_abi(
325 link_name,
326 abi,
327 ExternAbi::C { unwind: false },
328 [this.tcx.types.i32],
329 this.tcx.types.i32,
330 args,
331 )?;
332 let result = this.close(fd)?;
333 this.write_scalar(result, dest)?;
334 }
335 "fcntl" => {
336 let ([fd_num, cmd], varargs) =
337 this.check_shim_variadic(abi, Conv::C, link_name, args)?;
338 let result = this.fcntl(fd_num, cmd, varargs)?;
339 this.write_scalar(result, dest)?;
340 }
341 "dup" => {
342 let [old_fd] = this.check_shim_abi(
343 link_name,
344 abi,
345 ExternAbi::C { unwind: false },
346 [this.tcx.types.i32],
347 this.tcx.types.i32,
348 args,
349 )?;
350 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
351 let new_fd = this.dup(old_fd)?;
352 this.write_scalar(new_fd, dest)?;
353 }
354 "dup2" => {
355 let [old_fd, new_fd] = this.check_shim_abi(
356 link_name,
357 abi,
358 ExternAbi::C { unwind: false },
359 [this.tcx.types.i32, this.tcx.types.i32],
360 this.tcx.types.i32,
361 args,
362 )?;
363 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
364 let new_fd = this.read_scalar(new_fd)?.to_i32()?;
365 let result = this.dup2(old_fd, new_fd)?;
366 this.write_scalar(result, dest)?;
367 }
368 "flock" => {
369 this.check_target_os(&["linux", "freebsd", "macos", "illumos"], link_name)?;
371 let [fd, op] = this.check_shim_abi(
372 link_name,
373 abi,
374 ExternAbi::C { unwind: false },
375 [this.tcx.types.i32, this.tcx.types.i32],
376 this.tcx.types.i32,
377 args,
378 )?;
379 let fd = this.read_scalar(fd)?.to_i32()?;
380 let op = this.read_scalar(op)?.to_i32()?;
381 let result = this.flock(fd, op)?;
382 this.write_scalar(result, dest)?;
383 }
384
385 "open" | "open64" => {
387 let ([path_raw, flag], varargs) =
390 this.check_shim_variadic(abi, Conv::C, link_name, args)?;
391 let result = this.open(path_raw, flag, varargs)?;
392 this.write_scalar(result, dest)?;
393 }
394 "unlink" => {
395 let [path] = this.check_shim_abi(
396 link_name,
397 abi,
398 ExternAbi::C { unwind: false },
399 [this.machine.layouts.const_raw_ptr.ty],
400 this.tcx.types.i32,
401 args,
402 )?;
403 let result = this.unlink(path)?;
404 this.write_scalar(result, dest)?;
405 }
406 "symlink" => {
407 let [target, linkpath] = this.check_shim_abi(
408 link_name,
409 abi,
410 ExternAbi::C { unwind: false },
411 [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.const_raw_ptr.ty],
412 this.tcx.types.i32,
413 args,
414 )?;
415 let result = this.symlink(target, linkpath)?;
416 this.write_scalar(result, dest)?;
417 }
418 "rename" => {
419 let [oldpath, newpath] = this.check_shim_abi(
420 link_name,
421 abi,
422 ExternAbi::C { unwind: false },
423 [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.const_raw_ptr.ty],
424 this.tcx.types.i32,
425 args,
426 )?;
427 let result = this.rename(oldpath, newpath)?;
428 this.write_scalar(result, dest)?;
429 }
430 "mkdir" => {
431 let [path, mode] = this.check_shim_abi(
432 link_name,
433 abi,
434 ExternAbi::C { unwind: false },
435 [this.machine.layouts.const_raw_ptr.ty, this.libc_ty_layout("mode_t").ty],
436 this.tcx.types.i32,
437 args,
438 )?;
439 let result = this.mkdir(path, mode)?;
440 this.write_scalar(result, dest)?;
441 }
442 "rmdir" => {
443 let [path] = this.check_shim_abi(
444 link_name,
445 abi,
446 ExternAbi::C { unwind: false },
447 [this.machine.layouts.const_raw_ptr.ty],
448 this.tcx.types.i32,
449 args,
450 )?;
451 let result = this.rmdir(path)?;
452 this.write_scalar(result, dest)?;
453 }
454 "opendir" => {
455 let [name] = this.check_shim_abi(
456 link_name,
457 abi,
458 ExternAbi::C { unwind: false },
459 [this.machine.layouts.const_raw_ptr.ty],
460 this.machine.layouts.mut_raw_ptr.ty,
461 args,
462 )?;
463 let result = this.opendir(name)?;
464 this.write_scalar(result, dest)?;
465 }
466 "closedir" => {
467 let [dirp] = this.check_shim_abi(
468 link_name,
469 abi,
470 ExternAbi::C { unwind: false },
471 [this.machine.layouts.mut_raw_ptr.ty],
472 this.tcx.types.i32,
473 args,
474 )?;
475 let result = this.closedir(dirp)?;
476 this.write_scalar(result, dest)?;
477 }
478 "lseek64" => {
479 let off64_t = this.libc_ty_layout("off64_t");
480 let [fd, offset, whence] = this.check_shim_abi(
481 link_name,
482 abi,
483 ExternAbi::C { unwind: false },
484 [this.tcx.types.i32, off64_t.ty, this.tcx.types.i32],
485 off64_t.ty,
486 args,
487 )?;
488 let fd = this.read_scalar(fd)?.to_i32()?;
489 let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
490 let whence = this.read_scalar(whence)?.to_i32()?;
491 this.lseek64(fd, offset, whence, dest)?;
492 }
493 "lseek" => {
494 let off_t = this.libc_ty_layout("off_t");
495 let [fd, offset, whence] = this.check_shim_abi(
496 link_name,
497 abi,
498 ExternAbi::C { unwind: false },
499 [this.tcx.types.i32, off_t.ty, this.tcx.types.i32],
500 off_t.ty,
501 args,
502 )?;
503 let fd = this.read_scalar(fd)?.to_i32()?;
504 let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
505 let whence = this.read_scalar(whence)?.to_i32()?;
506 this.lseek64(fd, offset, whence, dest)?;
507 }
508 "ftruncate64" => {
509 let off64_t = this.libc_ty_layout("off64_t");
510 let [fd, length] = this.check_shim_abi(
511 link_name,
512 abi,
513 ExternAbi::C { unwind: false },
514 [this.tcx.types.i32, off64_t.ty],
515 this.tcx.types.i32,
516 args,
517 )?;
518 let fd = this.read_scalar(fd)?.to_i32()?;
519 let length = this.read_scalar(length)?.to_int(off64_t.size)?;
520 let result = this.ftruncate64(fd, length)?;
521 this.write_scalar(result, dest)?;
522 }
523 "ftruncate" => {
524 let off_t = this.libc_ty_layout("off_t");
525 let [fd, length] = this.check_shim_abi(
526 link_name,
527 abi,
528 ExternAbi::C { unwind: false },
529 [this.tcx.types.i32, off_t.ty],
530 this.tcx.types.i32,
531 args,
532 )?;
533 let fd = this.read_scalar(fd)?.to_i32()?;
534 let length = this.read_scalar(length)?.to_int(off_t.size)?;
535 let result = this.ftruncate64(fd, length)?;
536 this.write_scalar(result, dest)?;
537 }
538 "fsync" => {
539 let [fd] = this.check_shim_abi(
540 link_name,
541 abi,
542 ExternAbi::C { unwind: false },
543 [this.tcx.types.i32],
544 this.tcx.types.i32,
545 args,
546 )?;
547 let result = this.fsync(fd)?;
548 this.write_scalar(result, dest)?;
549 }
550 "fdatasync" => {
551 let [fd] = this.check_shim_abi(
552 link_name,
553 abi,
554 ExternAbi::C { unwind: false },
555 [this.tcx.types.i32],
556 this.tcx.types.i32,
557 args,
558 )?;
559 let result = this.fdatasync(fd)?;
560 this.write_scalar(result, dest)?;
561 }
562 "readlink" => {
563 let [pathname, buf, bufsize] = this.check_shim_abi(
564 link_name,
565 abi,
566 ExternAbi::C { unwind: false },
567 [
568 this.machine.layouts.const_raw_ptr.ty,
569 this.machine.layouts.mut_raw_ptr.ty,
570 this.tcx.types.usize,
571 ],
572 this.tcx.types.isize,
573 args,
574 )?;
575 let result = this.readlink(pathname, buf, bufsize)?;
576 this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
577 }
578 "posix_fadvise" => {
579 let off_t = this.libc_ty_layout("off_t");
580 let [fd, offset, len, advice] = this.check_shim_abi(
581 link_name,
582 abi,
583 ExternAbi::C { unwind: false },
584 [this.tcx.types.i32, off_t.ty, off_t.ty, this.tcx.types.i32],
585 this.tcx.types.i32,
586 args,
587 )?;
588 this.read_scalar(fd)?.to_i32()?;
589 this.read_scalar(offset)?.to_int(off_t.size)?;
590 this.read_scalar(len)?.to_int(off_t.size)?;
591 this.read_scalar(advice)?.to_i32()?;
592 this.write_null(dest)?;
594 }
595 "realpath" => {
596 let [path, resolved_path] = this.check_shim_abi(
597 link_name,
598 abi,
599 ExternAbi::C { unwind: false },
600 [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
601 this.machine.layouts.mut_raw_ptr.ty,
602 args,
603 )?;
604 let result = this.realpath(path, resolved_path)?;
605 this.write_scalar(result, dest)?;
606 }
607 "mkstemp" => {
608 let [template] = this.check_shim_abi(
609 link_name,
610 abi,
611 ExternAbi::C { unwind: false },
612 [this.machine.layouts.mut_raw_ptr.ty],
613 this.tcx.types.i32,
614 args,
615 )?;
616 let result = this.mkstemp(template)?;
617 this.write_scalar(result, dest)?;
618 }
619
620 "socketpair" => {
622 let [domain, type_, protocol, sv] = this.check_shim_abi(
623 link_name,
624 abi,
625 ExternAbi::C { unwind: false },
626 [
627 this.tcx.types.i32,
628 this.tcx.types.i32,
629 this.tcx.types.i32,
630 this.machine.layouts.mut_raw_ptr.ty,
631 ],
632 this.tcx.types.i32,
633 args,
634 )?;
635 let result = this.socketpair(domain, type_, protocol, sv)?;
636 this.write_scalar(result, dest)?;
637 }
638 "pipe" => {
639 let [pipefd] = this.check_shim_abi(
640 link_name,
641 abi,
642 ExternAbi::C { unwind: false },
643 [this.machine.layouts.mut_raw_ptr.ty],
644 this.tcx.types.i32,
645 args,
646 )?;
647 let result = this.pipe2(pipefd, None)?;
648 this.write_scalar(result, dest)?;
649 }
650 "pipe2" => {
651 this.check_target_os(&["linux", "freebsd", "solaris", "illumos"], link_name)?;
653 let [pipefd, flags] = this.check_shim_abi(
654 link_name,
655 abi,
656 ExternAbi::C { unwind: false },
657 [this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.i32],
658 this.tcx.types.i32,
659 args,
660 )?;
661 let result = this.pipe2(pipefd, Some(flags))?;
662 this.write_scalar(result, dest)?;
663 }
664
665 "gettimeofday" => {
667 let [tv, tz] = this.check_shim_abi(
668 link_name,
669 abi,
670 ExternAbi::C { unwind: false },
671 [this.machine.layouts.mut_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
672 this.tcx.types.i32,
673 args,
674 )?;
675 let result = this.gettimeofday(tv, tz)?;
676 this.write_scalar(result, dest)?;
677 }
678 "localtime_r" => {
679 let [timep, result_op] = this.check_shim_abi(
680 link_name,
681 abi,
682 ExternAbi::C { unwind: false },
683 [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
684 this.machine.layouts.mut_raw_ptr.ty,
685 args,
686 )?;
687 let result = this.localtime_r(timep, result_op)?;
688 this.write_pointer(result, dest)?;
689 }
690 "clock_gettime" => {
691 let [clk_id, tp] = this.check_shim_abi(
692 link_name,
693 abi,
694 ExternAbi::C { unwind: false },
695 [this.libc_ty_layout("clockid_t").ty, this.machine.layouts.mut_raw_ptr.ty],
696 this.tcx.types.i32,
697 args,
698 )?;
699 this.clock_gettime(clk_id, tp, dest)?;
700 }
701
702 "posix_memalign" => {
704 let [memptr, align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
705 let result = this.posix_memalign(memptr, align, size)?;
706 this.write_scalar(result, dest)?;
707 }
708
709 "mmap" => {
710 let [addr, length, prot, flags, fd, offset] =
711 this.check_shim(abi, Conv::C, link_name, args)?;
712 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
713 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
714 this.write_scalar(ptr, dest)?;
715 }
716 "munmap" => {
717 let [addr, length] = this.check_shim(abi, Conv::C, link_name, args)?;
718 let result = this.munmap(addr, length)?;
719 this.write_scalar(result, dest)?;
720 }
721
722 "reallocarray" => {
723 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
725 let [ptr, nmemb, size] = this.check_shim(abi, Conv::C, link_name, args)?;
726 let ptr = this.read_pointer(ptr)?;
727 let nmemb = this.read_target_usize(nmemb)?;
728 let size = this.read_target_usize(size)?;
729 match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
735 None => {
736 this.set_last_error(LibcError("ENOMEM"))?;
737 this.write_null(dest)?;
738 }
739 Some(len) => {
740 let res = this.realloc(ptr, len.bytes())?;
741 this.write_pointer(res, dest)?;
742 }
743 }
744 }
745 "aligned_alloc" => {
746 let [align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
749 let res = this.aligned_alloc(align, size)?;
750 this.write_pointer(res, dest)?;
751 }
752
753 "dlsym" => {
755 let [handle, symbol] = this.check_shim(abi, Conv::C, link_name, args)?;
756 this.read_target_usize(handle)?;
757 let symbol = this.read_pointer(symbol)?;
758 let name = this.read_c_str(symbol)?;
759 if let Ok(name) = str::from_utf8(name)
760 && is_dyn_sym(name, &this.tcx.sess.target.os)
761 {
762 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
763 this.write_pointer(ptr, dest)?;
764 } else {
765 this.write_null(dest)?;
766 }
767 }
768
769 "pthread_key_create" => {
771 let [key, dtor] = this.check_shim(abi, Conv::C, link_name, args)?;
772 let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
773 let dtor = this.read_pointer(dtor)?;
774
775 let dtor = if !this.ptr_is_null(dtor)? {
777 Some(this.get_ptr_fn(dtor)?.as_instance()?)
778 } else {
779 None
780 };
781
782 let key_type = key.layout.ty
785 .builtin_deref(true)
786 .ok_or_else(|| err_ub_format!(
787 "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
788 ))?;
789 let key_layout = this.layout_of(key_type)?;
790
791 let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
793 this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place)?;
794
795 this.write_null(dest)?;
797 }
798 "pthread_key_delete" => {
799 let [key] = this.check_shim(abi, Conv::C, link_name, args)?;
800 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
801 this.machine.tls.delete_tls_key(key)?;
802 this.write_null(dest)?;
804 }
805 "pthread_getspecific" => {
806 let [key] = this.check_shim(abi, Conv::C, link_name, args)?;
807 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
808 let active_thread = this.active_thread();
809 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
810 this.write_scalar(ptr, dest)?;
811 }
812 "pthread_setspecific" => {
813 let [key, new_ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
814 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
815 let active_thread = this.active_thread();
816 let new_data = this.read_scalar(new_ptr)?;
817 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
818
819 this.write_null(dest)?;
821 }
822
823 "pthread_mutexattr_init" => {
825 let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
826 this.pthread_mutexattr_init(attr)?;
827 this.write_null(dest)?;
828 }
829 "pthread_mutexattr_settype" => {
830 let [attr, kind] = this.check_shim(abi, Conv::C, link_name, args)?;
831 let result = this.pthread_mutexattr_settype(attr, kind)?;
832 this.write_scalar(result, dest)?;
833 }
834 "pthread_mutexattr_destroy" => {
835 let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
836 this.pthread_mutexattr_destroy(attr)?;
837 this.write_null(dest)?;
838 }
839 "pthread_mutex_init" => {
840 let [mutex, attr] = this.check_shim(abi, Conv::C, link_name, args)?;
841 this.pthread_mutex_init(mutex, attr)?;
842 this.write_null(dest)?;
843 }
844 "pthread_mutex_lock" => {
845 let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
846 this.pthread_mutex_lock(mutex, dest)?;
847 }
848 "pthread_mutex_trylock" => {
849 let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
850 let result = this.pthread_mutex_trylock(mutex)?;
851 this.write_scalar(result, dest)?;
852 }
853 "pthread_mutex_unlock" => {
854 let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
855 let result = this.pthread_mutex_unlock(mutex)?;
856 this.write_scalar(result, dest)?;
857 }
858 "pthread_mutex_destroy" => {
859 let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
860 this.pthread_mutex_destroy(mutex)?;
861 this.write_int(0, dest)?;
862 }
863 "pthread_rwlock_rdlock" => {
864 let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
865 this.pthread_rwlock_rdlock(rwlock, dest)?;
866 }
867 "pthread_rwlock_tryrdlock" => {
868 let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
869 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
870 this.write_scalar(result, dest)?;
871 }
872 "pthread_rwlock_wrlock" => {
873 let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
874 this.pthread_rwlock_wrlock(rwlock, dest)?;
875 }
876 "pthread_rwlock_trywrlock" => {
877 let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
878 let result = this.pthread_rwlock_trywrlock(rwlock)?;
879 this.write_scalar(result, dest)?;
880 }
881 "pthread_rwlock_unlock" => {
882 let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
883 this.pthread_rwlock_unlock(rwlock)?;
884 this.write_null(dest)?;
885 }
886 "pthread_rwlock_destroy" => {
887 let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
888 this.pthread_rwlock_destroy(rwlock)?;
889 this.write_null(dest)?;
890 }
891 "pthread_condattr_init" => {
892 let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
893 this.pthread_condattr_init(attr)?;
894 this.write_null(dest)?;
895 }
896 "pthread_condattr_setclock" => {
897 let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?;
898 let result = this.pthread_condattr_setclock(attr, clock_id)?;
899 this.write_scalar(result, dest)?;
900 }
901 "pthread_condattr_getclock" => {
902 let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?;
903 this.pthread_condattr_getclock(attr, clock_id)?;
904 this.write_null(dest)?;
905 }
906 "pthread_condattr_destroy" => {
907 let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
908 this.pthread_condattr_destroy(attr)?;
909 this.write_null(dest)?;
910 }
911 "pthread_cond_init" => {
912 let [cond, attr] = this.check_shim(abi, Conv::C, link_name, args)?;
913 this.pthread_cond_init(cond, attr)?;
914 this.write_null(dest)?;
915 }
916 "pthread_cond_signal" => {
917 let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
918 this.pthread_cond_signal(cond)?;
919 this.write_null(dest)?;
920 }
921 "pthread_cond_broadcast" => {
922 let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
923 this.pthread_cond_broadcast(cond)?;
924 this.write_null(dest)?;
925 }
926 "pthread_cond_wait" => {
927 let [cond, mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
928 this.pthread_cond_wait(cond, mutex, dest)?;
929 }
930 "pthread_cond_timedwait" => {
931 let [cond, mutex, abstime] = this.check_shim(abi, Conv::C, link_name, args)?;
932 this.pthread_cond_timedwait(cond, mutex, abstime, dest)?;
933 }
934 "pthread_cond_destroy" => {
935 let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
936 this.pthread_cond_destroy(cond)?;
937 this.write_null(dest)?;
938 }
939
940 "pthread_create" => {
942 let [thread, attr, start, arg] = this.check_shim(abi, Conv::C, link_name, args)?;
943 this.pthread_create(thread, attr, start, arg)?;
944 this.write_null(dest)?;
945 }
946 "pthread_join" => {
947 let [thread, retval] = this.check_shim(abi, Conv::C, link_name, args)?;
948 let res = this.pthread_join(thread, retval)?;
949 this.write_scalar(res, dest)?;
950 }
951 "pthread_detach" => {
952 let [thread] = this.check_shim(abi, Conv::C, link_name, args)?;
953 let res = this.pthread_detach(thread)?;
954 this.write_scalar(res, dest)?;
955 }
956 "pthread_self" => {
957 let [] = this.check_shim(abi, Conv::C, link_name, args)?;
958 let res = this.pthread_self()?;
959 this.write_scalar(res, dest)?;
960 }
961 "sched_yield" => {
962 let [] = this.check_shim(abi, Conv::C, link_name, args)?;
963 this.sched_yield()?;
964 this.write_null(dest)?;
965 }
966 "nanosleep" => {
967 let [req, rem] = this.check_shim(abi, Conv::C, link_name, args)?;
968 let result = this.nanosleep(req, rem)?;
969 this.write_scalar(result, dest)?;
970 }
971 "sched_getaffinity" => {
972 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
974 let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
975 let pid = this.read_scalar(pid)?.to_u32()?;
976 let cpusetsize = this.read_target_usize(cpusetsize)?;
977 let mask = this.read_pointer(mask)?;
978
979 let thread_id = match pid {
981 0 => this.active_thread(),
982 _ =>
983 throw_unsup_format!(
984 "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"
985 ),
986 };
987
988 let chunk_size = CpuAffinityMask::chunk_size(this);
990
991 if this.ptr_is_null(mask)? {
992 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
993 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
994 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
996 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
997 let cpuset = cpuset.clone();
998 let byte_count =
1000 Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
1001 this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
1002 this.write_null(dest)?;
1003 } else {
1004 this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
1006 }
1007 }
1008 "sched_setaffinity" => {
1009 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
1011 let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
1012 let pid = this.read_scalar(pid)?.to_u32()?;
1013 let cpusetsize = this.read_target_usize(cpusetsize)?;
1014 let mask = this.read_pointer(mask)?;
1015
1016 let thread_id = match pid {
1018 0 => this.active_thread(),
1019 _ =>
1020 throw_unsup_format!(
1021 "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"
1022 ),
1023 };
1024
1025 if this.ptr_is_null(mask)? {
1026 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
1027 } else {
1028 let bits_slice =
1032 this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
1033 let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
1035 std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
1036 match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
1037 Some(cpuset) => {
1038 this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
1039 this.write_null(dest)?;
1040 }
1041 None => {
1042 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
1044 }
1045 }
1046 }
1047 }
1048
1049 "isatty" => {
1051 let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
1052 let result = this.isatty(fd)?;
1053 this.write_scalar(result, dest)?;
1054 }
1055 "pthread_atfork" => {
1056 let [prepare, parent, child] = this.check_shim(abi, Conv::C, link_name, args)?;
1057 this.read_pointer(prepare)?;
1058 this.read_pointer(parent)?;
1059 this.read_pointer(child)?;
1060 this.write_null(dest)?;
1062 }
1063 "getentropy" => {
1064 this.check_target_os(
1067 &["linux", "macos", "freebsd", "illumos", "solaris", "android"],
1068 link_name,
1069 )?;
1070 let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
1071 let buf = this.read_pointer(buf)?;
1072 let bufsize = this.read_target_usize(bufsize)?;
1073
1074 if bufsize > 256 {
1080 this.set_last_error_and_return(LibcError("EIO"), dest)?;
1081 } else {
1082 this.gen_random(buf, bufsize)?;
1083 this.write_null(dest)?;
1084 }
1085 }
1086
1087 "strerror_r" => {
1088 let [errnum, buf, buflen] = this.check_shim(abi, Conv::C, link_name, args)?;
1089 let result = this.strerror_r(errnum, buf, buflen)?;
1090 this.write_scalar(result, dest)?;
1091 }
1092
1093 "getrandom" => {
1094 this.check_target_os(
1097 &["linux", "freebsd", "illumos", "solaris", "android"],
1098 link_name,
1099 )?;
1100 let [ptr, len, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
1101 let ptr = this.read_pointer(ptr)?;
1102 let len = this.read_target_usize(len)?;
1103 let _flags = this.read_scalar(flags)?.to_i32()?;
1104 this.gen_random(ptr, len)?;
1106 this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
1107 }
1108 "arc4random_buf" => {
1109 this.check_target_os(&["freebsd", "illumos", "solaris"], link_name)?;
1112 let [ptr, len] = this.check_shim(abi, Conv::C, link_name, args)?;
1113 let ptr = this.read_pointer(ptr)?;
1114 let len = this.read_target_usize(len)?;
1115 this.gen_random(ptr, len)?;
1116 }
1117 "_Unwind_RaiseException" => {
1118 this.check_target_os(
1132 &["linux", "freebsd", "illumos", "solaris", "android", "macos"],
1133 link_name,
1134 )?;
1135 let [payload] = this.check_shim(abi, Conv::C, link_name, args)?;
1137 this.handle_miri_start_unwind(payload)?;
1138 return interp_ok(EmulateItemResult::NeedsUnwind);
1139 }
1140 "getuid" | "geteuid" => {
1141 let [] = this.check_shim(abi, Conv::C, link_name, args)?;
1142 this.write_int(UID, dest)?;
1144 }
1145
1146 "pthread_attr_getguardsize" if this.frame_in_std() => {
1149 let [_attr, guard_size] = this.check_shim(abi, Conv::C, link_name, args)?;
1150 let guard_size_layout = this.machine.layouts.usize;
1151 let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
1152 this.write_scalar(
1153 Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
1154 &guard_size,
1155 )?;
1156
1157 this.write_null(dest)?;
1159 }
1160
1161 "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
1162 let [_] = this.check_shim(abi, Conv::C, link_name, args)?;
1163 this.write_null(dest)?;
1164 }
1165 "pthread_attr_setstacksize" if this.frame_in_std() => {
1166 let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?;
1167 this.write_null(dest)?;
1168 }
1169
1170 "pthread_attr_getstack" if this.frame_in_std() => {
1171 let [attr_place, addr_place, size_place] =
1174 this.check_shim(abi, Conv::C, link_name, args)?;
1175 let _attr_place =
1176 this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
1177 let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?;
1178 let size_place = this.deref_pointer_as(size_place, this.machine.layouts.usize)?;
1179
1180 this.write_scalar(
1181 Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
1182 &addr_place,
1183 )?;
1184 this.write_scalar(
1185 Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
1186 &size_place,
1187 )?;
1188
1189 this.write_null(dest)?;
1191 }
1192
1193 "signal" | "sigaltstack" if this.frame_in_std() => {
1194 let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?;
1195 this.write_null(dest)?;
1196 }
1197 "sigaction" | "mprotect" if this.frame_in_std() => {
1198 let [_, _, _] = this.check_shim(abi, Conv::C, link_name, args)?;
1199 this.write_null(dest)?;
1200 }
1201
1202 "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
1203 let [uid, pwd, buf, buflen, result] =
1205 this.check_shim(abi, Conv::C, link_name, args)?;
1206 this.check_no_isolation("`getpwuid_r`")?;
1207
1208 let uid = this.read_scalar(uid)?.to_u32()?;
1209 let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?;
1210 let buf = this.read_pointer(buf)?;
1211 let buflen = this.read_target_usize(buflen)?;
1212 let result = this.deref_pointer_as(result, this.machine.layouts.mut_raw_ptr)?;
1213
1214 if uid != UID {
1216 throw_unsup_format!("`getpwuid_r` on other users is not supported");
1217 }
1218
1219 this.write_uninit(&pwd)?;
1222
1223 #[allow(deprecated)]
1225 let home_dir = std::env::home_dir().unwrap();
1226 let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
1227 let pw_dir = this.project_field_named(&pwd, "pw_dir")?;
1228 this.write_pointer(buf, &pw_dir)?;
1229
1230 if written {
1231 this.write_pointer(pwd.ptr(), &result)?;
1232 this.write_null(dest)?;
1233 } else {
1234 this.write_null(&result)?;
1235 this.write_scalar(this.eval_libc("ERANGE"), dest)?;
1236 }
1237 }
1238
1239 _ => {
1241 let target_os = &*this.tcx.sess.target.os;
1242 return match target_os {
1243 "android" =>
1244 android::EvalContextExt::emulate_foreign_item_inner(
1245 this, link_name, abi, args, dest,
1246 ),
1247 "freebsd" =>
1248 freebsd::EvalContextExt::emulate_foreign_item_inner(
1249 this, link_name, abi, args, dest,
1250 ),
1251 "linux" =>
1252 linux::EvalContextExt::emulate_foreign_item_inner(
1253 this, link_name, abi, args, dest,
1254 ),
1255 "macos" =>
1256 macos::EvalContextExt::emulate_foreign_item_inner(
1257 this, link_name, abi, args, dest,
1258 ),
1259 "solaris" | "illumos" =>
1260 solarish::EvalContextExt::emulate_foreign_item_inner(
1261 this, link_name, abi, args, dest,
1262 ),
1263 _ => interp_ok(EmulateItemResult::NotSupported),
1264 };
1265 }
1266 };
1267
1268 interp_ok(EmulateItemResult::NeedsReturn)
1269 }
1270}