1use std::ffi::OsStr;
2use std::str;
3
4use rustc_abi::{CanonAbi, ExternAbi, Size};
5use rustc_middle::ty::Ty;
6use rustc_span::Symbol;
7use rustc_target::callconv::FnAbi;
8
9use self::shims::unix::android::foreign_items as android;
10use self::shims::unix::freebsd::foreign_items as freebsd;
11use self::shims::unix::linux::foreign_items as linux;
12use self::shims::unix::macos::foreign_items as macos;
13use self::shims::unix::solarish::foreign_items as solarish;
14use crate::concurrency::cpu_affinity::CpuAffinityMask;
15use crate::shims::alloc::EvalContextExt as _;
16use crate::shims::unix::*;
17use crate::*;
18
19pub fn is_dyn_sym(name: &str, target_os: &str) -> bool {
20 match name {
21 "isatty" => true,
23 "signal" => true,
26 "getentropy" | "getrandom" => true,
28 _ =>
30 match target_os {
31 "android" => android::is_dyn_sym(name),
32 "freebsd" => freebsd::is_dyn_sym(name),
33 "linux" => linux::is_dyn_sym(name),
34 "macos" => macos::is_dyn_sym(name),
35 "solaris" | "illumos" => solarish::is_dyn_sym(name),
36 _ => false,
37 },
38 }
39}
40
41impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
42pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
43 fn sysconf(&mut self, val: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
45 let this = self.eval_context_mut();
46
47 let name = this.read_scalar(val)?.to_i32()?;
48 let sysconfs: &[(&str, fn(&MiriInterpCx<'_>) -> Scalar)] = &[
51 ("_SC_PAGESIZE", |this| Scalar::from_int(this.machine.page_size, this.pointer_size())),
52 ("_SC_PAGE_SIZE", |this| Scalar::from_int(this.machine.page_size, this.pointer_size())),
53 ("_SC_NPROCESSORS_CONF", |this| {
54 Scalar::from_int(this.machine.num_cpus, this.pointer_size())
55 }),
56 ("_SC_NPROCESSORS_ONLN", |this| {
57 Scalar::from_int(this.machine.num_cpus, this.pointer_size())
58 }),
59 ("_SC_GETPW_R_SIZE_MAX", |this| Scalar::from_int(512, this.pointer_size())),
62 ("_SC_OPEN_MAX", |this| Scalar::from_int(2_i32.pow(16), this.pointer_size())),
67 ];
68 for &(sysconf_name, value) in sysconfs {
69 let sysconf_name = this.eval_libc_i32(sysconf_name);
70 if sysconf_name == name {
71 return interp_ok(value(this));
72 }
73 }
74 throw_unsup_format!("unimplemented sysconf name: {}", name)
75 }
76
77 fn strerror_r(
78 &mut self,
79 errnum: &OpTy<'tcx>,
80 buf: &OpTy<'tcx>,
81 buflen: &OpTy<'tcx>,
82 ) -> InterpResult<'tcx, Scalar> {
83 let this = self.eval_context_mut();
84
85 let errnum = this.read_scalar(errnum)?;
86 let buf = this.read_pointer(buf)?;
87 let buflen = this.read_target_usize(buflen)?;
88 let error = this.try_errnum_to_io_error(errnum)?;
89 let formatted = match error {
90 Some(err) => format!("{err}"),
91 None => format!("<unknown errnum in strerror_r: {errnum}>"),
92 };
93 let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?;
94 if complete {
95 interp_ok(Scalar::from_i32(0))
96 } else {
97 interp_ok(Scalar::from_i32(this.eval_libc_i32("ERANGE")))
98 }
99 }
100
101 fn emulate_foreign_item_inner(
102 &mut self,
103 link_name: Symbol,
104 abi: &FnAbi<'tcx, Ty<'tcx>>,
105 args: &[OpTy<'tcx>],
106 dest: &MPlaceTy<'tcx>,
107 ) -> InterpResult<'tcx, EmulateItemResult> {
108 let this = self.eval_context_mut();
109
110 match link_name.as_str() {
112 "getenv" => {
114 let [name] = this.check_shim_abi(
115 link_name,
116 abi,
117 ExternAbi::C { unwind: false },
118 [this.machine.layouts.const_raw_ptr.ty],
119 this.machine.layouts.mut_raw_ptr.ty,
120 args,
121 )?;
122 let result = this.getenv(name)?;
123 this.write_pointer(result, dest)?;
124 }
125 "unsetenv" => {
126 let [name] = this.check_shim_abi(
127 link_name,
128 abi,
129 ExternAbi::C { unwind: false },
130 [this.machine.layouts.const_raw_ptr.ty],
131 this.tcx.types.i32,
132 args,
133 )?;
134 let result = this.unsetenv(name)?;
135 this.write_scalar(result, dest)?;
136 }
137 "setenv" => {
138 let [name, value, overwrite] = this.check_shim_abi(
139 link_name,
140 abi,
141 ExternAbi::C { unwind: false },
142 [
143 this.machine.layouts.const_raw_ptr.ty,
144 this.machine.layouts.const_raw_ptr.ty,
145 this.tcx.types.i32,
146 ],
147 this.tcx.types.i32,
148 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_abi(
156 link_name,
157 abi,
158 ExternAbi::C { unwind: false },
159 [this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.usize],
160 this.machine.layouts.mut_raw_ptr.ty,
161 args,
162 )?;
163 let result = this.getcwd(buf, size)?;
164 this.write_pointer(result, dest)?;
165 }
166 "chdir" => {
167 let [path] = this.check_shim_abi(
168 link_name,
169 abi,
170 ExternAbi::C { unwind: false },
171 [this.machine.layouts.const_raw_ptr.ty],
172 this.tcx.types.i32,
173 args,
174 )?;
175 let result = this.chdir(path)?;
176 this.write_scalar(result, dest)?;
177 }
178 "getpid" => {
179 let [] = this.check_shim_abi(
180 link_name,
181 abi,
182 ExternAbi::C { unwind: false },
183 [],
184 this.libc_ty_layout("pid_t").ty,
185 args,
186 )?;
187 let result = this.getpid()?;
188 this.write_scalar(result, dest)?;
189 }
190 "sysconf" => {
191 let [val] = this.check_shim_abi(
192 link_name,
193 abi,
194 ExternAbi::C { unwind: false },
195 [this.tcx.types.i32],
196 this.tcx.types.isize,
197 args,
198 )?;
199 let result = this.sysconf(val)?;
200 this.write_scalar(result, dest)?;
201 }
202 "read" => {
204 let [fd, buf, count] = this.check_shim_abi(
205 link_name,
206 abi,
207 ExternAbi::C { unwind: false },
208 [this.tcx.types.i32, this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.usize],
209 this.tcx.types.isize,
210 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_abi(
219 link_name,
220 abi,
221 ExternAbi::C { unwind: false },
222 [
223 this.tcx.types.i32,
224 this.machine.layouts.const_raw_ptr.ty,
225 this.tcx.types.usize,
226 ],
227 this.tcx.types.isize,
228 args,
229 )?;
230 let fd = this.read_scalar(fd)?.to_i32()?;
231 let buf = this.read_pointer(buf)?;
232 let count = this.read_target_usize(n)?;
233 trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
234 this.write(fd, buf, count, None, dest)?;
235 }
236 "pread" => {
237 let off_t = this.libc_ty_layout("off_t");
238 let [fd, buf, count, offset] = this.check_shim_abi(
239 link_name,
240 abi,
241 ExternAbi::C { unwind: false },
242 [
243 this.tcx.types.i32,
244 this.machine.layouts.mut_raw_ptr.ty,
245 this.tcx.types.usize,
246 off_t.ty,
247 ],
248 this.tcx.types.isize,
249 args,
250 )?;
251 let fd = this.read_scalar(fd)?.to_i32()?;
252 let buf = this.read_pointer(buf)?;
253 let count = this.read_target_usize(count)?;
254 let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
255 this.read(fd, buf, count, Some(offset), dest)?;
256 }
257 "pwrite" => {
258 let off_t = this.libc_ty_layout("off_t");
259 let [fd, buf, n, offset] = this.check_shim_abi(
260 link_name,
261 abi,
262 ExternAbi::C { unwind: false },
263 [
264 this.tcx.types.i32,
265 this.machine.layouts.const_raw_ptr.ty,
266 this.tcx.types.usize,
267 off_t.ty,
268 ],
269 this.tcx.types.isize,
270 args,
271 )?;
272 let fd = this.read_scalar(fd)?.to_i32()?;
273 let buf = this.read_pointer(buf)?;
274 let count = this.read_target_usize(n)?;
275 let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
276 trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
277 this.write(fd, buf, count, Some(offset), dest)?;
278 }
279 "pread64" => {
280 let off64_t = this.libc_ty_layout("off64_t");
281 let [fd, buf, count, offset] = this.check_shim_abi(
282 link_name,
283 abi,
284 ExternAbi::C { unwind: false },
285 [
286 this.tcx.types.i32,
287 this.machine.layouts.mut_raw_ptr.ty,
288 this.tcx.types.usize,
289 off64_t.ty,
290 ],
291 this.tcx.types.isize,
292 args,
293 )?;
294 let fd = this.read_scalar(fd)?.to_i32()?;
295 let buf = this.read_pointer(buf)?;
296 let count = this.read_target_usize(count)?;
297 let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
298 this.read(fd, buf, count, Some(offset), dest)?;
299 }
300 "pwrite64" => {
301 let off64_t = this.libc_ty_layout("off64_t");
302 let [fd, buf, n, offset] = this.check_shim_abi(
303 link_name,
304 abi,
305 ExternAbi::C { unwind: false },
306 [
307 this.tcx.types.i32,
308 this.machine.layouts.const_raw_ptr.ty,
309 this.tcx.types.usize,
310 off64_t.ty,
311 ],
312 this.tcx.types.isize,
313 args,
314 )?;
315 let fd = this.read_scalar(fd)?.to_i32()?;
316 let buf = this.read_pointer(buf)?;
317 let count = this.read_target_usize(n)?;
318 let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
319 trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
320 this.write(fd, buf, count, Some(offset), dest)?;
321 }
322 "close" => {
323 let [fd] = this.check_shim_abi(
324 link_name,
325 abi,
326 ExternAbi::C { unwind: false },
327 [this.tcx.types.i32],
328 this.tcx.types.i32,
329 args,
330 )?;
331 let result = this.close(fd)?;
332 this.write_scalar(result, dest)?;
333 }
334 "fcntl" => {
335 let ([fd_num, cmd], varargs) =
336 this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
337 let result = this.fcntl(fd_num, cmd, varargs)?;
338 this.write_scalar(result, dest)?;
339 }
340 "dup" => {
341 let [old_fd] = this.check_shim_abi(
342 link_name,
343 abi,
344 ExternAbi::C { unwind: false },
345 [this.tcx.types.i32],
346 this.tcx.types.i32,
347 args,
348 )?;
349 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
350 let new_fd = this.dup(old_fd)?;
351 this.write_scalar(new_fd, dest)?;
352 }
353 "dup2" => {
354 let [old_fd, new_fd] = this.check_shim_abi(
355 link_name,
356 abi,
357 ExternAbi::C { unwind: false },
358 [this.tcx.types.i32, this.tcx.types.i32],
359 this.tcx.types.i32,
360 args,
361 )?;
362 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
363 let new_fd = this.read_scalar(new_fd)?.to_i32()?;
364 let result = this.dup2(old_fd, new_fd)?;
365 this.write_scalar(result, dest)?;
366 }
367 "flock" => {
368 this.check_target_os(&["linux", "freebsd", "macos", "illumos"], link_name)?;
370 let [fd, op] = this.check_shim_abi(
371 link_name,
372 abi,
373 ExternAbi::C { unwind: false },
374 [this.tcx.types.i32, this.tcx.types.i32],
375 this.tcx.types.i32,
376 args,
377 )?;
378 let fd = this.read_scalar(fd)?.to_i32()?;
379 let op = this.read_scalar(op)?.to_i32()?;
380 let result = this.flock(fd, op)?;
381 this.write_scalar(result, dest)?;
382 }
383
384 "open" | "open64" => {
386 let ([path_raw, flag], varargs) =
389 this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
390 let result = this.open(path_raw, flag, varargs)?;
391 this.write_scalar(result, dest)?;
392 }
393 "unlink" => {
394 let [path] = this.check_shim_abi(
395 link_name,
396 abi,
397 ExternAbi::C { unwind: false },
398 [this.machine.layouts.const_raw_ptr.ty],
399 this.tcx.types.i32,
400 args,
401 )?;
402 let result = this.unlink(path)?;
403 this.write_scalar(result, dest)?;
404 }
405 "symlink" => {
406 let [target, linkpath] = this.check_shim_abi(
407 link_name,
408 abi,
409 ExternAbi::C { unwind: false },
410 [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.const_raw_ptr.ty],
411 this.tcx.types.i32,
412 args,
413 )?;
414 let result = this.symlink(target, linkpath)?;
415 this.write_scalar(result, dest)?;
416 }
417 "rename" => {
418 let [oldpath, newpath] = this.check_shim_abi(
419 link_name,
420 abi,
421 ExternAbi::C { unwind: false },
422 [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.const_raw_ptr.ty],
423 this.tcx.types.i32,
424 args,
425 )?;
426 let result = this.rename(oldpath, newpath)?;
427 this.write_scalar(result, dest)?;
428 }
429 "mkdir" => {
430 let [path, mode] = this.check_shim_abi(
431 link_name,
432 abi,
433 ExternAbi::C { unwind: false },
434 [this.machine.layouts.const_raw_ptr.ty, this.libc_ty_layout("mode_t").ty],
435 this.tcx.types.i32,
436 args,
437 )?;
438 let result = this.mkdir(path, mode)?;
439 this.write_scalar(result, dest)?;
440 }
441 "rmdir" => {
442 let [path] = this.check_shim_abi(
443 link_name,
444 abi,
445 ExternAbi::C { unwind: false },
446 [this.machine.layouts.const_raw_ptr.ty],
447 this.tcx.types.i32,
448 args,
449 )?;
450 let result = this.rmdir(path)?;
451 this.write_scalar(result, dest)?;
452 }
453 "opendir" => {
454 let [name] = this.check_shim_abi(
455 link_name,
456 abi,
457 ExternAbi::C { unwind: false },
458 [this.machine.layouts.const_raw_ptr.ty],
459 this.machine.layouts.mut_raw_ptr.ty,
460 args,
461 )?;
462 let result = this.opendir(name)?;
463 this.write_scalar(result, dest)?;
464 }
465 "closedir" => {
466 let [dirp] = this.check_shim_abi(
467 link_name,
468 abi,
469 ExternAbi::C { unwind: false },
470 [this.machine.layouts.mut_raw_ptr.ty],
471 this.tcx.types.i32,
472 args,
473 )?;
474 let result = this.closedir(dirp)?;
475 this.write_scalar(result, dest)?;
476 }
477 "lseek64" => {
478 let off64_t = this.libc_ty_layout("off64_t");
479 let [fd, offset, whence] = this.check_shim_abi(
480 link_name,
481 abi,
482 ExternAbi::C { unwind: false },
483 [this.tcx.types.i32, off64_t.ty, this.tcx.types.i32],
484 off64_t.ty,
485 args,
486 )?;
487 let fd = this.read_scalar(fd)?.to_i32()?;
488 let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
489 let whence = this.read_scalar(whence)?.to_i32()?;
490 this.lseek64(fd, offset, whence, dest)?;
491 }
492 "lseek" => {
493 let off_t = this.libc_ty_layout("off_t");
494 let [fd, offset, whence] = this.check_shim_abi(
495 link_name,
496 abi,
497 ExternAbi::C { unwind: false },
498 [this.tcx.types.i32, off_t.ty, this.tcx.types.i32],
499 off_t.ty,
500 args,
501 )?;
502 let fd = this.read_scalar(fd)?.to_i32()?;
503 let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
504 let whence = this.read_scalar(whence)?.to_i32()?;
505 this.lseek64(fd, offset, whence, dest)?;
506 }
507 "ftruncate64" => {
508 let off64_t = this.libc_ty_layout("off64_t");
509 let [fd, length] = this.check_shim_abi(
510 link_name,
511 abi,
512 ExternAbi::C { unwind: false },
513 [this.tcx.types.i32, off64_t.ty],
514 this.tcx.types.i32,
515 args,
516 )?;
517 let fd = this.read_scalar(fd)?.to_i32()?;
518 let length = this.read_scalar(length)?.to_int(off64_t.size)?;
519 let result = this.ftruncate64(fd, length)?;
520 this.write_scalar(result, dest)?;
521 }
522 "ftruncate" => {
523 let off_t = this.libc_ty_layout("off_t");
524 let [fd, length] = this.check_shim_abi(
525 link_name,
526 abi,
527 ExternAbi::C { unwind: false },
528 [this.tcx.types.i32, off_t.ty],
529 this.tcx.types.i32,
530 args,
531 )?;
532 let fd = this.read_scalar(fd)?.to_i32()?;
533 let length = this.read_scalar(length)?.to_int(off_t.size)?;
534 let result = this.ftruncate64(fd, length)?;
535 this.write_scalar(result, dest)?;
536 }
537 "fsync" => {
538 let [fd] = this.check_shim_abi(
539 link_name,
540 abi,
541 ExternAbi::C { unwind: false },
542 [this.tcx.types.i32],
543 this.tcx.types.i32,
544 args,
545 )?;
546 let result = this.fsync(fd)?;
547 this.write_scalar(result, dest)?;
548 }
549 "fdatasync" => {
550 let [fd] = this.check_shim_abi(
551 link_name,
552 abi,
553 ExternAbi::C { unwind: false },
554 [this.tcx.types.i32],
555 this.tcx.types.i32,
556 args,
557 )?;
558 let result = this.fdatasync(fd)?;
559 this.write_scalar(result, dest)?;
560 }
561 "readlink" => {
562 let [pathname, buf, bufsize] = this.check_shim_abi(
563 link_name,
564 abi,
565 ExternAbi::C { unwind: false },
566 [
567 this.machine.layouts.const_raw_ptr.ty,
568 this.machine.layouts.mut_raw_ptr.ty,
569 this.tcx.types.usize,
570 ],
571 this.tcx.types.isize,
572 args,
573 )?;
574 let result = this.readlink(pathname, buf, bufsize)?;
575 this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
576 }
577 "posix_fadvise" => {
578 let off_t = this.libc_ty_layout("off_t");
579 let [fd, offset, len, advice] = this.check_shim_abi(
580 link_name,
581 abi,
582 ExternAbi::C { unwind: false },
583 [this.tcx.types.i32, off_t.ty, off_t.ty, this.tcx.types.i32],
584 this.tcx.types.i32,
585 args,
586 )?;
587 this.read_scalar(fd)?.to_i32()?;
588 this.read_scalar(offset)?.to_int(off_t.size)?;
589 this.read_scalar(len)?.to_int(off_t.size)?;
590 this.read_scalar(advice)?.to_i32()?;
591 this.write_null(dest)?;
593 }
594 "realpath" => {
595 let [path, resolved_path] = this.check_shim_abi(
596 link_name,
597 abi,
598 ExternAbi::C { unwind: false },
599 [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
600 this.machine.layouts.mut_raw_ptr.ty,
601 args,
602 )?;
603 let result = this.realpath(path, resolved_path)?;
604 this.write_scalar(result, dest)?;
605 }
606 "mkstemp" => {
607 let [template] = this.check_shim_abi(
608 link_name,
609 abi,
610 ExternAbi::C { unwind: false },
611 [this.machine.layouts.mut_raw_ptr.ty],
612 this.tcx.types.i32,
613 args,
614 )?;
615 let result = this.mkstemp(template)?;
616 this.write_scalar(result, dest)?;
617 }
618
619 "socketpair" => {
621 let [domain, type_, protocol, sv] = this.check_shim_abi(
622 link_name,
623 abi,
624 ExternAbi::C { unwind: false },
625 [
626 this.tcx.types.i32,
627 this.tcx.types.i32,
628 this.tcx.types.i32,
629 this.machine.layouts.mut_raw_ptr.ty,
630 ],
631 this.tcx.types.i32,
632 args,
633 )?;
634 let result = this.socketpair(domain, type_, protocol, sv)?;
635 this.write_scalar(result, dest)?;
636 }
637 "pipe" => {
638 let [pipefd] = this.check_shim_abi(
639 link_name,
640 abi,
641 ExternAbi::C { unwind: false },
642 [this.machine.layouts.mut_raw_ptr.ty],
643 this.tcx.types.i32,
644 args,
645 )?;
646 let result = this.pipe2(pipefd, None)?;
647 this.write_scalar(result, dest)?;
648 }
649 "pipe2" => {
650 this.check_target_os(&["linux", "freebsd", "solaris", "illumos"], link_name)?;
652 let [pipefd, flags] = this.check_shim_abi(
653 link_name,
654 abi,
655 ExternAbi::C { unwind: false },
656 [this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.i32],
657 this.tcx.types.i32,
658 args,
659 )?;
660 let result = this.pipe2(pipefd, Some(flags))?;
661 this.write_scalar(result, dest)?;
662 }
663
664 "gettimeofday" => {
666 let [tv, tz] = this.check_shim_abi(
667 link_name,
668 abi,
669 ExternAbi::C { unwind: false },
670 [this.machine.layouts.mut_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
671 this.tcx.types.i32,
672 args,
673 )?;
674 let result = this.gettimeofday(tv, tz)?;
675 this.write_scalar(result, dest)?;
676 }
677 "localtime_r" => {
678 let [timep, result_op] = this.check_shim_abi(
679 link_name,
680 abi,
681 ExternAbi::C { unwind: false },
682 [this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
683 this.machine.layouts.mut_raw_ptr.ty,
684 args,
685 )?;
686 let result = this.localtime_r(timep, result_op)?;
687 this.write_pointer(result, dest)?;
688 }
689 "clock_gettime" => {
690 let [clk_id, tp] = this.check_shim_abi(
691 link_name,
692 abi,
693 ExternAbi::C { unwind: false },
694 [this.libc_ty_layout("clockid_t").ty, this.machine.layouts.mut_raw_ptr.ty],
695 this.tcx.types.i32,
696 args,
697 )?;
698 this.clock_gettime(clk_id, tp, dest)?;
699 }
700
701 "posix_memalign" => {
703 let [memptr, align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
704 let result = this.posix_memalign(memptr, align, size)?;
705 this.write_scalar(result, dest)?;
706 }
707
708 "mmap" => {
709 let [addr, length, prot, flags, fd, offset] =
710 this.check_shim(abi, CanonAbi::C, link_name, args)?;
711 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
712 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
713 this.write_scalar(ptr, dest)?;
714 }
715 "munmap" => {
716 let [addr, length] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
717 let result = this.munmap(addr, length)?;
718 this.write_scalar(result, dest)?;
719 }
720
721 "reallocarray" => {
722 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
724 let [ptr, nmemb, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
725 let ptr = this.read_pointer(ptr)?;
726 let nmemb = this.read_target_usize(nmemb)?;
727 let size = this.read_target_usize(size)?;
728 match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
734 None => {
735 this.set_last_error(LibcError("ENOMEM"))?;
736 this.write_null(dest)?;
737 }
738 Some(len) => {
739 let res = this.realloc(ptr, len.bytes())?;
740 this.write_pointer(res, dest)?;
741 }
742 }
743 }
744 "aligned_alloc" => {
745 let [align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
748 let res = this.aligned_alloc(align, size)?;
749 this.write_pointer(res, dest)?;
750 }
751
752 "dlsym" => {
754 let [handle, symbol] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
755 this.read_target_usize(handle)?;
756 let symbol = this.read_pointer(symbol)?;
757 let name = this.read_c_str(symbol)?;
758 if let Ok(name) = str::from_utf8(name)
759 && is_dyn_sym(name, &this.tcx.sess.target.os)
760 {
761 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
762 this.write_pointer(ptr, dest)?;
763 } else {
764 this.write_null(dest)?;
765 }
766 }
767
768 "pthread_key_create" => {
770 let [key, dtor] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
771 let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
772 let dtor = this.read_pointer(dtor)?;
773
774 let dtor = if !this.ptr_is_null(dtor)? {
776 Some(this.get_ptr_fn(dtor)?.as_instance()?)
777 } else {
778 None
779 };
780
781 let key_type = key.layout.ty
784 .builtin_deref(true)
785 .ok_or_else(|| err_ub_format!(
786 "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
787 ))?;
788 let key_layout = this.layout_of(key_type)?;
789
790 let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
792 this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place)?;
793
794 this.write_null(dest)?;
796 }
797 "pthread_key_delete" => {
798 let [key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
799 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
800 this.machine.tls.delete_tls_key(key)?;
801 this.write_null(dest)?;
803 }
804 "pthread_getspecific" => {
805 let [key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
806 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
807 let active_thread = this.active_thread();
808 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
809 this.write_scalar(ptr, dest)?;
810 }
811 "pthread_setspecific" => {
812 let [key, new_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
813 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
814 let active_thread = this.active_thread();
815 let new_data = this.read_scalar(new_ptr)?;
816 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
817
818 this.write_null(dest)?;
820 }
821
822 "pthread_mutexattr_init" => {
824 let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
825 this.pthread_mutexattr_init(attr)?;
826 this.write_null(dest)?;
827 }
828 "pthread_mutexattr_settype" => {
829 let [attr, kind] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
830 let result = this.pthread_mutexattr_settype(attr, kind)?;
831 this.write_scalar(result, dest)?;
832 }
833 "pthread_mutexattr_destroy" => {
834 let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
835 this.pthread_mutexattr_destroy(attr)?;
836 this.write_null(dest)?;
837 }
838 "pthread_mutex_init" => {
839 let [mutex, attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
840 this.pthread_mutex_init(mutex, attr)?;
841 this.write_null(dest)?;
842 }
843 "pthread_mutex_lock" => {
844 let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
845 this.pthread_mutex_lock(mutex, dest)?;
846 }
847 "pthread_mutex_trylock" => {
848 let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
849 let result = this.pthread_mutex_trylock(mutex)?;
850 this.write_scalar(result, dest)?;
851 }
852 "pthread_mutex_unlock" => {
853 let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
854 let result = this.pthread_mutex_unlock(mutex)?;
855 this.write_scalar(result, dest)?;
856 }
857 "pthread_mutex_destroy" => {
858 let [mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
859 this.pthread_mutex_destroy(mutex)?;
860 this.write_int(0, dest)?;
861 }
862 "pthread_rwlock_rdlock" => {
863 let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
864 this.pthread_rwlock_rdlock(rwlock, dest)?;
865 }
866 "pthread_rwlock_tryrdlock" => {
867 let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
868 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
869 this.write_scalar(result, dest)?;
870 }
871 "pthread_rwlock_wrlock" => {
872 let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
873 this.pthread_rwlock_wrlock(rwlock, dest)?;
874 }
875 "pthread_rwlock_trywrlock" => {
876 let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
877 let result = this.pthread_rwlock_trywrlock(rwlock)?;
878 this.write_scalar(result, dest)?;
879 }
880 "pthread_rwlock_unlock" => {
881 let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
882 this.pthread_rwlock_unlock(rwlock)?;
883 this.write_null(dest)?;
884 }
885 "pthread_rwlock_destroy" => {
886 let [rwlock] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
887 this.pthread_rwlock_destroy(rwlock)?;
888 this.write_null(dest)?;
889 }
890 "pthread_condattr_init" => {
891 let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
892 this.pthread_condattr_init(attr)?;
893 this.write_null(dest)?;
894 }
895 "pthread_condattr_setclock" => {
896 let [attr, clock_id] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
897 let result = this.pthread_condattr_setclock(attr, clock_id)?;
898 this.write_scalar(result, dest)?;
899 }
900 "pthread_condattr_getclock" => {
901 let [attr, clock_id] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
902 this.pthread_condattr_getclock(attr, clock_id)?;
903 this.write_null(dest)?;
904 }
905 "pthread_condattr_destroy" => {
906 let [attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
907 this.pthread_condattr_destroy(attr)?;
908 this.write_null(dest)?;
909 }
910 "pthread_cond_init" => {
911 let [cond, attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
912 this.pthread_cond_init(cond, attr)?;
913 this.write_null(dest)?;
914 }
915 "pthread_cond_signal" => {
916 let [cond] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
917 this.pthread_cond_signal(cond)?;
918 this.write_null(dest)?;
919 }
920 "pthread_cond_broadcast" => {
921 let [cond] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
922 this.pthread_cond_broadcast(cond)?;
923 this.write_null(dest)?;
924 }
925 "pthread_cond_wait" => {
926 let [cond, mutex] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
927 this.pthread_cond_wait(cond, mutex, dest)?;
928 }
929 "pthread_cond_timedwait" => {
930 let [cond, mutex, abstime] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
931 this.pthread_cond_timedwait(cond, mutex, abstime, dest)?;
932 }
933 "pthread_cond_destroy" => {
934 let [cond] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
935 this.pthread_cond_destroy(cond)?;
936 this.write_null(dest)?;
937 }
938
939 "pthread_create" => {
941 let [thread, attr, start, arg] =
942 this.check_shim(abi, CanonAbi::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, CanonAbi::C, link_name, args)?;
948 this.pthread_join(thread, retval, dest)?;
949 }
950 "pthread_detach" => {
951 let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
952 let res = this.pthread_detach(thread)?;
953 this.write_scalar(res, dest)?;
954 }
955 "pthread_self" => {
956 let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
957 let res = this.pthread_self()?;
958 this.write_scalar(res, dest)?;
959 }
960 "sched_yield" => {
961 let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
962 this.sched_yield()?;
963 this.write_null(dest)?;
964 }
965 "nanosleep" => {
966 let [req, rem] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
967 let result = this.nanosleep(req, rem)?;
968 this.write_scalar(result, dest)?;
969 }
970 "sched_getaffinity" => {
971 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
973 let [pid, cpusetsize, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
974 let pid = this.read_scalar(pid)?.to_u32()?;
975 let cpusetsize = this.read_target_usize(cpusetsize)?;
976 let mask = this.read_pointer(mask)?;
977
978 let thread_id = match pid {
980 0 => this.active_thread(),
981 _ =>
982 throw_unsup_format!(
983 "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"
984 ),
985 };
986
987 let chunk_size = CpuAffinityMask::chunk_size(this);
989
990 if this.ptr_is_null(mask)? {
991 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
992 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
993 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
995 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
996 let cpuset = cpuset.clone();
997 let byte_count =
999 Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
1000 this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
1001 this.write_null(dest)?;
1002 } else {
1003 this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
1005 }
1006 }
1007 "sched_setaffinity" => {
1008 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
1010 let [pid, cpusetsize, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
1011 let pid = this.read_scalar(pid)?.to_u32()?;
1012 let cpusetsize = this.read_target_usize(cpusetsize)?;
1013 let mask = this.read_pointer(mask)?;
1014
1015 let thread_id = match pid {
1017 0 => this.active_thread(),
1018 _ =>
1019 throw_unsup_format!(
1020 "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"
1021 ),
1022 };
1023
1024 if this.ptr_is_null(mask)? {
1025 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
1026 } else {
1027 let bits_slice =
1031 this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
1032 let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
1034 std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
1035 match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
1036 Some(cpuset) => {
1037 this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
1038 this.write_null(dest)?;
1039 }
1040 None => {
1041 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
1043 }
1044 }
1045 }
1046 }
1047
1048 "isatty" => {
1050 let [fd] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
1051 let result = this.isatty(fd)?;
1052 this.write_scalar(result, dest)?;
1053 }
1054 "pthread_atfork" => {
1055 let [prepare, parent, child] =
1056 this.check_shim(abi, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::C, link_name, args)?;
1195 this.write_null(dest)?;
1196 }
1197 "sigaction" | "mprotect" if this.frame_in_std() => {
1198 let [_, _, _] = this.check_shim(abi, CanonAbi::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, CanonAbi::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}