]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #1159 - divergentdave:shim-seek, r=RalfJung
authorbors <bors@rust-lang.org>
Sat, 8 Feb 2020 13:54:33 +0000 (13:54 +0000)
committerbors <bors@rust-lang.org>
Sat, 8 Feb 2020 13:54:33 +0000 (13:54 +0000)
Add shim for seeking files

This adds a shim for `lseek64` (`lseek` on macOS). This enables the use of `<File as Seek>::seek`. Testing is included.

34 files changed:
.appveyor.yml
.travis.yml
README.md
rust-version
src/helpers.rs
src/shims/foreign_items.rs
src/shims/fs.rs
src/shims/intrinsics.rs
src/shims/time.rs
tests/compile-fail/deallocate-bad-alignment.rs
tests/compile-fail/deallocate-bad-size.rs
tests/compile-fail/deallocate-twice.rs
tests/compile-fail/div-by-zero-1.rs
tests/compile-fail/div-by-zero-2.rs [new file with mode: 0644]
tests/compile-fail/div-by-zero-3.rs [deleted file]
tests/compile-fail/generator-pinned-moved.rs
tests/compile-fail/reallocate-bad-size.rs
tests/compile-fail/reallocate-change-alloc.rs
tests/compile-fail/reallocate-dangling.rs
tests/compile-fail/stacked_borrows/illegal_read8.rs [new file with mode: 0644]
tests/compile-fail/unchecked_add1.rs
tests/compile-fail/unchecked_add2.rs
tests/compile-fail/unchecked_div1.rs [new file with mode: 0644]
tests/compile-fail/unchecked_mul1.rs
tests/compile-fail/unchecked_mul2.rs
tests/compile-fail/unchecked_sub1.rs
tests/compile-fail/unchecked_sub2.rs
tests/run-pass/fs.rs
tests/run-pass/generator.rs
tests/run-pass/heap_allocator.rs
tests/run-pass/libc.rs [new file with mode: 0644]
tests/run-pass/stacked-borrows/stacked-borrows.rs
tests/run-pass/stacked-borrows/stacked-borrows.stderr
tests/run-pass/track-caller-attribute.rs

index 16fd20c9da616d280a47789e3ed429c044ddd41f..4281fe0180f05f9d46a2cb8ecd8be57bc86b3260 100644 (file)
@@ -30,7 +30,7 @@ install:
     - rustup toolchain uninstall beta
     - rustup update
     # Install "master" toolchain
-    - cargo install rustup-toolchain-install-master & exit 0
+    - cargo install rustup-toolchain-install-master
     # We need to install cargo here as well or else the DLL search path inside `cargo run`
     # will be for the wrong toolchain. (On Unix, `./miri` takes care of this, but not here.)
     - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev -c cargo
index cbb7c69db1cdfc089ab6107905c49962c6f0f36f..3f0ca8a016bd2b4a1e5fc27431304b38d5094877 100644 (file)
@@ -37,7 +37,7 @@ before_script:
 - rustup toolchain uninstall beta
 - rustup update
 # Install "master" toolchain
-- cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed"
+- cargo install rustup-toolchain-install-master
 - travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev
 - rustup default master
 - rustc --version
index bbf26ff6f71e693e9844c552bc2942d32a14f3c2..cf18e6a0670bc43823d6293f2d64c5cc92c8aace 100644 (file)
--- a/README.md
+++ b/README.md
@@ -51,10 +51,10 @@ program, and cannot run all programs:
 
 ## Using Miri
 
-Install Miri via `rustup`:
+Install Miri on Rust nightly via `rustup`:
 
 ```sh
-rustup component add miri
+rustup +nightly component add miri
 ```
 
 If `rustup` says the `miri` component is unavailable, that's because not all
index d6464fa872e32dba313c5ce69f43656afd1d4f0e..edb99d8eb0d5b65b01feafaeddf0e2bf72e5d503 100644 (file)
@@ -1 +1 @@
-6250d56355d72264ece721e8d0dc95b16a6824b1
+b5e21dbb5cabdaaadc47a4d8e3f59979dcad2871
index fba933d278d2fcd452dee6ab3948ffcfe7af9cec..a765d58bbcf35c200e3f600c851a21f5e178789a 100644 (file)
@@ -339,7 +339,7 @@ fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> {
     // different values into a struct.
     fn write_packed_immediates(
         &mut self,
-        place: &MPlaceTy<'tcx, Tag>,
+        place: MPlaceTy<'tcx, Tag>,
         imms: &[ImmTy<'tcx, Tag>],
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
index a6c1a31b4feb33fcf4dab8f45ff8c8d3a32a35ba..5b40f3c690631a7b8cc4dbe0e199a800e5362252 100644 (file)
@@ -516,6 +516,11 @@ fn emulate_foreign_item(
                 this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
             }
 
+            "fstat$INODE64" => {
+                let result = this.fstat(args[0], args[1])?;
+                this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
+            }
+
             "clock_gettime" => {
                 let result = this.clock_gettime(args[0], args[1])?;
                 this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
@@ -787,6 +792,11 @@ fn emulate_foreign_item(
                 this.write_null(dest)?;
             }
 
+            "posix_fadvise" => {
+                // fadvise is only informational, we can ignore it.
+                this.write_null(dest)?;
+            }
+
             "mmap" => {
                 // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
                 let addr = this.read_scalar(args[0])?.not_undef()?;
index 388117daee6bb2b4da86020648383456acae1b49..f0efc073f75cb77c0a8f92dbf57f9665803e8fdf 100644 (file)
@@ -362,6 +362,28 @@ fn lstat(
         this.stat_or_lstat(false, path_op, buf_op)
     }
 
+    fn fstat(
+        &mut self,
+        fd_op: OpTy<'tcx, Tag>,
+        buf_op: OpTy<'tcx, Tag>,
+    ) -> InterpResult<'tcx, i32> {
+        let this = self.eval_context_mut();
+
+        this.check_no_isolation("fstat")?;
+
+        if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" {
+            throw_unsup_format!("The `fstat` shim is only available for `macos` targets.")
+        }
+
+        let fd = this.read_scalar(fd_op)?.to_i32()?;
+
+        let metadata = match FileMetadata::from_fd(this, fd)? {
+            Some(metadata) => metadata,
+            None => return Ok(-1),
+        };
+        stat_macos_write_buf(this, metadata, buf_op)
+    }
+
     fn stat_or_lstat(
         &mut self,
         follow_symlink: bool,
@@ -377,66 +399,11 @@ fn stat_or_lstat(
         let path_scalar = this.read_scalar(path_op)?.not_undef()?;
         let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into();
 
-        let buf = this.deref_operand(buf_op)?;
-
-        let metadata = match FileMetadata::new(this, path, follow_symlink)? {
+        let metadata = match FileMetadata::from_path(this, path, follow_symlink)? {
             Some(metadata) => metadata,
             None => return Ok(-1),
         };
-
-        let mode: u16 = metadata.mode.to_u16()?;
-
-        let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0));
-        let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0));
-        let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0));
-
-        let dev_t_layout = this.libc_ty_layout("dev_t")?;
-        let mode_t_layout = this.libc_ty_layout("mode_t")?;
-        let nlink_t_layout = this.libc_ty_layout("nlink_t")?;
-        let ino_t_layout = this.libc_ty_layout("ino_t")?;
-        let uid_t_layout = this.libc_ty_layout("uid_t")?;
-        let gid_t_layout = this.libc_ty_layout("gid_t")?;
-        let time_t_layout = this.libc_ty_layout("time_t")?;
-        let long_layout = this.libc_ty_layout("c_long")?;
-        let off_t_layout = this.libc_ty_layout("off_t")?;
-        let blkcnt_t_layout = this.libc_ty_layout("blkcnt_t")?;
-        let blksize_t_layout = this.libc_ty_layout("blksize_t")?;
-        let uint32_t_layout = this.libc_ty_layout("uint32_t")?;
-
-        // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform.
-        let pad_layout = if this.tcx.sess.target.ptr_width == 64 {
-            uint32_t_layout
-        } else {
-            this.layout_of(this.tcx.mk_unit())?
-        };
-
-        let imms = [
-            immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev
-            immty_from_uint_checked(mode, mode_t_layout)?, // st_mode
-            immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink
-            immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino
-            immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid
-            immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid
-            immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev
-            immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets
-            immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime
-            immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec
-            immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime
-            immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec
-            immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime
-            immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec
-            immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime
-            immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec
-            immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size
-            immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks
-            immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize
-            immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags
-            immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen
-        ];
-
-        this.write_packed_immediates(&buf, &imms)?;
-
-        Ok(0)
+        stat_macos_write_buf(this, metadata, buf_op)
     }
 
     fn statx(
@@ -488,18 +455,28 @@ fn statx(
             this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| {
                 err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e)
             })?;
+        let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0;
         // `dirfd` should be a `c_int` but the `syscall` function provides an `isize`.
         let dirfd: i32 =
             this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| {
                 err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e)
             })?;
-        // we only support interpreting `path` as an absolute directory or as a directory relative
-        // to `dirfd` when the latter is `AT_FDCWD`. The behavior of `statx` with a relative path
-        // and a directory file descriptor other than `AT_FDCWD` is specified but it cannot be
-        // tested from `libstd`. If you found this error, please open an issue reporting it.
-        if !(path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")?) {
+        // We only support:
+        // * interpreting `path` as an absolute directory,
+        // * interpreting `path` as a path relative to `dirfd` when the latter is `AT_FDCWD`, or
+        // * interpreting `dirfd` as any file descriptor when `path` is empty and AT_EMPTY_PATH is
+        // set.
+        // Other behaviors cannot be tested from `libstd` and thus are not implemented. If you
+        // found this error, please open an issue reporting it.
+        if !(
+            path.is_absolute() ||
+            dirfd == this.eval_libc_i32("AT_FDCWD")? ||
+            (path.as_os_str().is_empty() && empty_path_flag)
+        ) {
             throw_unsup_format!(
-                "Using statx with a relative path and a file descriptor different from `AT_FDCWD` is not supported"
+                "Using statx is only supported with absolute paths, relative paths with the file \
+                descriptor `AT_FDCWD`, and empty paths with the `AT_EMPTY_PATH` flag set and any \
+                file descriptor"
             )
         }
 
@@ -514,7 +491,14 @@ fn statx(
         // symbolic links.
         let follow_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? == 0;
 
-        let metadata = match FileMetadata::new(this, path, follow_symlink)? {
+        // If the path is empty, and the AT_EMPTY_PATH flag is set, we query the open file
+        // represented by dirfd, whether it's a directory or otherwise.
+        let metadata = if path.as_os_str().is_empty() && empty_path_flag {
+            FileMetadata::from_fd(this, dirfd)?
+        } else {
+            FileMetadata::from_path(this, path, follow_symlink)?
+        };
+        let metadata = match metadata {
             Some(metadata) => metadata,
             None => return Ok(-1),
         };
@@ -583,7 +567,7 @@ fn statx(
             immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_minor
         ];
 
-        this.write_packed_immediates(&statxbuf_place, &imms)?;
+        this.write_packed_immediates(statxbuf_place, &imms)?;
 
         Ok(0)
     }
@@ -623,7 +607,7 @@ struct FileMetadata {
 }
 
 impl FileMetadata {
-    fn new<'tcx, 'mir>(
+    fn from_path<'tcx, 'mir>(
         ecx: &mut MiriEvalContext<'mir, 'tcx>,
         path: PathBuf,
         follow_symlink: bool
@@ -634,6 +618,27 @@ fn new<'tcx, 'mir>(
             std::fs::symlink_metadata(path)
         };
 
+        FileMetadata::from_meta(ecx, metadata)
+    }
+
+    fn from_fd<'tcx, 'mir>(
+        ecx: &mut MiriEvalContext<'mir, 'tcx>,
+        fd: i32,
+    ) -> InterpResult<'tcx, Option<FileMetadata>> {
+        let option = ecx.machine.file_handler.handles.get(&fd);
+        let handle = match option {
+            Some(handle) => handle,
+            None => return ecx.handle_not_found().map(|_: i32| None),
+        };
+        let metadata = handle.file.metadata();
+
+        FileMetadata::from_meta(ecx, metadata)
+    }
+
+    fn from_meta<'tcx, 'mir>(
+        ecx: &mut MiriEvalContext<'mir, 'tcx>,
+        metadata: Result<std::fs::Metadata, std::io::Error>,
+    ) -> InterpResult<'tcx, Option<FileMetadata>> {
         let metadata = match metadata {
             Ok(metadata) => metadata,
             Err(e) => {
@@ -664,3 +669,64 @@ fn new<'tcx, 'mir>(
         Ok(Some(FileMetadata { mode, size, created, accessed, modified }))
     }
 }
+
+fn stat_macos_write_buf<'tcx, 'mir>(
+    ecx: &mut MiriEvalContext<'mir, 'tcx>,
+    metadata: FileMetadata,
+    buf_op: OpTy<'tcx, Tag>,
+) -> InterpResult<'tcx, i32> {
+    let mode: u16 = metadata.mode.to_u16()?;
+
+    let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0));
+    let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0));
+    let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0));
+
+    let dev_t_layout = ecx.libc_ty_layout("dev_t")?;
+    let mode_t_layout = ecx.libc_ty_layout("mode_t")?;
+    let nlink_t_layout = ecx.libc_ty_layout("nlink_t")?;
+    let ino_t_layout = ecx.libc_ty_layout("ino_t")?;
+    let uid_t_layout = ecx.libc_ty_layout("uid_t")?;
+    let gid_t_layout = ecx.libc_ty_layout("gid_t")?;
+    let time_t_layout = ecx.libc_ty_layout("time_t")?;
+    let long_layout = ecx.libc_ty_layout("c_long")?;
+    let off_t_layout = ecx.libc_ty_layout("off_t")?;
+    let blkcnt_t_layout = ecx.libc_ty_layout("blkcnt_t")?;
+    let blksize_t_layout = ecx.libc_ty_layout("blksize_t")?;
+    let uint32_t_layout = ecx.libc_ty_layout("uint32_t")?;
+
+    // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform.
+    let pad_layout = if ecx.tcx.sess.target.ptr_width == 64 {
+        uint32_t_layout
+    } else {
+        ecx.layout_of(ecx.tcx.mk_unit())?
+    };
+
+    let imms = [
+        immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev
+        immty_from_uint_checked(mode, mode_t_layout)?, // st_mode
+        immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink
+        immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino
+        immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid
+        immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid
+        immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev
+        immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets
+        immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime
+        immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec
+        immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime
+        immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec
+        immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime
+        immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec
+        immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime
+        immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec
+        immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size
+        immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks
+        immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize
+        immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags
+        immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen
+    ];
+
+    let buf = ecx.deref_operand(buf_op)?;
+    ecx.write_packed_immediates(buf, &imms)?;
+
+    Ok(0)
+}
index 04e724ff1d3477458b078a5d15df327ced0eae83..9cae97a4060cf7bff3243ab4fe68d354cddaa9cc 100644 (file)
@@ -518,46 +518,6 @@ fn call_intrinsic(
                 this.write_scalar(Scalar::from_uint(align.bytes(), ptr_size), dest)?;
             }
 
-            "unchecked_div" => {
-                let l = this.read_immediate(args[0])?;
-                let r = this.read_immediate(args[1])?;
-                let rval = r.to_scalar()?.to_bits(args[1].layout.size)?;
-                if rval == 0 {
-                    throw_ub_format!("Division by 0 in unchecked_div");
-                }
-                this.binop_ignore_overflow(mir::BinOp::Div, l, r, dest)?;
-            }
-
-            "unchecked_rem" => {
-                let l = this.read_immediate(args[0])?;
-                let r = this.read_immediate(args[1])?;
-                let rval = r.to_scalar()?.to_bits(args[1].layout.size)?;
-                if rval == 0 {
-                    throw_ub_format!("Division by 0 in unchecked_rem");
-                }
-                this.binop_ignore_overflow(mir::BinOp::Rem, l, r, dest)?;
-            }
-
-            #[rustfmt::skip]
-            | "unchecked_add"
-            | "unchecked_sub"
-            | "unchecked_mul"
-            => {
-                let l = this.read_immediate(args[0])?;
-                let r = this.read_immediate(args[1])?;
-                let op = match intrinsic_name {
-                    "unchecked_add" => mir::BinOp::Add,
-                    "unchecked_sub" => mir::BinOp::Sub,
-                    "unchecked_mul" => mir::BinOp::Mul,
-                    _ => bug!(),
-                };
-                let (res, overflowed, _ty) = this.overflowing_binary_op(op, l, r)?;
-                if overflowed {
-                    throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name);
-                }
-                this.write_scalar(res, dest)?;
-            }
-
             "uninit" => {
                 // Check fast path: we don't want to force an allocation in case the destination is a simple value,
                 // but we also do not want to create a new allocation with 0s and then copy that over.
index a7d51eaa2e0f7a2006d5192bde1dbbfa511b9822..6adea524d2d88992a1cd1d5a9d48bd3d60652334 100644 (file)
@@ -45,7 +45,7 @@ fn clock_gettime(
             immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?,
         ];
 
-        this.write_packed_immediates(&tp, &imms)?;
+        this.write_packed_immediates(tp, &imms)?;
 
         Ok(0)
     }
@@ -77,7 +77,7 @@ fn gettimeofday(
             immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?,
         ];
 
-        this.write_packed_immediates(&tv, &imms)?;
+        this.write_packed_immediates(tv, &imms)?;
 
         Ok(0)
     }
index d124136a965372acf99fab9e061e250eacbcadb0..2ac35a450cf196f07cd7fb29c32e667798fcdf65 100644 (file)
@@ -3,7 +3,7 @@
 extern crate alloc;
 
 use alloc::alloc::Global;
-use std::alloc::*;
+use std::alloc::{AllocRef, Layout};
 
 // error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1
 
index 7a95b0ac7e90a620815f637f93282bbda9eed413..c5b48f5ddf59005748010daa12a7573a2bde3878 100644 (file)
@@ -3,7 +3,7 @@
 extern crate alloc;
 
 use alloc::alloc::Global;
-use std::alloc::*;
+use std::alloc::{AllocRef, Layout};
 
 // error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1
 
index 03fab76d601b57cba3399e66f9aa3770ffc5d8cd..02c442f0ab85f068769e3081e98bbb5302ff7dd9 100644 (file)
@@ -3,7 +3,7 @@
 extern crate alloc;
 
 use alloc::alloc::Global;
-use std::alloc::*;
+use std::alloc::{AllocRef, Layout};
 
 // error-pattern: tried to deallocate dangling pointer
 
index 987c18e4c492ab017dd385cab4767debd6fe8791..d67d06dc1e6742fdbf7f3b3787a5ef223585268d 100644 (file)
@@ -2,10 +2,8 @@
 
 use std::intrinsics::*;
 
-//error-pattern: Division by 0 in unchecked_div
-
 fn main() {
     unsafe {
-        let _n = unchecked_div(1i64, 0);
+        let _n = unchecked_div(1i64, 0); //~ERROR dividing by zero
     }
 }
diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs
new file mode 100644 (file)
index 0000000..e904049
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(core_intrinsics)]
+
+use std::intrinsics::*;
+
+fn main() {
+    unsafe {
+        let _n = unchecked_rem(3u32, 0); //~ ERROR calculating the remainder with a divisor of zero
+    }
+}
diff --git a/tests/compile-fail/div-by-zero-3.rs b/tests/compile-fail/div-by-zero-3.rs
deleted file mode 100644 (file)
index 3200504..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(core_intrinsics)]
-
-use std::intrinsics::*;
-
-//error-pattern: Division by 0 in unchecked_rem
-
-fn main() {
-    unsafe {
-        let _n = unchecked_rem(3u32, 0);
-    }
-}
index 2ae98adad77395c7111f64c6321c801c95015610..70ceacd8ca6facbaf788a6888c2b657d22b6b7b4 100644 (file)
@@ -25,7 +25,7 @@ impl<G> Iterator for GeneratorIteratorAdapter<G>
 
     fn next(&mut self) -> Option<Self::Item> {
         let me = unsafe { Pin::new_unchecked(&mut self.0) };
-        match me.resume() {
+        match me.resume(()) {
             GeneratorState::Yielded(x) => Some(x),
             GeneratorState::Complete(_) => None,
         }
index 24d913205447d7f95791c03f7a1854a7e1681af1..905e8e061721274758c5e2077905c05366a00eab 100644 (file)
@@ -3,7 +3,7 @@
 extern crate alloc;
 
 use alloc::alloc::Global;
-use std::alloc::*;
+use std::alloc::{AllocRef, Layout};
 
 // error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1
 
index 312edfd52b27755c913693d519d1a4e9ced6bfa8..21468739b31c0b364d8e781601a26f1ba75260c1 100644 (file)
@@ -3,7 +3,7 @@
 extern crate alloc;
 
 use alloc::alloc::Global;
-use std::alloc::*;
+use std::alloc::{AllocRef, Layout};
 
 fn main() {
     unsafe {
index 450f63cc40d3570b29438df92242ff0f67eb2138..ee73cfce8634be4dc68d5a728f42b254a3b66ba8 100644 (file)
@@ -3,7 +3,7 @@
 extern crate alloc;
 
 use alloc::alloc::Global;
-use std::alloc::*;
+use std::alloc::{AllocRef, Layout};
 
 // error-pattern: dangling pointer was dereferenced
 
diff --git a/tests/compile-fail/stacked_borrows/illegal_read8.rs b/tests/compile-fail/stacked_borrows/illegal_read8.rs
new file mode 100644 (file)
index 0000000..72fca84
--- /dev/null
@@ -0,0 +1,13 @@
+// Make sure that creating a raw ptr next to a shared ref works
+// but the shared ref still gets invalidated when the raw ptr is used for writing.
+
+fn main() { unsafe {
+    use std::mem;
+    let x = &mut 0;
+    let y1: &i32 = mem::transmute(&*x); // launder lifetimes
+    let y2 = x as *mut _;
+    let _val = *y2;
+    let _val = *y1;
+    *y2 += 1;
+    let _fail = *y1; //~ ERROR borrow stack
+} }
index 2447c8ba4a818cb68f3d5a1084d3dd9bb5061ebe..eb5a41fdfaf9d4bb5128e2c264bb5fe65b36fce3 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(core_intrinsics)]
 fn main() {
     // MAX overflow
-    unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflowing arithmetic in unchecked_add
+    unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflow executing `unchecked_add`
 }
index e292cdf6d961e07f3858a9cf02d9edc350188c80..fa6a232aedee9c23843237f88ded47c03bd172e5 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(core_intrinsics)]
 fn main() {
     // MIN overflow
-    unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflowing arithmetic in unchecked_add
+    unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflow executing `unchecked_add`
 }
diff --git a/tests/compile-fail/unchecked_div1.rs b/tests/compile-fail/unchecked_div1.rs
new file mode 100644 (file)
index 0000000..1d1bbb0
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(core_intrinsics)]
+fn main() {
+    // MIN/-1 cannot be represented
+    unsafe { std::intrinsics::unchecked_div(i16::min_value(), -1); } //~ ERROR Overflow executing `unchecked_div`
+}
index 57bfaf124c2417c593db226fdf2cb9f3fd78f9bc..a3681a57df79d255f6410d5e4951c706551ec542 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(core_intrinsics)]
 fn main() {
     // MAX overflow
-    unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflowing arithmetic in unchecked_mul
+    unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflow executing `unchecked_mul`
 }
index 690f2dc76284ccc4cb4dfaa8779bee7ebd167dd8..8fe677f8ded53028a40095d5d396df3ea0aa088c 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(core_intrinsics)]
 fn main() {
     // MIN overflow
-    unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflowing arithmetic in unchecked_mul
+    unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflow executing `unchecked_mul`
 }
index 0be8afa2c34cc8010ccb52c405660f700cd1e5af..230607f033058c80a4bf92ddc77cbd4d28ae4ee0 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(core_intrinsics)]
 fn main() {
     // MIN overflow
-    unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflowing arithmetic in unchecked_sub
+    unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflow executing `unchecked_sub`
 }
index bc23fa37c36764368b6081aec2446bac3fbdc353..1ea41a3c0fb07693089c10c7db3cd9edecfff3bd 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(core_intrinsics)]
 fn main() {
     // MAX overflow
-    unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflowing arithmetic in unchecked_sub
+    unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflow executing `unchecked_sub`
 }
index 73e6f37453fa5c73a2148f1dced97ab5b95e393a..7483bf3ec8b8ab6114fa498f915f3dbee16cec2a 100644 (file)
@@ -29,8 +29,10 @@ fn main() {
     let mut file = File::create(&path).unwrap();
     // Writing 0 bytes should not change the file contents.
     file.write(&mut []).unwrap();
+    assert_eq!(file.metadata().unwrap().len(), 0);
 
     file.write(bytes).unwrap();
+    assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
     // Test opening, reading and closing a file.
     let mut file = File::open(&path).unwrap();
     let mut contents = Vec::new();
index c31b5b9ed3bb2a3845f931d3dea776e3e8986dd1..e85d2cf8f29a8006a5ea23185f1784ed26ec85bb 100644 (file)
@@ -1,30 +1,32 @@
 #![feature(generators, generator_trait, never_type)]
 
-use std::ops::{GeneratorState, Generator};
+use std::ops::{GeneratorState::{self, *}, Generator};
 use std::pin::Pin;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::fmt::Debug;
 
-fn finish<T>(mut amt: usize, mut t: T) -> T::Return
-    where T: Generator<Yield = usize>
-{
-    // We are not moving the `t` around until it gets dropped, so this is okay.
-    let mut t = unsafe { Pin::new_unchecked(&mut t) };
-    loop {
-        match t.as_mut().resume() {
-            GeneratorState::Yielded(y) => amt -= y,
-            GeneratorState::Complete(ret) => {
-                assert_eq!(amt, 0);
-                return ret
+fn basic() {
+    fn finish<T>(mut amt: usize, mut t: T) -> T::Return
+        where T: Generator<Yield = usize>
+    {
+        // We are not moving the `t` around until it gets dropped, so this is okay.
+        let mut t = unsafe { Pin::new_unchecked(&mut t) };
+        loop {
+            match t.as_mut().resume(()) {
+                GeneratorState::Yielded(y) => amt -= y,
+                GeneratorState::Complete(ret) => {
+                    assert_eq!(amt, 0);
+                    return ret
+                }
             }
         }
     }
-}
 
-enum Never {}
-fn never() -> Never {
-    panic!()
-}
+    enum Never {}
+    fn never() -> Never {
+        panic!()
+    }
 
-fn main() {
     finish(1, || yield 1);
 
     finish(3, || {
@@ -94,3 +96,93 @@ fn main() {
         let _x: (String, !) = (String::new(), { yield 2; return });
     });
 }
+
+fn smoke_resume_arg() {
+    fn drain<G: Generator<R, Yield = Y> + Unpin, R, Y>(
+        gen: &mut G,
+        inout: Vec<(R, GeneratorState<Y, G::Return>)>,
+    ) where
+        Y: Debug + PartialEq,
+        G::Return: Debug + PartialEq,
+    {
+        let mut gen = Pin::new(gen);
+
+        for (input, out) in inout {
+            assert_eq!(gen.as_mut().resume(input), out);
+        }
+    }
+
+    static DROPS: AtomicUsize = AtomicUsize::new(0);
+
+    #[derive(Debug, PartialEq)]
+    struct DropMe;
+
+    impl Drop for DropMe {
+        fn drop(&mut self) {
+            DROPS.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+
+    fn expect_drops<T>(expected_drops: usize, f: impl FnOnce() -> T) -> T {
+        DROPS.store(0, Ordering::SeqCst);
+
+        let res = f();
+
+        let actual_drops = DROPS.load(Ordering::SeqCst);
+        assert_eq!(actual_drops, expected_drops);
+        res
+    }
+
+    drain(
+        &mut |mut b| {
+            while b != 0 {
+                b = yield (b + 1);
+            }
+            -1
+        },
+        vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))],
+    );
+
+    expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))]));
+
+    expect_drops(6, || {
+        drain(
+            &mut |a| yield yield a,
+            vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))],
+        )
+    });
+
+    #[allow(unreachable_code)]
+    expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))]));
+
+    expect_drops(2, || {
+        drain(
+            &mut |a: DropMe| {
+                if false { yield () } else { a }
+            },
+            vec![(DropMe, Complete(DropMe))],
+        )
+    });
+
+    expect_drops(4, || {
+        drain(
+            #[allow(unused_assignments, unused_variables)]
+            &mut |mut a: DropMe| {
+                a = yield;
+                a = yield;
+                a = yield;
+            },
+            vec![
+                (DropMe, Yielded(())),
+                (DropMe, Yielded(())),
+                (DropMe, Yielded(())),
+                (DropMe, Complete(())),
+            ],
+        )
+    });
+}
+
+fn main() {
+    basic();
+    smoke_resume_arg();
+}
index 7bcb08058c36aa31aad50465429d9b695e8b6970..907fbf962df02ebdf687586edb966d8a71b8abd6 100644 (file)
@@ -1,10 +1,10 @@
 #![feature(allocator_api)]
 
 use std::ptr::NonNull;
-use std::alloc::{Global, Alloc, Layout, System};
+use std::alloc::{Global, AllocRef, Layout, System};
 use std::slice;
 
-fn check_alloc<T: Alloc>(mut allocator: T) { unsafe {
+fn check_alloc<T: AllocRef>(mut allocator: T) { unsafe {
     for &align in &[4, 8, 16, 32] {
         let layout = Layout::from_size_align(20, align).unwrap();
 
@@ -40,7 +40,7 @@ fn check_alloc<T: Alloc>(mut allocator: T) { unsafe {
     }
 } }
 
-fn check_align_requests<T: Alloc>(mut allocator: T) {
+fn check_align_requests<T: AllocRef>(mut allocator: T) {
     for &size in &[2, 8, 64] { // size less than and bigger than alignment
         for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures
             let iterations = 32;
diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs
new file mode 100644 (file)
index 0000000..5b7b37d
--- /dev/null
@@ -0,0 +1,43 @@
+// ignore-windows: No libc on Windows
+// compile-flags: -Zmiri-disable-isolation
+
+#![feature(rustc_private)]
+
+#[allow(unused)] // necessary on macos due to conditional compilation
+extern crate libc;
+
+#[cfg(not(target_os = "macos"))]
+fn test_posix_fadvise() {
+    use std::convert::TryInto;
+    use std::env::temp_dir;
+    use std::fs::{File, remove_file};
+    use std::io::Write;
+    use std::os::unix::io::AsRawFd;
+
+    let path = temp_dir().join("miri_test_libc.txt");
+    // Cleanup before test
+    remove_file(&path).ok();
+
+    // Set up an open file
+    let mut file = File::create(&path).unwrap();
+    let bytes = b"Hello, World!\n";
+    file.write(bytes).unwrap();
+
+    // Test calling posix_fadvise on a file.
+    let result = unsafe {
+        libc::posix_fadvise(
+            file.as_raw_fd(),
+            0,
+            bytes.len().try_into().unwrap(),
+            libc::POSIX_FADV_DONTNEED,
+        )
+    };
+    drop(file);
+    remove_file(&path).unwrap();
+    assert_eq!(result, 0);
+}
+
+fn main() {
+    #[cfg(not(target_os = "macos"))]
+    test_posix_fadvise();
+}
index fe6a9a54d4f34ad0afeed535e887e50cda3b708e..765c6188b6e17a925cb47a624c2fc72ae6e3bc33 100644 (file)
@@ -108,7 +108,7 @@ fn drop_after_sharing() {
 
 // Make sure that coercing &mut T to *const T produces a writeable pointer.
 fn direct_mut_to_const_raw() {
-    // FIXME: This is currently disabled, waiting on a fix for <https://github.com/rust-lang/rust/issues/56604>
+    // TODO: This is currently disabled, waiting on a decision on <https://github.com/rust-lang/rust/issues/56604>
     /*let x = &mut 0;
     let y: *const i32 = x;
     unsafe { *(y as *mut i32) = 1; }
@@ -119,9 +119,6 @@ fn direct_mut_to_const_raw() {
 // Make sure that we can create two raw pointers from a mutable reference and use them both.
 fn two_raw() { unsafe {
     let x = &mut 0;
-    // Given the implicit reborrows, the only reason this currently works is that we
-    // do not track raw pointers: The creation of `y2` reborrows `x` and thus pops
-    // `y1` off the stack.
     let y1 = x as *mut _;
     let y2 = x as *mut _;
     *y1 += 2;
@@ -129,16 +126,14 @@ fn two_raw() { unsafe {
 } }
 
 // Make sure that creating a *mut does not invalidate existing shared references.
-fn shr_and_raw() { /* unsafe {
+fn shr_and_raw() { unsafe {
     use std::mem;
-    // FIXME: This is currently disabled because "as *mut _" incurs a reborrow.
     let x = &mut 0;
     let y1: &i32 = mem::transmute(&*x); // launder lifetimes
     let y2 = x as *mut _;
     let _val = *y1;
     *y2 += 1;
-    // TODO: Once this works, add compile-fail test that tries to read from y1 again.
-} */ }
+} }
 
 fn disjoint_mutable_subborrows() {
     struct Foo {
@@ -165,5 +160,5 @@ unsafe fn borrow_field_b<'a>(this:*mut Foo) -> &'a mut Vec<u32> {
     let b = unsafe{ borrow_field_b(ptr) };
     b.push(4);
     a.push_str(" world");
-    dbg!(a,b);
+    eprintln!("{:?} {:?}", a, b);
 }
index 4493d45ae157a17c81eb7b14cb82a97d3443f3e6..8ee4e25dbef8431827774bed1ae50b8cfdf16b24 100644 (file)
@@ -1,7 +1 @@
-[$DIR/stacked-borrows.rs:168] a = "hello world"
-[$DIR/stacked-borrows.rs:168] b = [
-    0,
-    1,
-    2,
-    4,
-]
+"hello world" [0, 1, 2, 4]
index 68a0c95b44dbad9b8c0c41fb7d020f9aa6d5d923..f6797c24ebecf327ee3458b6cbfa7d2308d6aad3 100644 (file)
@@ -19,15 +19,33 @@ macro_rules! caller_location_from_macro {
     () => (core::panic::Location::caller());
 }
 
+fn test_fn_ptr() {
+    fn pass_to_ptr_call<T>(f: fn(T), x: T) {
+        f(x);
+    }
+
+    #[track_caller]
+    fn tracked_unit(_: ()) {
+        let expected_line = line!() - 1;
+        let location = std::panic::Location::caller();
+        assert_eq!(location.file(), file!());
+        assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
+    }
+
+    pass_to_ptr_call(tracked_unit, ());
+}
+
 fn main() {
     let location = Location::caller();
+    let expected_line = line!() - 1;
     assert_eq!(location.file(), file!());
-    assert_eq!(location.line(), 23);
+    assert_eq!(location.line(), expected_line);
     assert_eq!(location.column(), 20);
 
     let tracked = tracked();
+    let expected_line = line!() - 1;
     assert_eq!(tracked.file(), file!());
-    assert_eq!(tracked.line(), 28);
+    assert_eq!(tracked.line(), expected_line);
     assert_eq!(tracked.column(), 19);
 
     let nested = nested_intrinsic();
@@ -43,12 +61,16 @@ fn main() {
     // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
     // i.e. point to where the macro was invoked, instead of the macro itself.
     let inmacro = caller_location_from_macro!();
+    let expected_line = line!() - 1;
     assert_eq!(inmacro.file(), file!());
-    assert_eq!(inmacro.line(), 45);
+    assert_eq!(inmacro.line(), expected_line);
     assert_eq!(inmacro.column(), 19);
 
     let intrinsic = core::intrinsics::caller_location();
+    let expected_line = line!() - 1;
     assert_eq!(intrinsic.file(), file!());
-    assert_eq!(intrinsic.line(), 50);
+    assert_eq!(intrinsic.line(), expected_line);
     assert_eq!(intrinsic.column(), 21);
+
+    test_fn_ptr();
 }