|
1 |
| -use std::ffi::{OsStr, OsString}; |
2 |
| -use std::path::{Path, PathBuf}; |
3 |
| -use std::{iter, mem}; |
4 | 1 | use std::convert::TryFrom;
|
5 |
| -use std::borrow::Cow; |
6 |
| - |
7 |
| -#[cfg(unix)] |
8 |
| -use std::os::unix::ffi::{OsStrExt, OsStringExt}; |
9 |
| -#[cfg(windows)] |
10 |
| -use std::os::windows::ffi::{OsStrExt, OsStringExt}; |
| 2 | +use std::mem; |
11 | 3 |
|
12 | 4 | use rustc::mir;
|
13 | 5 | use rustc::ty::{
|
@@ -462,237 +454,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
462 | 454 | }
|
463 | 455 | }
|
464 | 456 | }
|
465 |
| - |
466 |
| - /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what |
467 |
| - /// the Unix APIs usually handle. |
468 |
| - fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar<Tag>) -> InterpResult<'tcx, &'a OsStr> |
469 |
| - where |
470 |
| - 'tcx: 'a, |
471 |
| - 'mir: 'a, |
472 |
| - { |
473 |
| - #[cfg(unix)] |
474 |
| - fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { |
475 |
| - Ok(OsStr::from_bytes(bytes)) |
476 |
| - } |
477 |
| - #[cfg(not(unix))] |
478 |
| - fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { |
479 |
| - let s = std::str::from_utf8(bytes) |
480 |
| - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; |
481 |
| - Ok(OsStr::new(s)) |
482 |
| - } |
483 |
| - |
484 |
| - let this = self.eval_context_ref(); |
485 |
| - let bytes = this.memory.read_c_str(scalar)?; |
486 |
| - bytes_to_os_str(bytes) |
487 |
| - } |
488 |
| - |
489 |
| - /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, |
490 |
| - /// which is what the Windows APIs usually handle. |
491 |
| - fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar<Tag>) -> InterpResult<'tcx, OsString> |
492 |
| - where |
493 |
| - 'tcx: 'a, |
494 |
| - 'mir: 'a, |
495 |
| - { |
496 |
| - #[cfg(windows)] |
497 |
| - pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec<u16>) -> InterpResult<'tcx, OsString> { |
498 |
| - Ok(OsString::from_wide(&u16_vec[..])) |
499 |
| - } |
500 |
| - #[cfg(not(windows))] |
501 |
| - pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec<u16>) -> InterpResult<'tcx, OsString> { |
502 |
| - let s = String::from_utf16(&u16_vec[..]) |
503 |
| - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-16 string", u16_vec))?; |
504 |
| - Ok(s.into()) |
505 |
| - } |
506 |
| - |
507 |
| - let u16_vec = self.eval_context_ref().memory.read_wide_str(scalar)?; |
508 |
| - u16vec_to_osstring(u16_vec) |
509 |
| - } |
510 |
| - |
511 |
| - /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what |
512 |
| - /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying |
513 |
| - /// to write if `size` is not large enough to fit the contents of `os_string` plus a null |
514 |
| - /// terminator. It returns `Ok((true, length))` if the writing process was successful. The |
515 |
| - /// string length returned does not include the null terminator. |
516 |
| - fn write_os_str_to_c_str( |
517 |
| - &mut self, |
518 |
| - os_str: &OsStr, |
519 |
| - scalar: Scalar<Tag>, |
520 |
| - size: u64, |
521 |
| - ) -> InterpResult<'tcx, (bool, u64)> { |
522 |
| - #[cfg(unix)] |
523 |
| - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { |
524 |
| - Ok(os_str.as_bytes()) |
525 |
| - } |
526 |
| - #[cfg(not(unix))] |
527 |
| - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { |
528 |
| - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the |
529 |
| - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually |
530 |
| - // valid. |
531 |
| - os_str |
532 |
| - .to_str() |
533 |
| - .map(|s| s.as_bytes()) |
534 |
| - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) |
535 |
| - } |
536 |
| - |
537 |
| - let bytes = os_str_to_bytes(os_str)?; |
538 |
| - // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null |
539 |
| - // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. |
540 |
| - let string_length = u64::try_from(bytes.len()).unwrap(); |
541 |
| - if size <= string_length { |
542 |
| - return Ok((false, string_length)); |
543 |
| - } |
544 |
| - self.eval_context_mut() |
545 |
| - .memory |
546 |
| - .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; |
547 |
| - Ok((true, string_length)) |
548 |
| - } |
549 |
| - |
550 |
| - /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what |
551 |
| - /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying |
552 |
| - /// to write if `size` is not large enough to fit the contents of `os_string` plus a null |
553 |
| - /// terminator. It returns `Ok((true, length))` if the writing process was successful. The |
554 |
| - /// string length returned does not include the null terminator. |
555 |
| - fn write_os_str_to_wide_str( |
556 |
| - &mut self, |
557 |
| - os_str: &OsStr, |
558 |
| - scalar: Scalar<Tag>, |
559 |
| - size: u64, |
560 |
| - ) -> InterpResult<'tcx, (bool, u64)> { |
561 |
| - #[cfg(windows)] |
562 |
| - fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec<u16>> { |
563 |
| - Ok(os_str.encode_wide().collect()) |
564 |
| - } |
565 |
| - #[cfg(not(windows))] |
566 |
| - fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec<u16>> { |
567 |
| - // On non-Windows platforms the best we can do to transform Vec<u16> from/to OS strings is to do the |
568 |
| - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually |
569 |
| - // valid. |
570 |
| - os_str |
571 |
| - .to_str() |
572 |
| - .map(|s| s.encode_utf16().collect()) |
573 |
| - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) |
574 |
| - } |
575 |
| - |
576 |
| - let u16_vec = os_str_to_u16vec(os_str)?; |
577 |
| - // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required |
578 |
| - // 0x0000 terminator to memory would cause an out-of-bounds access. |
579 |
| - let string_length = u64::try_from(u16_vec.len()).unwrap(); |
580 |
| - if size <= string_length { |
581 |
| - return Ok((false, string_length)); |
582 |
| - } |
583 |
| - |
584 |
| - // Store the UTF-16 string. |
585 |
| - self.eval_context_mut() |
586 |
| - .memory |
587 |
| - .write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?; |
588 |
| - Ok((true, string_length)) |
589 |
| - } |
590 |
| - |
591 |
| - /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. |
592 |
| - fn alloc_os_str_as_c_str( |
593 |
| - &mut self, |
594 |
| - os_str: &OsStr, |
595 |
| - memkind: MemoryKind<MiriMemoryKind>, |
596 |
| - ) -> Pointer<Tag> { |
597 |
| - let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. |
598 |
| - let this = self.eval_context_mut(); |
599 |
| - |
600 |
| - let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); |
601 |
| - let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); |
602 |
| - assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0); |
603 |
| - arg_place.ptr.assert_ptr() |
604 |
| - } |
605 |
| - |
606 |
| - /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. |
607 |
| - fn alloc_os_str_as_wide_str( |
608 |
| - &mut self, |
609 |
| - os_str: &OsStr, |
610 |
| - memkind: MemoryKind<MiriMemoryKind>, |
611 |
| - ) -> Pointer<Tag> { |
612 |
| - let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. |
613 |
| - let this = self.eval_context_mut(); |
614 |
| - |
615 |
| - let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); |
616 |
| - let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); |
617 |
| - assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0); |
618 |
| - arg_place.ptr.assert_ptr() |
619 |
| - } |
620 |
| - |
621 |
| - /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. |
622 |
| - fn read_path_from_c_str<'a>(&'a self, scalar: Scalar<Tag>) -> InterpResult<'tcx, Cow<'a, Path>> |
623 |
| - where |
624 |
| - 'tcx: 'a, |
625 |
| - 'mir: 'a, |
626 |
| - { |
627 |
| - let this = self.eval_context_ref(); |
628 |
| - let os_str = this.read_os_str_from_c_str(scalar)?; |
629 |
| - |
630 |
| - #[cfg(windows)] |
631 |
| - return Ok(if this.tcx.sess.target.target.target_os == "windows" { |
632 |
| - // Windows-on-Windows, all fine. |
633 |
| - Cow::Borrowed(Path::new(os_str)) |
634 |
| - } else { |
635 |
| - // Unix target, Windows host. Need to convert target '/' to host '\'. |
636 |
| - let converted = os_str |
637 |
| - .encode_wide() |
638 |
| - .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) |
639 |
| - .collect::<Vec<_>>(); |
640 |
| - Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) |
641 |
| - }); |
642 |
| - #[cfg(unix)] |
643 |
| - return Ok(if this.tcx.sess.target.target.target_os == "windows" { |
644 |
| - // Windows target, Unix host. Need to convert target '\' to host '/'. |
645 |
| - let converted = os_str |
646 |
| - .as_bytes() |
647 |
| - .iter() |
648 |
| - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) |
649 |
| - .collect::<Vec<_>>(); |
650 |
| - Cow::Owned(PathBuf::from(OsString::from_vec(converted))) |
651 |
| - } else { |
652 |
| - // Unix-on-Unix, all is fine. |
653 |
| - Cow::Borrowed(Path::new(os_str)) |
654 |
| - }); |
655 |
| - } |
656 |
| - |
657 |
| - /// Write a Path to the machine memory, adjusting path separators if needed. |
658 |
| - fn write_path_to_c_str( |
659 |
| - &mut self, |
660 |
| - path: &Path, |
661 |
| - scalar: Scalar<Tag>, |
662 |
| - size: u64, |
663 |
| - ) -> InterpResult<'tcx, (bool, u64)> { |
664 |
| - let this = self.eval_context_mut(); |
665 |
| - |
666 |
| - #[cfg(windows)] |
667 |
| - let os_str = if this.tcx.sess.target.target.target_os == "windows" { |
668 |
| - // Windows-on-Windows, all fine. |
669 |
| - Cow::Borrowed(path.as_os_str()) |
670 |
| - } else { |
671 |
| - // Unix target, Windows host. Need to convert host '\\' to target '/'. |
672 |
| - let converted = path |
673 |
| - .as_os_str() |
674 |
| - .encode_wide() |
675 |
| - .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) |
676 |
| - .collect::<Vec<_>>(); |
677 |
| - Cow::Owned(OsString::from_wide(&converted)) |
678 |
| - }; |
679 |
| - #[cfg(unix)] |
680 |
| - let os_str = if this.tcx.sess.target.target.target_os == "windows" { |
681 |
| - // Windows target, Unix host. Need to convert host '/' to target '\'. |
682 |
| - let converted = path |
683 |
| - .as_os_str() |
684 |
| - .as_bytes() |
685 |
| - .iter() |
686 |
| - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) |
687 |
| - .collect::<Vec<_>>(); |
688 |
| - Cow::Owned(OsString::from_vec(converted)) |
689 |
| - } else { |
690 |
| - // Unix-on-Unix, all is fine. |
691 |
| - Cow::Borrowed(path.as_os_str()) |
692 |
| - }; |
693 |
| - |
694 |
| - this.write_os_str_to_c_str(&os_str, scalar, size) |
695 |
| - } |
696 | 457 | }
|
697 | 458 |
|
698 | 459 | pub fn immty_from_int_checked<'tcx>(
|
|
0 commit comments