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