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, Conv::C, link_name, args)?;
116 let result = this.getenv(name)?;
117 this.write_pointer(result, dest)?;
118 }
119 "unsetenv" => {
120 let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
121 let result = this.unsetenv(name)?;
122 this.write_scalar(result, dest)?;
123 }
124 "setenv" => {
125 let [name, value, overwrite] = this.check_shim(abi, Conv::C, link_name, args)?;
126 this.read_scalar(overwrite)?.to_i32()?;
127 let result = this.setenv(name, value)?;
128 this.write_scalar(result, dest)?;
129 }
130 "getcwd" => {
131 let [buf, size] = this.check_shim(abi, Conv::C, link_name, args)?;
132 let result = this.getcwd(buf, size)?;
133 this.write_pointer(result, dest)?;
134 }
135 "chdir" => {
136 let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
137 let result = this.chdir(path)?;
138 this.write_scalar(result, dest)?;
139 }
140 "getpid" => {
141 let [] = this.check_shim(abi, Conv::C, link_name, args)?;
142 let result = this.getpid()?;
143 this.write_scalar(result, dest)?;
144 }
145 "sysconf" => {
146 let [val] = this.check_shim(abi, Conv::C, link_name, args)?;
147 let result = this.sysconf(val)?;
148 this.write_scalar(result, dest)?;
149 }
150 "read" => {
152 let [fd, buf, count] = this.check_shim(abi, Conv::C, link_name, args)?;
153 let fd = this.read_scalar(fd)?.to_i32()?;
154 let buf = this.read_pointer(buf)?;
155 let count = this.read_target_usize(count)?;
156 this.read(fd, buf, count, None, dest)?;
157 }
158 "write" => {
159 let [fd, buf, n] = this.check_shim(abi, Conv::C, link_name, args)?;
160 let fd = this.read_scalar(fd)?.to_i32()?;
161 let buf = this.read_pointer(buf)?;
162 let count = this.read_target_usize(n)?;
163 trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
164 this.write(fd, buf, count, None, dest)?;
165 }
166 "pread" => {
167 let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
168 let fd = this.read_scalar(fd)?.to_i32()?;
169 let buf = this.read_pointer(buf)?;
170 let count = this.read_target_usize(count)?;
171 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
172 this.read(fd, buf, count, Some(offset), dest)?;
173 }
174 "pwrite" => {
175 let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
176 let fd = this.read_scalar(fd)?.to_i32()?;
177 let buf = this.read_pointer(buf)?;
178 let count = this.read_target_usize(n)?;
179 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
180 trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
181 this.write(fd, buf, count, Some(offset), dest)?;
182 }
183 "pread64" => {
184 let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
185 let fd = this.read_scalar(fd)?.to_i32()?;
186 let buf = this.read_pointer(buf)?;
187 let count = this.read_target_usize(count)?;
188 let offset =
189 this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
190 this.read(fd, buf, count, Some(offset), dest)?;
191 }
192 "pwrite64" => {
193 let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
194 let fd = this.read_scalar(fd)?.to_i32()?;
195 let buf = this.read_pointer(buf)?;
196 let count = this.read_target_usize(n)?;
197 let offset =
198 this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
199 trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
200 this.write(fd, buf, count, Some(offset), dest)?;
201 }
202 "close" => {
203 let [fd] = this.check_shim_abi(
204 link_name,
205 abi,
206 ExternAbi::C { unwind: false },
207 [this.tcx.types.i32],
208 this.tcx.types.i32,
209 args,
210 )?;
211 let result = this.close(fd)?;
212 this.write_scalar(result, dest)?;
213 }
214 "fcntl" => {
215 let ([fd_num, cmd], varargs) =
216 this.check_shim_variadic(abi, Conv::C, link_name, args)?;
217 let result = this.fcntl(fd_num, cmd, varargs)?;
218 this.write_scalar(result, dest)?;
219 }
220 "dup" => {
221 let [old_fd] = this.check_shim(abi, Conv::C, link_name, args)?;
222 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
223 let new_fd = this.dup(old_fd)?;
224 this.write_scalar(new_fd, dest)?;
225 }
226 "dup2" => {
227 let [old_fd, new_fd] = this.check_shim(abi, Conv::C, link_name, args)?;
228 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
229 let new_fd = this.read_scalar(new_fd)?.to_i32()?;
230 let result = this.dup2(old_fd, new_fd)?;
231 this.write_scalar(result, dest)?;
232 }
233 "flock" => {
234 let [fd, op] = this.check_shim(abi, Conv::C, link_name, args)?;
235 let fd = this.read_scalar(fd)?.to_i32()?;
236 let op = this.read_scalar(op)?.to_i32()?;
237 let result = this.flock(fd, op)?;
238 this.write_scalar(result, dest)?;
239 }
240
241 "open" | "open64" => {
243 let ([path_raw, flag], varargs) =
246 this.check_shim_variadic(abi, Conv::C, link_name, args)?;
247 let result = this.open(path_raw, flag, varargs)?;
248 this.write_scalar(result, dest)?;
249 }
250 "unlink" => {
251 let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
252 let result = this.unlink(path)?;
253 this.write_scalar(result, dest)?;
254 }
255 "symlink" => {
256 let [target, linkpath] = this.check_shim(abi, Conv::C, link_name, args)?;
257 let result = this.symlink(target, linkpath)?;
258 this.write_scalar(result, dest)?;
259 }
260 "rename" => {
261 let [oldpath, newpath] = this.check_shim(abi, Conv::C, link_name, args)?;
262 let result = this.rename(oldpath, newpath)?;
263 this.write_scalar(result, dest)?;
264 }
265 "mkdir" => {
266 let [path, mode] = this.check_shim(abi, Conv::C, link_name, args)?;
267 let result = this.mkdir(path, mode)?;
268 this.write_scalar(result, dest)?;
269 }
270 "rmdir" => {
271 let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
272 let result = this.rmdir(path)?;
273 this.write_scalar(result, dest)?;
274 }
275 "opendir" => {
276 let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
277 let result = this.opendir(name)?;
278 this.write_scalar(result, dest)?;
279 }
280 "closedir" => {
281 let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?;
282 let result = this.closedir(dirp)?;
283 this.write_scalar(result, dest)?;
284 }
285 "lseek64" => {
286 let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?;
287 let fd = this.read_scalar(fd)?.to_i32()?;
288 let offset = this.read_scalar(offset)?.to_i64()?;
289 let whence = this.read_scalar(whence)?.to_i32()?;
290 let result = this.lseek64(fd, offset.into(), whence)?;
291 this.write_scalar(result, dest)?;
292 }
293 "lseek" => {
294 let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?;
295 let fd = this.read_scalar(fd)?.to_i32()?;
296 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
297 let whence = this.read_scalar(whence)?.to_i32()?;
298 let result = this.lseek64(fd, offset, whence)?;
299 this.write_scalar(result, dest)?;
300 }
301 "ftruncate64" => {
302 let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?;
303 let fd = this.read_scalar(fd)?.to_i32()?;
304 let length = this.read_scalar(length)?.to_i64()?;
305 let result = this.ftruncate64(fd, length.into())?;
306 this.write_scalar(result, dest)?;
307 }
308 "ftruncate" => {
309 let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?;
310 let fd = this.read_scalar(fd)?.to_i32()?;
311 let length = this.read_scalar(length)?.to_int(this.libc_ty_layout("off_t").size)?;
312 let result = this.ftruncate64(fd, length)?;
313 this.write_scalar(result, dest)?;
314 }
315 "fsync" => {
316 let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
317 let result = this.fsync(fd)?;
318 this.write_scalar(result, dest)?;
319 }
320 "fdatasync" => {
321 let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
322 let result = this.fdatasync(fd)?;
323 this.write_scalar(result, dest)?;
324 }
325 "readlink" => {
326 let [pathname, buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
327 let result = this.readlink(pathname, buf, bufsize)?;
328 this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
329 }
330 "posix_fadvise" => {
331 let [fd, offset, len, advice] = this.check_shim(abi, Conv::C, link_name, args)?;
332 this.read_scalar(fd)?.to_i32()?;
333 this.read_target_isize(offset)?;
334 this.read_target_isize(len)?;
335 this.read_scalar(advice)?.to_i32()?;
336 this.write_null(dest)?;
338 }
339 "realpath" => {
340 let [path, resolved_path] = this.check_shim(abi, Conv::C, link_name, args)?;
341 let result = this.realpath(path, resolved_path)?;
342 this.write_scalar(result, dest)?;
343 }
344 "mkstemp" => {
345 let [template] = this.check_shim(abi, Conv::C, link_name, args)?;
346 let result = this.mkstemp(template)?;
347 this.write_scalar(result, dest)?;
348 }
349
350 "socketpair" => {
352 let [domain, type_, protocol, sv] =
353 this.check_shim(abi, Conv::C, link_name, args)?;
354 let result = this.socketpair(domain, type_, protocol, sv)?;
355 this.write_scalar(result, dest)?;
356 }
357 "pipe" => {
358 let [pipefd] = this.check_shim(abi, Conv::C, link_name, args)?;
359 let result = this.pipe2(pipefd, None)?;
360 this.write_scalar(result, dest)?;
361 }
362 "pipe2" => {
363 this.check_target_os(&["linux", "freebsd", "solaris", "illumos"], link_name)?;
365 let [pipefd, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
366 let result = this.pipe2(pipefd, Some(flags))?;
367 this.write_scalar(result, dest)?;
368 }
369
370 "gettimeofday" => {
372 let [tv, tz] = this.check_shim(abi, Conv::C, link_name, args)?;
373 let result = this.gettimeofday(tv, tz)?;
374 this.write_scalar(result, dest)?;
375 }
376 "localtime_r" => {
377 let [timep, result_op] = this.check_shim(abi, Conv::C, link_name, args)?;
378 let result = this.localtime_r(timep, result_op)?;
379 this.write_pointer(result, dest)?;
380 }
381 "clock_gettime" => {
382 let [clk_id, tp] = this.check_shim(abi, Conv::C, link_name, args)?;
383 let result = this.clock_gettime(clk_id, tp)?;
384 this.write_scalar(result, dest)?;
385 }
386
387 "posix_memalign" => {
389 let [memptr, align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
390 let result = this.posix_memalign(memptr, align, size)?;
391 this.write_scalar(result, dest)?;
392 }
393
394 "mmap" => {
395 let [addr, length, prot, flags, fd, offset] =
396 this.check_shim(abi, Conv::C, link_name, args)?;
397 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
398 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
399 this.write_scalar(ptr, dest)?;
400 }
401 "munmap" => {
402 let [addr, length] = this.check_shim(abi, Conv::C, link_name, args)?;
403 let result = this.munmap(addr, length)?;
404 this.write_scalar(result, dest)?;
405 }
406
407 "reallocarray" => {
408 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
410 let [ptr, nmemb, size] = this.check_shim(abi, Conv::C, link_name, args)?;
411 let ptr = this.read_pointer(ptr)?;
412 let nmemb = this.read_target_usize(nmemb)?;
413 let size = this.read_target_usize(size)?;
414 match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
420 None => {
421 this.set_last_error(LibcError("ENOMEM"))?;
422 this.write_null(dest)?;
423 }
424 Some(len) => {
425 let res = this.realloc(ptr, len.bytes())?;
426 this.write_pointer(res, dest)?;
427 }
428 }
429 }
430 "aligned_alloc" => {
431 let [align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
434 let res = this.aligned_alloc(align, size)?;
435 this.write_pointer(res, dest)?;
436 }
437
438 "dlsym" => {
440 let [handle, symbol] = this.check_shim(abi, Conv::C, link_name, args)?;
441 this.read_target_usize(handle)?;
442 let symbol = this.read_pointer(symbol)?;
443 let name = this.read_c_str(symbol)?;
444 if let Ok(name) = str::from_utf8(name)
445 && is_dyn_sym(name, &this.tcx.sess.target.os)
446 {
447 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
448 this.write_pointer(ptr, dest)?;
449 } else {
450 this.write_null(dest)?;
451 }
452 }
453
454 "pthread_key_create" => {
456 let [key, dtor] = this.check_shim(abi, Conv::C, link_name, args)?;
457 let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
458 let dtor = this.read_pointer(dtor)?;
459
460 let dtor = if !this.ptr_is_null(dtor)? {
462 Some(this.get_ptr_fn(dtor)?.as_instance()?)
463 } else {
464 None
465 };
466
467 let key_type = key.layout.ty
470 .builtin_deref(true)
471 .ok_or_else(|| err_ub_format!(
472 "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
473 ))?;
474 let key_layout = this.layout_of(key_type)?;
475
476 let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
478 this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place)?;
479
480 this.write_null(dest)?;
482 }
483 "pthread_key_delete" => {
484 let [key] = this.check_shim(abi, Conv::C, link_name, args)?;
485 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
486 this.machine.tls.delete_tls_key(key)?;
487 this.write_null(dest)?;
489 }
490 "pthread_getspecific" => {
491 let [key] = this.check_shim(abi, Conv::C, link_name, args)?;
492 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
493 let active_thread = this.active_thread();
494 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
495 this.write_scalar(ptr, dest)?;
496 }
497 "pthread_setspecific" => {
498 let [key, new_ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
499 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
500 let active_thread = this.active_thread();
501 let new_data = this.read_scalar(new_ptr)?;
502 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
503
504 this.write_null(dest)?;
506 }
507
508 "pthread_mutexattr_init" => {
510 let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
511 this.pthread_mutexattr_init(attr)?;
512 this.write_null(dest)?;
513 }
514 "pthread_mutexattr_settype" => {
515 let [attr, kind] = this.check_shim(abi, Conv::C, link_name, args)?;
516 let result = this.pthread_mutexattr_settype(attr, kind)?;
517 this.write_scalar(result, dest)?;
518 }
519 "pthread_mutexattr_destroy" => {
520 let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
521 this.pthread_mutexattr_destroy(attr)?;
522 this.write_null(dest)?;
523 }
524 "pthread_mutex_init" => {
525 let [mutex, attr] = this.check_shim(abi, Conv::C, link_name, args)?;
526 this.pthread_mutex_init(mutex, attr)?;
527 this.write_null(dest)?;
528 }
529 "pthread_mutex_lock" => {
530 let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
531 this.pthread_mutex_lock(mutex, dest)?;
532 }
533 "pthread_mutex_trylock" => {
534 let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
535 let result = this.pthread_mutex_trylock(mutex)?;
536 this.write_scalar(result, dest)?;
537 }
538 "pthread_mutex_unlock" => {
539 let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
540 let result = this.pthread_mutex_unlock(mutex)?;
541 this.write_scalar(result, dest)?;
542 }
543 "pthread_mutex_destroy" => {
544 let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
545 this.pthread_mutex_destroy(mutex)?;
546 this.write_int(0, dest)?;
547 }
548 "pthread_rwlock_rdlock" => {
549 let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
550 this.pthread_rwlock_rdlock(rwlock, dest)?;
551 }
552 "pthread_rwlock_tryrdlock" => {
553 let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
554 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
555 this.write_scalar(result, dest)?;
556 }
557 "pthread_rwlock_wrlock" => {
558 let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
559 this.pthread_rwlock_wrlock(rwlock, dest)?;
560 }
561 "pthread_rwlock_trywrlock" => {
562 let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
563 let result = this.pthread_rwlock_trywrlock(rwlock)?;
564 this.write_scalar(result, dest)?;
565 }
566 "pthread_rwlock_unlock" => {
567 let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
568 this.pthread_rwlock_unlock(rwlock)?;
569 this.write_null(dest)?;
570 }
571 "pthread_rwlock_destroy" => {
572 let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
573 this.pthread_rwlock_destroy(rwlock)?;
574 this.write_null(dest)?;
575 }
576 "pthread_condattr_init" => {
577 let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
578 this.pthread_condattr_init(attr)?;
579 this.write_null(dest)?;
580 }
581 "pthread_condattr_setclock" => {
582 let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?;
583 let result = this.pthread_condattr_setclock(attr, clock_id)?;
584 this.write_scalar(result, dest)?;
585 }
586 "pthread_condattr_getclock" => {
587 let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?;
588 this.pthread_condattr_getclock(attr, clock_id)?;
589 this.write_null(dest)?;
590 }
591 "pthread_condattr_destroy" => {
592 let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
593 this.pthread_condattr_destroy(attr)?;
594 this.write_null(dest)?;
595 }
596 "pthread_cond_init" => {
597 let [cond, attr] = this.check_shim(abi, Conv::C, link_name, args)?;
598 this.pthread_cond_init(cond, attr)?;
599 this.write_null(dest)?;
600 }
601 "pthread_cond_signal" => {
602 let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
603 this.pthread_cond_signal(cond)?;
604 this.write_null(dest)?;
605 }
606 "pthread_cond_broadcast" => {
607 let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
608 this.pthread_cond_broadcast(cond)?;
609 this.write_null(dest)?;
610 }
611 "pthread_cond_wait" => {
612 let [cond, mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
613 this.pthread_cond_wait(cond, mutex, dest)?;
614 }
615 "pthread_cond_timedwait" => {
616 let [cond, mutex, abstime] = this.check_shim(abi, Conv::C, link_name, args)?;
617 this.pthread_cond_timedwait(cond, mutex, abstime, dest)?;
618 }
619 "pthread_cond_destroy" => {
620 let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
621 this.pthread_cond_destroy(cond)?;
622 this.write_null(dest)?;
623 }
624
625 "pthread_create" => {
627 let [thread, attr, start, arg] = this.check_shim(abi, Conv::C, link_name, args)?;
628 this.pthread_create(thread, attr, start, arg)?;
629 this.write_null(dest)?;
630 }
631 "pthread_join" => {
632 let [thread, retval] = this.check_shim(abi, Conv::C, link_name, args)?;
633 let res = this.pthread_join(thread, retval)?;
634 this.write_scalar(res, dest)?;
635 }
636 "pthread_detach" => {
637 let [thread] = this.check_shim(abi, Conv::C, link_name, args)?;
638 let res = this.pthread_detach(thread)?;
639 this.write_scalar(res, dest)?;
640 }
641 "pthread_self" => {
642 let [] = this.check_shim(abi, Conv::C, link_name, args)?;
643 let res = this.pthread_self()?;
644 this.write_scalar(res, dest)?;
645 }
646 "sched_yield" => {
647 let [] = this.check_shim(abi, Conv::C, link_name, args)?;
648 this.sched_yield()?;
649 this.write_null(dest)?;
650 }
651 "nanosleep" => {
652 let [req, rem] = this.check_shim(abi, Conv::C, link_name, args)?;
653 let result = this.nanosleep(req, rem)?;
654 this.write_scalar(result, dest)?;
655 }
656 "sched_getaffinity" => {
657 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
659 let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
660 let pid = this.read_scalar(pid)?.to_u32()?;
661 let cpusetsize = this.read_target_usize(cpusetsize)?;
662 let mask = this.read_pointer(mask)?;
663
664 let thread_id = match pid {
666 0 => this.active_thread(),
667 _ =>
668 throw_unsup_format!(
669 "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"
670 ),
671 };
672
673 let chunk_size = CpuAffinityMask::chunk_size(this);
675
676 if this.ptr_is_null(mask)? {
677 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
678 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
679 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
681 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
682 let cpuset = cpuset.clone();
683 let byte_count =
685 Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
686 this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
687 this.write_null(dest)?;
688 } else {
689 this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
691 }
692 }
693 "sched_setaffinity" => {
694 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
696 let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
697 let pid = this.read_scalar(pid)?.to_u32()?;
698 let cpusetsize = this.read_target_usize(cpusetsize)?;
699 let mask = this.read_pointer(mask)?;
700
701 let thread_id = match pid {
703 0 => this.active_thread(),
704 _ =>
705 throw_unsup_format!(
706 "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"
707 ),
708 };
709
710 if this.ptr_is_null(mask)? {
711 this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
712 } else {
713 let bits_slice =
717 this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
718 let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
720 std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
721 match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
722 Some(cpuset) => {
723 this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
724 this.write_null(dest)?;
725 }
726 None => {
727 this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
729 }
730 }
731 }
732 }
733
734 "isatty" => {
736 let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
737 let result = this.isatty(fd)?;
738 this.write_scalar(result, dest)?;
739 }
740 "pthread_atfork" => {
741 let [prepare, parent, child] = this.check_shim(abi, Conv::C, link_name, args)?;
742 this.read_pointer(prepare)?;
743 this.read_pointer(parent)?;
744 this.read_pointer(child)?;
745 this.write_null(dest)?;
747 }
748 "getentropy" => {
749 this.check_target_os(
752 &["linux", "macos", "freebsd", "illumos", "solaris", "android"],
753 link_name,
754 )?;
755 let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
756 let buf = this.read_pointer(buf)?;
757 let bufsize = this.read_target_usize(bufsize)?;
758
759 if bufsize > 256 {
765 this.set_last_error_and_return(LibcError("EIO"), dest)?;
766 } else {
767 this.gen_random(buf, bufsize)?;
768 this.write_null(dest)?;
769 }
770 }
771
772 "strerror_r" => {
773 let [errnum, buf, buflen] = this.check_shim(abi, Conv::C, link_name, args)?;
774 let result = this.strerror_r(errnum, buf, buflen)?;
775 this.write_scalar(result, dest)?;
776 }
777
778 "getrandom" => {
779 this.check_target_os(
782 &["linux", "freebsd", "illumos", "solaris", "android"],
783 link_name,
784 )?;
785 let [ptr, len, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
786 let ptr = this.read_pointer(ptr)?;
787 let len = this.read_target_usize(len)?;
788 let _flags = this.read_scalar(flags)?.to_i32()?;
789 this.gen_random(ptr, len)?;
791 this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
792 }
793 "arc4random_buf" => {
794 this.check_target_os(&["freebsd", "illumos", "solaris"], link_name)?;
797 let [ptr, len] = this.check_shim(abi, Conv::C, link_name, args)?;
798 let ptr = this.read_pointer(ptr)?;
799 let len = this.read_target_usize(len)?;
800 this.gen_random(ptr, len)?;
801 }
802 "_Unwind_RaiseException" => {
803 this.check_target_os(
817 &["linux", "freebsd", "illumos", "solaris", "android", "macos"],
818 link_name,
819 )?;
820 let [payload] = this.check_shim(abi, Conv::C, link_name, args)?;
822 this.handle_miri_start_unwind(payload)?;
823 return interp_ok(EmulateItemResult::NeedsUnwind);
824 }
825 "getuid" | "geteuid" => {
826 let [] = this.check_shim(abi, Conv::C, link_name, args)?;
827 this.write_int(UID, dest)?;
829 }
830
831 "pthread_attr_getguardsize" if this.frame_in_std() => {
834 let [_attr, guard_size] = this.check_shim(abi, Conv::C, link_name, args)?;
835 let guard_size_layout = this.libc_ty_layout("size_t");
836 let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
837 this.write_scalar(
838 Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
839 &guard_size,
840 )?;
841
842 this.write_null(dest)?;
844 }
845
846 "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
847 let [_] = this.check_shim(abi, Conv::C, link_name, args)?;
848 this.write_null(dest)?;
849 }
850 "pthread_attr_setstacksize" if this.frame_in_std() => {
851 let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?;
852 this.write_null(dest)?;
853 }
854
855 "pthread_attr_getstack" if this.frame_in_std() => {
856 let [attr_place, addr_place, size_place] =
859 this.check_shim(abi, Conv::C, link_name, args)?;
860 let _attr_place =
861 this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
862 let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?;
863 let size_place = this.deref_pointer_as(size_place, this.machine.layouts.usize)?;
864
865 this.write_scalar(
866 Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
867 &addr_place,
868 )?;
869 this.write_scalar(
870 Scalar::from_uint(this.machine.stack_size, this.pointer_size()),
871 &size_place,
872 )?;
873
874 this.write_null(dest)?;
876 }
877
878 "signal" | "sigaltstack" if this.frame_in_std() => {
879 let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?;
880 this.write_null(dest)?;
881 }
882 "sigaction" | "mprotect" if this.frame_in_std() => {
883 let [_, _, _] = this.check_shim(abi, Conv::C, link_name, args)?;
884 this.write_null(dest)?;
885 }
886
887 "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
888 let [uid, pwd, buf, buflen, result] =
890 this.check_shim(abi, Conv::C, link_name, args)?;
891 this.check_no_isolation("`getpwuid_r`")?;
892
893 let uid = this.read_scalar(uid)?.to_u32()?;
894 let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?;
895 let buf = this.read_pointer(buf)?;
896 let buflen = this.read_target_usize(buflen)?;
897 let result = this.deref_pointer_as(result, this.machine.layouts.mut_raw_ptr)?;
898
899 if uid != UID {
901 throw_unsup_format!("`getpwuid_r` on other users is not supported");
902 }
903
904 this.write_uninit(&pwd)?;
907
908 #[allow(deprecated)]
910 let home_dir = std::env::home_dir().unwrap();
911 let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
912 let pw_dir = this.project_field_named(&pwd, "pw_dir")?;
913 this.write_pointer(buf, &pw_dir)?;
914
915 if written {
916 this.write_pointer(pwd.ptr(), &result)?;
917 this.write_null(dest)?;
918 } else {
919 this.write_null(&result)?;
920 this.write_scalar(this.eval_libc("ERANGE"), dest)?;
921 }
922 }
923
924 _ => {
926 let target_os = &*this.tcx.sess.target.os;
927 return match target_os {
928 "android" =>
929 android::EvalContextExt::emulate_foreign_item_inner(
930 this, link_name, abi, args, dest,
931 ),
932 "freebsd" =>
933 freebsd::EvalContextExt::emulate_foreign_item_inner(
934 this, link_name, abi, args, dest,
935 ),
936 "linux" =>
937 linux::EvalContextExt::emulate_foreign_item_inner(
938 this, link_name, abi, args, dest,
939 ),
940 "macos" =>
941 macos::EvalContextExt::emulate_foreign_item_inner(
942 this, link_name, abi, args, dest,
943 ),
944 "solaris" | "illumos" =>
945 solarish::EvalContextExt::emulate_foreign_item_inner(
946 this, link_name, abi, args, dest,
947 ),
948 _ => interp_ok(EmulateItemResult::NotSupported),
949 };
950 }
951 };
952
953 interp_ok(EmulateItemResult::NeedsReturn)
954 }
955}