1 //! stdlib implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdlib.h.html 2 3 use core::{convert::TryFrom, intrinsics, iter, mem, ptr, slice}; 4 use rand::{ 5 distributions::{Alphanumeric, Distribution, Uniform}, 6 prng::XorShiftRng, 7 rngs::JitterRng, 8 Rng, SeedableRng, 9 }; 10 11 use crate::unix::header::{ 12 ctype, 13 errno::{self, *}, 14 limits, 15 stdio::flush_io_streams, 16 string::*, 17 unistd::{self, sysconf, _SC_PAGESIZE}, 18 wchar::*, 19 }; 20 21 use crate::unix::{c_str::CStr, fs::File, ld_so, platform}; 22 23 mod rand48; 24 mod random; 25 mod sort; 26 27 pub const EXIT_FAILURE: ::c_int = 1; 28 pub const EXIT_SUCCESS: ::c_int = 0; 29 pub const RAND_MAX: ::c_int = 2_147_483_647; 30 31 //Maximum number of bytes in a multibyte character for the current locale 32 pub const MB_CUR_MAX: ::c_int = 4; 33 //Maximum number of bytes in a multibyte characters for any locale 34 pub const MB_LEN_MAX: ::c_int = 4; 35 36 static mut ATEXIT_FUNCS: [Option<extern "C" fn()>; 32] = [None; 32]; 37 static mut L64A_BUFFER: [::c_char; 7] = [0; 7]; // up to 6 digits plus null terminator 38 static mut RNG: Option<XorShiftRng> = None; 39 40 use lazy_static::lazy_static; 41 lazy_static! { 42 static ref RNG_SAMPLER: Uniform<::c_int> = Uniform::new_inclusive(0, RAND_MAX); 43 } 44 45 #[no_mangle] 46 pub extern "C" fn _Exit(status: ::c_int) { 47 unistd::_exit(status); 48 } 49 50 #[no_mangle] 51 pub unsafe extern "C" fn a64l(s: *const ::c_char) -> ::c_long { 52 // Early return upon null pointer argument 53 if s.is_null() { 54 return 0; 55 } 56 57 // POSIX says only the low-order 32 bits are used. 58 let mut l: i32 = 0; 59 60 // Handle up to 6 input characters (excl. null terminator) 61 for i in 0..6 { 62 let digit_char = *s.offset(i); 63 64 let digit_value = match digit_char { 65 0 => break, // Null terminator encountered 66 46..=57 => { 67 // ./0123456789 represents values 0 to 11. b'.' == 46 68 digit_char - 46 69 } 70 65..=90 => { 71 // A-Z for values 12 to 37. b'A' == 65, 65-12 == 53 72 digit_char - 53 73 } 74 97..=122 => { 75 // a-z for values 38 to 63. b'a' == 97, 97-38 == 59 76 digit_char - 59 77 } 78 _ => return 0, // Early return for anything else 79 }; 80 81 l |= i32::from(digit_value) << 6 * i; 82 } 83 84 ::c_long::from(l) 85 } 86 87 #[no_mangle] 88 pub unsafe extern "C" fn abort() -> ! { 89 eprintln!("Abort"); 90 intrinsics::abort(); 91 } 92 93 #[no_mangle] 94 pub extern "C" fn abs(i: ::c_int) -> ::c_int { 95 i.abs() 96 } 97 98 #[no_mangle] 99 pub unsafe extern "C" fn aligned_alloc(alignment: ::size_t, size: ::size_t) -> *mut ::c_void { 100 if size % alignment == 0 { 101 /* The size-is-multiple-of-alignment requirement is the only 102 * difference between aligned_alloc() and memalign(). */ 103 memalign(alignment, size) 104 } else { 105 platform::errno = ::EINVAL; 106 ptr::null_mut() 107 } 108 } 109 110 #[no_mangle] 111 pub unsafe extern "C" fn atexit(func: Option<extern "C" fn()>) -> ::c_int { 112 for i in 0..ATEXIT_FUNCS.len() { 113 if ATEXIT_FUNCS[i] == None { 114 ATEXIT_FUNCS[i] = func; 115 return 0; 116 } 117 } 118 119 1 120 } 121 122 #[no_mangle] 123 pub unsafe extern "C" fn atof(s: *const ::c_char) -> ::c_double { 124 strtod(s, ptr::null_mut()) 125 } 126 127 macro_rules! dec_num_from_ascii { 128 ($s:expr, $t:ty) => { 129 unsafe { 130 let mut s = $s; 131 // Iterate past whitespace 132 while ctype::isspace(*s as ::c_int) != 0 { 133 s = s.offset(1); 134 } 135 136 // Find out if there is a - sign 137 let neg_sign = match *s { 138 0x2d => { 139 s = s.offset(1); 140 true 141 } 142 // '+' increment s and continue parsing 143 0x2b => { 144 s = s.offset(1); 145 false 146 } 147 _ => false, 148 }; 149 150 let mut n: $t = 0; 151 while ctype::isdigit(*s as ::c_int) != 0 { 152 n = 10 * n - (*s as $t - 0x30); 153 s = s.offset(1); 154 } 155 156 if neg_sign { 157 n 158 } else { 159 -n 160 } 161 } 162 }; 163 } 164 165 #[no_mangle] 166 pub extern "C" fn atoi(s: *const ::c_char) -> ::c_int { 167 dec_num_from_ascii!(s, ::c_int) 168 } 169 170 #[no_mangle] 171 pub extern "C" fn atol(s: *const ::c_char) -> ::c_long { 172 dec_num_from_ascii!(s, ::c_long) 173 } 174 175 #[no_mangle] 176 pub extern "C" fn atoll(s: *const ::c_char) -> ::c_longlong { 177 dec_num_from_ascii!(s, ::c_longlong) 178 } 179 180 unsafe extern "C" fn void_cmp(a: *const ::c_void, b: *const ::c_void) -> ::c_int { 181 *(a as *const i32) - *(b as *const i32) as ::c_int 182 } 183 184 #[no_mangle] 185 pub unsafe extern "C" fn bsearch( 186 key: *const ::c_void, 187 base: *const ::c_void, 188 nel: ::size_t, 189 width: ::size_t, 190 compar: Option<unsafe extern "C" fn(*const ::c_void, *const ::c_void) -> ::c_int>, 191 ) -> *mut ::c_void { 192 let mut start = base; 193 let mut len = nel; 194 let cmp_fn = compar.unwrap_or(void_cmp); 195 while len > 0 { 196 let med = (start as ::size_t + (len >> 1) * width) as *const ::c_void; 197 let diff = cmp_fn(key, med); 198 if diff == 0 { 199 return med as *mut ::c_void; 200 } else if diff > 0 { 201 start = (med as usize + width) as *const ::c_void; 202 len -= 1; 203 } 204 len >>= 1; 205 } 206 ptr::null_mut() 207 } 208 209 #[no_mangle] 210 pub unsafe extern "C" fn calloc(nelem: ::size_t, elsize: ::size_t) -> *mut ::c_void { 211 //Handle possible integer overflow in size calculation 212 match nelem.checked_mul(elsize) { 213 Some(size) => { 214 /* If allocation fails here, errno setting will be handled 215 * by malloc() */ 216 let ptr = malloc(size); 217 if !ptr.is_null() { 218 intrinsics::write_bytes(ptr as *mut u8, 0, size); 219 } 220 ptr 221 } 222 None => { 223 // For overflowing multiplication, we have to set errno here 224 platform::errno = ENOMEM; 225 ptr::null_mut() 226 } 227 } 228 } 229 230 #[repr(C)] 231 pub struct div_t { 232 quot: ::c_int, 233 rem: ::c_int, 234 } 235 236 #[no_mangle] 237 pub extern "C" fn div(numer: ::c_int, denom: ::c_int) -> div_t { 238 div_t { 239 quot: numer / denom, 240 rem: numer % denom, 241 } 242 } 243 244 #[no_mangle] 245 pub unsafe extern "C" fn drand48() -> ::c_double { 246 let new_xsubi_value = rand48::generator_step(&mut rand48::DEFAULT_XSUBI); 247 rand48::f64_from_x(new_xsubi_value) 248 } 249 250 // #[no_mangle] 251 pub extern "C" fn ecvt( 252 _value: ::c_double, 253 _ndigit: ::c_int, 254 _decpt: *mut ::c_int, 255 _sign: *mut ::c_int, 256 ) -> *mut ::c_char { 257 unimplemented!(); 258 } 259 260 #[no_mangle] 261 pub unsafe extern "C" fn erand48(xsubi: *mut ::c_ushort) -> ::c_double { 262 let new_xsubi_value = rand48::generator_step(&mut *(xsubi as *mut [::c_ushort; 3])); 263 rand48::f64_from_x(new_xsubi_value) 264 } 265 266 #[no_mangle] 267 pub unsafe extern "C" fn exit(status: ::c_int) { 268 extern "C" { 269 static __fini_array_start: extern "C" fn(); 270 static __fini_array_end: extern "C" fn(); 271 272 fn pthread_terminate(); 273 fn _fini(); 274 } 275 276 for i in (0..ATEXIT_FUNCS.len()).rev() { 277 if let Some(func) = ATEXIT_FUNCS[i] { 278 (func)(); 279 } 280 } 281 282 // Look for the neighbor functions in memory until the end 283 let mut f = &__fini_array_end as *const _; 284 #[allow(clippy::op_ref)] 285 while f > &__fini_array_start { 286 f = f.offset(-1); 287 (*f)(); 288 } 289 290 _fini(); 291 292 ld_so::fini(); 293 294 pthread_terminate(); 295 296 flush_io_streams(); 297 298 platform::pal::exit(status); 299 } 300 301 // #[no_mangle] 302 pub extern "C" fn fcvt( 303 _value: ::c_double, 304 _ndigit: ::c_int, 305 _decpt: *mut ::c_int, 306 _sign: *mut ::c_int, 307 ) -> *mut ::c_char { 308 unimplemented!(); 309 } 310 311 #[no_mangle] 312 pub unsafe extern "C" fn free(ptr: *mut ::c_void) { 313 platform::free(ptr); 314 } 315 316 // #[no_mangle] 317 pub extern "C" fn gcvt(_value: ::c_double, _ndigit: ::c_int, _buf: *mut ::c_char) -> *mut ::c_char { 318 unimplemented!(); 319 } 320 321 unsafe fn find_env(search: *const ::c_char) -> Option<(usize, *mut ::c_char)> { 322 for (i, mut item) in platform::environ_iter().enumerate() { 323 let mut search = search; 324 loop { 325 let end_of_query = *search == 0 || *search == b'=' as ::c_char; 326 assert_ne!(*item, 0, "environ has an item without value"); 327 if *item == b'=' as ::c_char || end_of_query { 328 if *item == b'=' as ::c_char && end_of_query { 329 // Both keys env here 330 return Some((i, item.add(1))); 331 } else { 332 break; 333 } 334 } 335 336 if *item != *search { 337 break; 338 } 339 340 item = item.add(1); 341 search = search.add(1); 342 } 343 } 344 345 None 346 } 347 348 #[no_mangle] 349 pub unsafe extern "C" fn getenv(name: *const ::c_char) -> *mut ::c_char { 350 find_env(name).map(|val| val.1).unwrap_or(ptr::null_mut()) 351 } 352 353 // #[no_mangle] 354 pub extern "C" fn getsubopt( 355 _optionp: *mut *mut ::c_char, 356 _tokens: *const *mut ::c_char, 357 _valuep: *mut *mut ::c_char, 358 ) -> ::c_int { 359 unimplemented!(); 360 } 361 362 // #[no_mangle] 363 pub extern "C" fn grantpt(_fildes: ::c_int) -> ::c_int { 364 unimplemented!(); 365 } 366 367 #[no_mangle] 368 pub unsafe extern "C" fn initstate( 369 seed: ::c_uint, 370 state: *mut ::c_char, 371 size: ::size_t, 372 ) -> *mut ::c_char { 373 // Ported from musl 374 375 if size < 8 { 376 ptr::null_mut() 377 } else { 378 // TODO: lock? 379 let old_state = random::save_state(); 380 random::N = match size { 381 0..=7 => unreachable!(), // ensured above 382 8..=31 => 0, 383 32..=63 => 7, 384 64..=127 => 15, 385 128..=255 => 31, 386 _ => 63, 387 }; 388 389 random::X_PTR = (state.cast::<[u8; 4]>()).offset(1); 390 random::seed(seed); 391 random::save_state(); 392 // TODO: unlock? 393 394 old_state.cast::<_>() 395 } 396 } 397 398 #[no_mangle] 399 pub unsafe extern "C" fn jrand48(xsubi: *mut ::c_ushort) -> ::c_long { 400 let new_xsubi_value = rand48::generator_step(&mut *(xsubi as *mut [::c_ushort; 3])); 401 rand48::i32_from_x(new_xsubi_value) 402 } 403 404 #[no_mangle] 405 pub unsafe extern "C" fn l64a(value: ::c_long) -> *mut ::c_char { 406 // POSIX says we should only consider the lower 32 bits of value. 407 let value_as_i32 = value as i32; 408 409 /* If we pretend to extend the 32-bit value with 4 binary zeros, we 410 * would get a 36-bit integer. The number of base-64 digits to be 411 * left unused can then be found by taking the number of leading 412 * zeros, dividing by 6 and rounding down (i.e. using integer 413 * division). */ 414 let num_output_digits = usize::try_from(6 - (value_as_i32.leading_zeros() + 4) / 6).unwrap(); 415 416 // Reset buffer (and have null terminator in place for any result) 417 L64A_BUFFER = [0; 7]; 418 419 for i in 0..num_output_digits { 420 // Conversion to ::c_char always succeeds for the range 0..=63 421 let digit_value = ::c_char::try_from((value_as_i32 >> 6 * i) & 63).unwrap(); 422 423 L64A_BUFFER[i] = match digit_value { 424 0..=11 => { 425 // ./0123456789 for values 0 to 11. b'.' == 46 426 46 + digit_value 427 } 428 12..=37 => { 429 // A-Z for values 12 to 37. b'A' == 65, 65-12 == 53 430 53 + digit_value 431 } 432 38..=63 => { 433 // a-z for values 38 to 63. b'a' == 97, 97-38 == 59 434 59 + digit_value 435 } 436 _ => unreachable!(), // Guaranteed by taking "& 63" above 437 }; 438 } 439 440 L64A_BUFFER.as_mut_ptr() 441 } 442 443 #[no_mangle] 444 pub extern "C" fn labs(i: ::c_long) -> ::c_long { 445 i.abs() 446 } 447 448 #[no_mangle] 449 pub unsafe extern "C" fn lcong48(param: *mut ::c_ushort) { 450 // Set DEFAULT_XSUBI buffer from elements 0-2 451 let xsubi_value = rand48::u48_from_ushort_arr3(&*(param as *const [::c_ushort; 3])); 452 rand48::DEFAULT_XSUBI = rand48::ushort_arr3_from_u48(xsubi_value); 453 454 // Set multiplier from elements 3-5 455 rand48::A = rand48::u48_from_ushort_arr3(&*(param.offset(3) as *const [::c_ushort; 3])); 456 457 /* Set addend from element 6. Note that ::c_ushort may be more than 16 458 * bits, thus the cast. */ 459 rand48::C = *param.offset(6) as u16; 460 } 461 462 #[repr(C)] 463 pub struct ldiv_t { 464 quot: ::c_long, 465 rem: ::c_long, 466 } 467 468 #[no_mangle] 469 pub extern "C" fn ldiv(numer: ::c_long, denom: ::c_long) -> ldiv_t { 470 ldiv_t { 471 quot: numer / denom, 472 rem: numer % denom, 473 } 474 } 475 476 #[no_mangle] 477 pub extern "C" fn llabs(i: ::c_longlong) -> ::c_longlong { 478 i.abs() 479 } 480 481 #[repr(C)] 482 pub struct lldiv_t { 483 quot: ::c_longlong, 484 rem: ::c_longlong, 485 } 486 487 #[no_mangle] 488 pub extern "C" fn lldiv(numer: ::c_longlong, denom: ::c_longlong) -> lldiv_t { 489 lldiv_t { 490 quot: numer / denom, 491 rem: numer % denom, 492 } 493 } 494 495 #[no_mangle] 496 pub unsafe extern "C" fn lrand48() -> ::c_long { 497 let new_xsubi_value = rand48::generator_step(&mut rand48::DEFAULT_XSUBI); 498 rand48::u31_from_x(new_xsubi_value) 499 } 500 501 #[no_mangle] 502 pub unsafe extern "C" fn malloc(size: ::size_t) -> *mut ::c_void { 503 let ptr = platform::alloc(size); 504 if ptr.is_null() { 505 platform::errno = ENOMEM; 506 } 507 ptr 508 } 509 510 #[no_mangle] 511 pub unsafe extern "C" fn memalign(alignment: ::size_t, size: ::size_t) -> *mut ::c_void { 512 if alignment.is_power_of_two() { 513 let ptr = platform::alloc_align(size, alignment); 514 if ptr.is_null() { 515 platform::errno = ENOMEM; 516 } 517 ptr 518 } else { 519 platform::errno = EINVAL; 520 ptr::null_mut() 521 } 522 } 523 524 #[no_mangle] 525 pub unsafe extern "C" fn mblen(s: *const ::c_char, n: ::size_t) -> ::c_int { 526 let mut wc: ::wchar_t = 0; 527 let mut state: mbstate_t = mbstate_t {}; 528 let result: usize = mbrtowc(&mut wc, s, n, &mut state); 529 530 if result == -1isize as usize { 531 return -1; 532 } 533 if result == -2isize as usize { 534 return -1; 535 } 536 537 result as i32 538 } 539 540 #[no_mangle] 541 pub unsafe extern "C" fn mbstowcs( 542 pwcs: *mut ::wchar_t, 543 mut s: *const ::c_char, 544 n: ::size_t, 545 ) -> ::size_t { 546 let mut state: mbstate_t = mbstate_t {}; 547 mbsrtowcs(pwcs, &mut s, n, &mut state) 548 } 549 550 #[no_mangle] 551 pub unsafe extern "C" fn mbtowc(pwc: *mut ::wchar_t, s: *const ::c_char, n: ::size_t) -> ::c_int { 552 let mut state: mbstate_t = mbstate_t {}; 553 mbrtowc(pwc, s, n, &mut state) as ::c_int 554 } 555 556 fn inner_mktemp<T, F>(name: *mut ::c_char, suffix_len: ::c_int, mut attempt: F) -> Option<T> 557 where 558 F: FnMut() -> Option<T>, 559 { 560 let len = unsafe { strlen(name) as ::c_int }; 561 562 if len < 6 || suffix_len > len - 6 { 563 unsafe { platform::errno = errno::EINVAL }; 564 return None; 565 } 566 567 for i in (len - suffix_len - 6)..(len - suffix_len) { 568 if unsafe { *name.offset(i as isize) } != b'X' as ::c_char { 569 unsafe { platform::errno = errno::EINVAL }; 570 return None; 571 } 572 } 573 574 let mut rng = JitterRng::new_with_timer(get_nstime); 575 let _ = rng.test_timer(); 576 577 for _ in 0..100 { 578 let char_iter = iter::repeat(()) 579 .map(|()| rng.sample(Alphanumeric)) 580 .take(6) 581 .enumerate(); 582 unsafe { 583 for (i, c) in char_iter { 584 *name.offset((len as isize) - (suffix_len as isize) - (i as isize) - 1) = 585 c as ::c_char 586 } 587 } 588 589 if let result @ Some(_) = attempt() { 590 return result; 591 } 592 } 593 594 unsafe { platform::errno = errno::EEXIST } 595 596 None 597 } 598 599 #[no_mangle] 600 pub unsafe extern "C" fn mktemp(name: *mut ::c_char) -> *mut ::c_char { 601 if inner_mktemp(name, 0, || { 602 if platform::pal::access(name, 0) != 0 && platform::errno == ENOENT { 603 Some(()) 604 } else { 605 None 606 } 607 }) 608 .is_none() 609 { 610 *name = 0; 611 } 612 name 613 } 614 615 fn get_nstime() -> u64 { 616 let mut ts = mem::MaybeUninit::uninit(); 617 platform::pal::clock_gettime(::CLOCK_MONOTONIC, ts.as_mut_ptr()); 618 unsafe { ts.assume_init() }.tv_nsec as u64 619 } 620 621 #[no_mangle] 622 pub extern "C" fn mkostemps( 623 name: *mut ::c_char, 624 suffix_len: ::c_int, 625 mut flags: ::c_int, 626 ) -> ::c_int { 627 flags &= !::O_ACCMODE; 628 flags |= ::O_RDWR | ::O_CREAT | ::O_EXCL; 629 630 inner_mktemp(name, suffix_len, || { 631 let fd = platform::pal::open(name, flags, 0o600); 632 633 if fd >= 0 { 634 Some(fd) 635 } else { 636 None 637 } 638 }) 639 .unwrap_or(-1) 640 } 641 642 #[no_mangle] 643 pub extern "C" fn mkstemp(name: *mut ::c_char) -> ::c_int { 644 mkostemps(name, 0, 0) 645 } 646 #[no_mangle] 647 pub extern "C" fn mkostemp(name: *mut ::c_char, flags: ::c_int) -> ::c_int { 648 mkostemps(name, 0, flags) 649 } 650 #[no_mangle] 651 pub extern "C" fn mkstemps(name: *mut ::c_char, suffix_len: ::c_int) -> ::c_int { 652 mkostemps(name, suffix_len, 0) 653 } 654 655 #[no_mangle] 656 pub unsafe extern "C" fn mrand48() -> ::c_long { 657 let new_xsubi_value = rand48::generator_step(&mut rand48::DEFAULT_XSUBI); 658 rand48::i32_from_x(new_xsubi_value) 659 } 660 661 #[no_mangle] 662 pub unsafe extern "C" fn nrand48(xsubi: *mut ::c_ushort) -> ::c_long { 663 let new_xsubi_value = rand48::generator_step(&mut *(xsubi as *mut [::c_ushort; 3])); 664 rand48::u31_from_x(new_xsubi_value) 665 } 666 667 #[no_mangle] 668 pub unsafe extern "C" fn posix_memalign( 669 memptr: *mut *mut ::c_void, 670 alignment: ::size_t, 671 size: ::size_t, 672 ) -> ::c_int { 673 const VOID_PTR_SIZE: usize = mem::size_of::<*mut ::c_void>(); 674 675 if alignment % VOID_PTR_SIZE == 0 && alignment.is_power_of_two() { 676 let ptr = platform::alloc_align(size, alignment); 677 *memptr = ptr; 678 if ptr.is_null() { 679 ENOMEM 680 } else { 681 0 682 } 683 } else { 684 *memptr = ptr::null_mut(); 685 EINVAL 686 } 687 } 688 689 // #[no_mangle] 690 pub extern "C" fn ptsname(_fildes: ::c_int) -> *mut ::c_char { 691 unimplemented!(); 692 } 693 694 unsafe fn put_new_env(insert: *mut ::c_char) { 695 // XXX: Another problem is that `environ` can be set to any pointer, which means there is a 696 // chance of a memory leak. But we can check if it was the same as before, like musl does. 697 if platform::environ == platform::OUR_ENVIRON.as_mut_ptr() { 698 *platform::OUR_ENVIRON.last_mut().unwrap() = insert; 699 platform::OUR_ENVIRON.push(core::ptr::null_mut()); 700 // Likely a no-op but is needed due to Stacked Borrows. 701 platform::environ = platform::OUR_ENVIRON.as_mut_ptr(); 702 } else { 703 platform::OUR_ENVIRON.clear(); 704 platform::OUR_ENVIRON.extend(platform::environ_iter()); 705 platform::OUR_ENVIRON.push(insert); 706 platform::OUR_ENVIRON.push(core::ptr::null_mut()); 707 platform::environ = platform::OUR_ENVIRON.as_mut_ptr(); 708 } 709 } 710 711 #[no_mangle] 712 pub unsafe extern "C" fn putenv(insert: *mut ::c_char) -> ::c_int { 713 assert_ne!(insert, ptr::null_mut(), "putenv(NULL)"); 714 if let Some((i, _)) = find_env(insert) { 715 // XXX: The POSIX manual states that environment variables can be *set* via the `environ` 716 // global variable. While we can check if a pointer belongs to our allocator, or check 717 // `environ` against a vector which we control, it is likely not worth the effort. 718 platform::environ.add(i).write(insert); 719 } else { 720 put_new_env(insert); 721 } 722 0 723 } 724 725 #[no_mangle] 726 pub extern "C" fn qsort( 727 base: *mut ::c_void, 728 nel: ::size_t, 729 width: ::size_t, 730 compar: Option<extern "C" fn(*const ::c_void, *const ::c_void) -> ::c_int>, 731 ) { 732 if let Some(comp) = compar { 733 // XXX: check width too? not specified 734 if nel > 0 { 735 // XXX: maybe try to do mergesort/timsort first and fallback to introsort if memory 736 // allocation fails? not sure what is ideal 737 sort::introsort(base as *mut ::c_char, nel, width, comp); 738 } 739 } 740 } 741 742 #[no_mangle] 743 pub unsafe extern "C" fn rand() -> ::c_int { 744 match RNG { 745 Some(ref mut rng) => RNG_SAMPLER.sample(rng), 746 None => { 747 let mut rng = XorShiftRng::from_seed([1; 16]); 748 let ret = RNG_SAMPLER.sample(&mut rng); 749 RNG = Some(rng); 750 ret 751 } 752 } 753 } 754 755 #[no_mangle] 756 pub unsafe extern "C" fn rand_r(seed: *mut ::c_uint) -> ::c_int { 757 if seed.is_null() { 758 errno::EINVAL 759 } else { 760 // set the type explicitly so this will fail if the array size for XorShiftRng changes 761 let seed_arr: [u8; 16] = mem::transmute([*seed; 16 / mem::size_of::<::c_uint>()]); 762 763 let mut rng = XorShiftRng::from_seed(seed_arr); 764 let ret = RNG_SAMPLER.sample(&mut rng); 765 766 *seed = ret as _; 767 768 ret 769 } 770 } 771 772 #[no_mangle] 773 pub unsafe extern "C" fn random() -> ::c_long { 774 // Ported from musl 775 776 let k: u32; 777 // TODO: lock? 778 random::ensure_x_ptr_init(); 779 780 if random::N == 0 { 781 let x_old = u32::from_ne_bytes(*random::X_PTR); 782 let x_new = random::lcg31_step(x_old); 783 *random::X_PTR = x_new.to_ne_bytes(); 784 k = x_new; 785 } else { 786 // The non-u32-aligned way of saying x[i] += x[j]... 787 let x_i_old = u32::from_ne_bytes(*random::X_PTR.add(usize::from(random::I))); 788 let x_j = u32::from_ne_bytes(*random::X_PTR.add(usize::from(random::J))); 789 let x_i_new = x_i_old.wrapping_add(x_j); 790 *random::X_PTR.add(usize::from(random::I)) = x_i_new.to_ne_bytes(); 791 792 k = x_i_new >> 1; 793 794 random::I += 1; 795 if random::I == random::N { 796 random::I = 0; 797 } 798 799 random::J += 1; 800 if random::J == random::N { 801 random::J = 0; 802 } 803 } 804 // TODO: unlock? 805 806 /* Both branches of this function result in a "u31", which will 807 * always fit in a ::c_long. */ 808 ::c_long::try_from(k).unwrap() 809 } 810 811 #[no_mangle] 812 pub unsafe extern "C" fn realloc(ptr: *mut ::c_void, size: ::size_t) -> *mut ::c_void { 813 let new_ptr = platform::realloc(ptr, size); 814 if new_ptr.is_null() { 815 platform::errno = ENOMEM; 816 } 817 new_ptr 818 } 819 820 #[no_mangle] 821 pub unsafe extern "C" fn reallocarray( 822 ptr: *mut ::c_void, 823 m: ::size_t, 824 n: ::size_t, 825 ) -> *mut ::c_void { 826 //Handle possible integer overflow in size calculation 827 match m.checked_mul(n) { 828 Some(size) => realloc(ptr, size), 829 None => { 830 // For overflowing multiplication, we have to set errno here 831 platform::errno = ENOMEM; 832 ptr::null_mut() 833 } 834 } 835 } 836 837 #[no_mangle] 838 pub unsafe extern "C" fn realpath( 839 pathname: *const ::c_char, 840 resolved: *mut ::c_char, 841 ) -> *mut ::c_char { 842 let ptr = if resolved.is_null() { 843 malloc(limits::PATH_MAX) as *mut ::c_char 844 } else { 845 resolved 846 }; 847 848 let out = slice::from_raw_parts_mut(ptr as *mut u8, limits::PATH_MAX); 849 { 850 let file = match File::open(&CStr::from_ptr(pathname), ::O_PATH | ::O_CLOEXEC) { 851 Ok(file) => file, 852 Err(_) => return ptr::null_mut(), 853 }; 854 855 let len = out.len(); 856 let read = platform::pal::fpath(*file, out[..len - 1].as_mut_ptr() as *const i8); 857 if read < 0 { 858 return ptr::null_mut(); 859 } 860 out[read as usize] = 0; 861 } 862 863 ptr 864 } 865 866 #[no_mangle] 867 pub unsafe extern "C" fn seed48(seed16v: *mut ::c_ushort) -> *mut ::c_ushort { 868 rand48::reset_a_and_c(); 869 870 // Stash current DEFAULT_XSUBI value in SEED48_XSUBI 871 rand48::SEED48_XSUBI = rand48::DEFAULT_XSUBI; 872 873 // Set DEFAULT_XSUBI from the argument provided 874 let xsubi_value = rand48::u48_from_ushort_arr3(&*(seed16v as *const [::c_ushort; 3])); 875 rand48::DEFAULT_XSUBI = rand48::ushort_arr3_from_u48(xsubi_value); 876 877 // Return the stashed value 878 rand48::SEED48_XSUBI.as_mut_ptr() 879 } 880 881 unsafe fn copy_kv( 882 existing: *mut ::c_char, 883 key: *const ::c_char, 884 value: *const ::c_char, 885 key_len: usize, 886 value_len: usize, 887 ) { 888 core::ptr::copy_nonoverlapping(key, existing, key_len); 889 core::ptr::write(existing.add(key_len), b'=' as ::c_char); 890 core::ptr::copy_nonoverlapping(value, existing.add(key_len + 1), value_len); 891 core::ptr::write(existing.add(key_len + 1 + value_len), 0); 892 } 893 894 #[no_mangle] 895 pub unsafe extern "C" fn setenv( 896 key: *const ::c_char, 897 value: *const ::c_char, 898 overwrite: ::c_int, 899 ) -> ::c_int { 900 let key_len = strlen(key); 901 let value_len = strlen(value); 902 903 if let Some((i, existing)) = find_env(key) { 904 if overwrite == 0 { 905 return 0; 906 } 907 908 let existing_len = strlen(existing); 909 910 if existing_len >= value_len { 911 // Reuse existing element's allocation 912 core::ptr::copy_nonoverlapping(value, existing, value_len); 913 //TODO: fill to end with zeroes 914 core::ptr::write(existing.add(value_len), 0); 915 } else { 916 // Reuse platform::environ slot, but allocate a new pointer. 917 let ptr = 918 platform::alloc(key_len as usize + 1 + value_len as usize + 1) as *mut ::c_char; 919 copy_kv(ptr, key, value, key_len, value_len); 920 platform::environ.add(i).write(ptr); 921 } 922 } else { 923 // Expand platform::environ and allocate a new pointer. 924 let ptr = platform::alloc(key_len as usize + 1 + value_len as usize + 1) as *mut ::c_char; 925 copy_kv(ptr, key, value, key_len, value_len); 926 put_new_env(ptr); 927 } 928 929 //platform::free(platform::pal::inner_environ[index] as *mut ::c_void); 930 931 0 932 } 933 934 // #[no_mangle] 935 pub extern "C" fn setkey(_key: *const ::c_char) { 936 unimplemented!(); 937 } 938 939 #[no_mangle] 940 pub unsafe extern "C" fn setstate(state: *mut ::c_char) -> *mut ::c_char { 941 /* Ported from musl. The state parameter is no longer const in newer 942 * versions of POSIX. */ 943 944 // TODO: lock? 945 let old_state = random::save_state(); 946 random::load_state(state.cast::<_>()); 947 // TODO: unlock? 948 old_state.cast::<_>() 949 } 950 951 #[no_mangle] 952 pub unsafe extern "C" fn srand(seed: ::c_uint) { 953 RNG = Some(XorShiftRng::from_seed([seed as u8; 16])); 954 } 955 956 #[no_mangle] 957 pub unsafe extern "C" fn srand48(seedval: ::c_long) { 958 rand48::reset_a_and_c(); 959 960 /* Set the high 32 bits of the 48-bit X_i value to the lower 32 bits 961 * of the input argument, and the lower 16 bits to 0x330e, as 962 * specified in POSIX. */ 963 let xsubi_value = (u64::from(seedval as u32) << 16) | 0x330e; 964 rand48::DEFAULT_XSUBI = rand48::ushort_arr3_from_u48(xsubi_value); 965 } 966 967 #[no_mangle] 968 pub unsafe extern "C" fn srandom(seed: ::c_uint) { 969 // Ported from musl 970 971 // TODO: lock? 972 random::seed(seed); 973 // TODO: unlock? 974 } 975 976 #[no_mangle] 977 pub unsafe extern "C" fn strtod(s: *const ::c_char, endptr: *mut *mut ::c_char) -> ::c_double { 978 strto_float_impl!(f64, s, endptr) 979 } 980 #[no_mangle] 981 pub unsafe extern "C" fn strtof(s: *const ::c_char, endptr: *mut *mut ::c_char) -> ::c_float { 982 strto_float_impl!(f32, s, endptr) 983 } 984 985 pub fn is_positive(ch: ::c_char) -> Option<(bool, isize)> { 986 match ch { 987 0 => None, 988 ch if ch == b'+' as ::c_char => Some((true, 1)), 989 ch if ch == b'-' as ::c_char => Some((false, 1)), 990 _ => Some((true, 0)), 991 } 992 } 993 994 pub unsafe fn detect_base(s: *const ::c_char) -> Option<(::c_int, isize)> { 995 let first = *s as u8; 996 match first { 997 0 => None, 998 b'0' => { 999 let second = *s.offset(1) as u8; 1000 if second == b'X' || second == b'x' { 1001 Some((16, 2)) 1002 } else if second >= b'0' && second <= b'7' { 1003 Some((8, 1)) 1004 } else { 1005 // in this case, the prefix (0) is going to be the number 1006 Some((8, 0)) 1007 } 1008 } 1009 _ => Some((10, 0)), 1010 } 1011 } 1012 1013 pub unsafe fn convert_octal(s: *const ::c_char) -> Option<(::c_ulong, isize, bool)> { 1014 if *s != 0 && *s == b'0' as ::c_char { 1015 if let Some((val, idx, overflow)) = convert_integer(s.offset(1), 8) { 1016 Some((val, idx + 1, overflow)) 1017 } else { 1018 // in case the prefix is not actually a prefix 1019 Some((0, 1, false)) 1020 } 1021 } else { 1022 None 1023 } 1024 } 1025 1026 pub unsafe fn convert_hex(s: *const ::c_char) -> Option<(::c_ulong, isize, bool)> { 1027 if (*s != 0 && *s == b'0' as ::c_char) 1028 && (*s.offset(1) != 0 1029 && (*s.offset(1) == b'x' as ::c_char || *s.offset(1) == b'X' as ::c_char)) 1030 { 1031 convert_integer(s.offset(2), 16).map(|(val, idx, overflow)| (val, idx + 2, overflow)) 1032 } else { 1033 convert_integer(s, 16).map(|(val, idx, overflow)| (val, idx, overflow)) 1034 } 1035 } 1036 1037 pub unsafe fn convert_integer( 1038 s: *const ::c_char, 1039 base: ::c_int, 1040 ) -> Option<(::c_ulong, isize, bool)> { 1041 // -1 means the character is invalid 1042 #[rustfmt::skip] 1043 const LOOKUP_TABLE: [::c_long; 256] = [ 1044 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1045 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1046 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1047 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, 1048 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 1049 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, 1050 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 1051 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, 1052 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1053 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1054 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1055 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1056 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1057 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1058 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1059 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1060 ]; 1061 1062 let mut num: ::c_ulong = 0; 1063 let mut idx = 0; 1064 let mut overflowed = false; 1065 1066 loop { 1067 // `-1 as usize` is usize::MAX 1068 // `-1 as u8 as usize` is u8::MAX 1069 // It extends by the sign bit unless we cast it to unsigned first. 1070 let val = LOOKUP_TABLE[*s.offset(idx) as u8 as usize]; 1071 if val == -1 || val as ::c_int >= base { 1072 break; 1073 } else { 1074 if let Some(res) = num 1075 .checked_mul(base as ::c_ulong) 1076 .and_then(|num| num.checked_add(val as ::c_ulong)) 1077 { 1078 num = res; 1079 } else { 1080 platform::errno = ERANGE; 1081 num = ::c_ulong::max_value(); 1082 overflowed = true; 1083 } 1084 1085 idx += 1; 1086 } 1087 } 1088 1089 if idx > 0 { 1090 Some((num, idx, overflowed)) 1091 } else { 1092 None 1093 } 1094 } 1095 1096 #[no_mangle] 1097 pub unsafe extern "C" fn strtoul( 1098 s: *const ::c_char, 1099 endptr: *mut *mut ::c_char, 1100 base: ::c_int, 1101 ) -> ::c_ulong { 1102 strto_impl!( 1103 ::c_ulong, 1104 false, 1105 ::c_ulong::max_value(), 1106 ::c_ulong::min_value(), 1107 s, 1108 endptr, 1109 base 1110 ) 1111 } 1112 1113 #[no_mangle] 1114 pub unsafe extern "C" fn strtol( 1115 s: *const ::c_char, 1116 endptr: *mut *mut ::c_char, 1117 base: ::c_int, 1118 ) -> ::c_long { 1119 strto_impl!( 1120 ::c_long, 1121 true, 1122 ::c_long::max_value(), 1123 ::c_long::min_value(), 1124 s, 1125 endptr, 1126 base 1127 ) 1128 } 1129 1130 #[no_mangle] 1131 pub unsafe extern "C" fn strtoull( 1132 s: *const ::c_char, 1133 endptr: *mut *mut ::c_char, 1134 base: ::c_int, 1135 ) -> ::c_ulonglong { 1136 strto_impl!( 1137 ::c_ulonglong, 1138 false, 1139 ::c_ulonglong::max_value(), 1140 ::c_ulonglong::min_value(), 1141 s, 1142 endptr, 1143 base 1144 ) 1145 } 1146 1147 #[no_mangle] 1148 pub unsafe extern "C" fn strtoll( 1149 s: *const ::c_char, 1150 endptr: *mut *mut ::c_char, 1151 base: ::c_int, 1152 ) -> ::c_longlong { 1153 strto_impl!( 1154 ::c_longlong, 1155 true, 1156 ::c_longlong::max_value(), 1157 ::c_longlong::min_value(), 1158 s, 1159 endptr, 1160 base 1161 ) 1162 } 1163 1164 #[no_mangle] 1165 pub unsafe extern "C" fn system(command: *const ::c_char) -> ::c_int { 1166 //TODO: share code with popen 1167 1168 let child_pid = unistd::fork(); 1169 if child_pid == 0 { 1170 let command_nonnull = if command.is_null() { 1171 "exit 0\0".as_ptr() 1172 } else { 1173 command as *const u8 1174 }; 1175 1176 let shell = "/bin/sh\0".as_ptr(); 1177 1178 let args = [ 1179 "sh\0".as_ptr(), 1180 "-c\0".as_ptr(), 1181 command_nonnull, 1182 ptr::null(), 1183 ]; 1184 1185 unistd::execv( 1186 shell as *const ::c_char, 1187 args.as_ptr() as *const *const ::c_char, 1188 ); 1189 1190 exit(127); 1191 1192 unreachable!(); 1193 } else if child_pid > 0 { 1194 let mut wstatus = 0; 1195 if platform::pal::waitpid(child_pid, &mut wstatus, 0) == !0 { 1196 return -1; 1197 } 1198 1199 wstatus 1200 } else { 1201 -1 1202 } 1203 } 1204 1205 // #[no_mangle] 1206 pub extern "C" fn ttyslot() -> ::c_int { 1207 unimplemented!(); 1208 } 1209 1210 // #[no_mangle] 1211 pub extern "C" fn unlockpt(_fildes: ::c_int) -> ::c_int { 1212 unimplemented!(); 1213 } 1214 1215 #[no_mangle] 1216 pub unsafe extern "C" fn unsetenv(key: *const ::c_char) -> ::c_int { 1217 if let Some((i, _)) = find_env(key) { 1218 if platform::environ == platform::OUR_ENVIRON.as_mut_ptr() { 1219 // No need to worry about updating the pointer, this does not 1220 // reallocate in any way. And the final null is already shifted back. 1221 platform::OUR_ENVIRON.remove(i); 1222 1223 // My UB paranoia. 1224 platform::environ = platform::OUR_ENVIRON.as_mut_ptr(); 1225 } else { 1226 platform::OUR_ENVIRON.clear(); 1227 platform::OUR_ENVIRON.extend( 1228 platform::environ_iter() 1229 .enumerate() 1230 .filter(|&(j, _)| j != i) 1231 .map(|(_, v)| v), 1232 ); 1233 platform::OUR_ENVIRON.push(core::ptr::null_mut()); 1234 platform::environ = platform::OUR_ENVIRON.as_mut_ptr(); 1235 } 1236 } 1237 0 1238 } 1239 1240 #[no_mangle] 1241 pub unsafe extern "C" fn valloc(size: ::size_t) -> *mut ::c_void { 1242 /* sysconf(_SC_PAGESIZE) is a ::c_long and may in principle not 1243 * convert correctly to a ::size_t. */ 1244 match ::size_t::try_from(sysconf(_SC_PAGESIZE)) { 1245 Ok(page_size) => { 1246 /* valloc() is not supposed to be able to set errno to 1247 * EINVAL, hence no call to memalign(). */ 1248 let ptr = platform::alloc_align(size, page_size); 1249 if ptr.is_null() { 1250 platform::errno = ENOMEM; 1251 } 1252 ptr 1253 } 1254 Err(_) => { 1255 // A corner case. No errno setting. 1256 ptr::null_mut() 1257 } 1258 } 1259 } 1260 1261 #[no_mangle] 1262 pub extern "C" fn wcstombs(s: *mut ::c_char, mut pwcs: *const ::wchar_t, n: ::size_t) -> ::size_t { 1263 let mut state: mbstate_t = mbstate_t {}; 1264 wcsrtombs(s, &mut pwcs, n, &mut state) 1265 } 1266 1267 #[no_mangle] 1268 pub unsafe extern "C" fn wctomb(s: *mut ::c_char, wc: ::wchar_t) -> ::c_int { 1269 let mut state: mbstate_t = mbstate_t {}; 1270 let result: usize = wcrtomb(s, wc, &mut state); 1271 1272 if result == -1isize as usize { 1273 return -1; 1274 } 1275 if result == -2isize as usize { 1276 return -1; 1277 } 1278 1279 result as ::c_int 1280 } 1281