Remove all non-CTFE stuff from the miri repository
This commit is contained in:
parent
ed674f7cb3
commit
f035b3d246
285 changed files with 0 additions and 11610 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -1,6 +0,0 @@
|
|||
target
|
||||
/doc
|
||||
tex/*/out
|
||||
*.dot
|
||||
*.mir
|
||||
*.rs.bk
|
||||
45
.travis.yml
45
.travis.yml
|
|
@ -1,45 +0,0 @@
|
|||
language: rust
|
||||
rust:
|
||||
- nightly
|
||||
before_script:
|
||||
- export PATH=$HOME/.local/bin:$PATH
|
||||
- rustup target add i686-unknown-linux-gnu
|
||||
- rustup target add i686-pc-windows-gnu
|
||||
- rustup target add i686-pc-windows-msvc
|
||||
- rustup component add rust-src
|
||||
- cargo install --git https://github.com/japaric/xargo.git
|
||||
- export RUST_SYSROOT=$HOME/rust
|
||||
script:
|
||||
- set -e
|
||||
- |
|
||||
# get ourselves a MIR-ful libstd
|
||||
xargo/build.sh
|
||||
- |
|
||||
# Test plain miri
|
||||
cargo build --locked --release --all-features &&
|
||||
cargo test --locked --release --all-features --all &&
|
||||
cargo install --locked --all-features
|
||||
- |
|
||||
# Test cargo miri
|
||||
cd cargo-miri-test &&
|
||||
cargo miri &&
|
||||
cargo miri test &&
|
||||
cd ..
|
||||
- |
|
||||
# and run all tests with full mir
|
||||
MIRI_SYSROOT=~/.xargo/HOST cargo test --locked --release
|
||||
- |
|
||||
# test that the rustc_tests binary compiles
|
||||
cd rustc_tests &&
|
||||
cargo build --locked --release &&
|
||||
cd ..
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
env:
|
||||
global:
|
||||
- RUST_TEST_NOCAPTURE=1
|
||||
- TRAVIS_CARGO_NIGHTLY_FEATURE=""
|
||||
413
Cargo.lock
generated
413
Cargo.lock
generated
|
|
@ -1,413 +0,0 @@
|
|||
[root]
|
||||
name = "rustc_miri"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace-sys"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "compiletest_rs"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "conv"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "custom_derive"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "dbghelp-sys"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log_settings"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "magenta"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "magenta-sys"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miri"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_miri 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.11.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synom"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempdir"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
|
||||
"checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983"
|
||||
"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
|
||||
"checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b"
|
||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||
"checksum compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86f4663adfd113e17109c35c2067194eca782a5baf9c90f4696ca13d04631adb"
|
||||
"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
|
||||
"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9"
|
||||
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
|
||||
"checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472"
|
||||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
|
||||
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
|
||||
"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a"
|
||||
"checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9"
|
||||
"checksum itoa 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f74cf6ca1bdbc28496a2b9798ab7fccc2ca5a42cace95bb2b219577216a5fb90"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
|
||||
"checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915"
|
||||
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
|
||||
"checksum log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3d382732ea0fbc09790c4899db3255bdea0fc78b54bf234bd18a63bb603915b6"
|
||||
"checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527"
|
||||
"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699"
|
||||
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
|
||||
"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0"
|
||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
"checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf"
|
||||
"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
|
||||
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
|
||||
"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e"
|
||||
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
||||
"checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9"
|
||||
"checksum serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cf823e706be268e73e7747b147aa31c8f633ab4ba31f115efb57e5047c3a76dd"
|
||||
"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a"
|
||||
"checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b"
|
||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
|
||||
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
|
||||
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
39
Cargo.toml
39
Cargo.toml
|
|
@ -1,39 +0,0 @@
|
|||
[package]
|
||||
authors = ["Scott Olson <scott@solson.me>"]
|
||||
description = "An experimental interpreter for Rust MIR."
|
||||
license = "MIT/Apache-2.0"
|
||||
name = "miri"
|
||||
repository = "https://github.com/solson/miri"
|
||||
version = "0.1.0"
|
||||
build = "build.rs"
|
||||
|
||||
[[bin]]
|
||||
doc = false
|
||||
name = "miri"
|
||||
path = "miri/bin/miri.rs"
|
||||
|
||||
[[bin]]
|
||||
doc = false
|
||||
name = "cargo-miri"
|
||||
path = "miri/bin/cargo-miri.rs"
|
||||
required-features = ["cargo_miri"]
|
||||
|
||||
[lib]
|
||||
path = "miri/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
byteorder = { version = "1.1", features = ["i128"]}
|
||||
env_logger = "0.4.3"
|
||||
log = "0.3.6"
|
||||
log_settings = "0.1.1"
|
||||
cargo_metadata = { version = "0.2", optional = true }
|
||||
rustc_miri = { path = "src/librustc_mir" }
|
||||
|
||||
[features]
|
||||
cargo_miri = ["cargo_metadata"]
|
||||
|
||||
[dev-dependencies]
|
||||
compiletest_rs = { version = "0.3", features = ["tmp"] }
|
||||
|
||||
[workspace]
|
||||
exclude = ["xargo", "cargo-miri-test", "rustc_tests"]
|
||||
201
LICENSE-APACHE
201
LICENSE-APACHE
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2016 The Miri Developers
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
25
LICENSE-MIT
25
LICENSE-MIT
|
|
@ -1,25 +0,0 @@
|
|||
Copyright (c) 2016 The Miri Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
103
README.md
103
README.md
|
|
@ -1,103 +0,0 @@
|
|||
# Miri [[slides](https://solson.me/miri-slides.pdf)] [[report](https://solson.me/miri-report.pdf)] [](https://travis-ci.org/solson/miri) [](https://ci.appveyor.com/project/solson63299/miri)
|
||||
|
||||
|
||||
An experimental interpreter for [Rust][rust]'s [mid-level intermediate
|
||||
representation][mir] (MIR). This project began as part of my work for the
|
||||
undergraduate research course at the [University of Saskatchewan][usask].
|
||||
|
||||
## Installing Rust
|
||||
|
||||
I recommend that you install [rustup][rustup] and then use it to install the
|
||||
current Rust nightly version:
|
||||
|
||||
```sh
|
||||
rustup update nightly
|
||||
```
|
||||
|
||||
You should also make `nightly` the default version for your Miri directory by
|
||||
running the following command while you're in it. If you don't do this, you can
|
||||
run the later `cargo` commands by using `cargo +nightly` instead.
|
||||
|
||||
```sh
|
||||
rustup override add nightly
|
||||
```
|
||||
|
||||
## Building Miri
|
||||
|
||||
```sh
|
||||
cargo build
|
||||
```
|
||||
|
||||
If Miri fails to build, it's likely because a change in the latest nightly
|
||||
compiler broke it. You could try an older nightly with `rustup update
|
||||
nightly-<date>` where `<date>` is a few days or weeks ago, e.g. `2016-05-20` for
|
||||
May 20th. Otherwise, you could notify me in an issue or on IRC. Or, if you know
|
||||
how to fix it, you could send a PR. :smile:
|
||||
|
||||
## Running tests
|
||||
|
||||
```sh
|
||||
cargo run --bin miri tests/run-pass/vecs.rs # Or whatever test you like.
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
You can get detailed, statement-by-statement traces by setting the `MIRI_LOG`
|
||||
environment variable to `trace`. These traces are indented based on call stack
|
||||
depth. You can get a much less verbose set of information with other logging
|
||||
levels such as `warn`.
|
||||
|
||||
## Running miri on your own project('s test suite)
|
||||
|
||||
Install miri as a cargo subcommand with `cargo install --debug`.
|
||||
Then, inside your own project, use `cargo +nightly miri` to run your project, if it is
|
||||
a bin project, or run `cargo +nightly miri test` to run all tests in your project
|
||||
through miri.
|
||||
|
||||
## Running miri with full libstd
|
||||
|
||||
Per default libstd does not contain the MIR of non-polymorphic functions. When
|
||||
miri hits a call to such a function, execution terminates. To fix this, it is
|
||||
possible to compile libstd with full MIR:
|
||||
|
||||
```sh
|
||||
rustup component add rust-src
|
||||
cargo install xargo
|
||||
cd xargo/
|
||||
RUSTFLAGS='-Zalways-encode-mir' xargo build
|
||||
```
|
||||
|
||||
Now you can run miri against the libstd compiled by xargo:
|
||||
|
||||
```sh
|
||||
MIRI_SYSROOT=~/.xargo/HOST cargo run --bin miri tests/run-pass-fullmir/vecs.rs
|
||||
```
|
||||
|
||||
Notice that you will have to re-run the last step of the preparations above when
|
||||
your toolchain changes (e.g., when you update the nightly).
|
||||
|
||||
## Contributing and getting help
|
||||
|
||||
Check out the issues on this GitHub repository for some ideas. There's lots that
|
||||
needs to be done that I haven't documented in the issues yet, however. For more
|
||||
ideas or help with running or hacking on Miri, you can contact me (`scott`) on
|
||||
Mozilla IRC in any of the Rust IRC channels (`#rust`, `#rust-offtopic`, etc).
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
http://opensource.org/licenses/MIT) at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you shall be dual licensed as above, without any
|
||||
additional terms or conditions.
|
||||
|
||||
[rust]: https://www.rust-lang.org/
|
||||
[mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md
|
||||
[usask]: https://www.usask.ca/
|
||||
[rustup]: https://www.rustup.rs
|
||||
41
appveyor.yml
41
appveyor.yml
|
|
@ -1,41 +0,0 @@
|
|||
environment:
|
||||
global:
|
||||
PROJECT_NAME: miri
|
||||
matrix:
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
MSYS2_BITS: 32
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
MSYS2_BITS: 64
|
||||
|
||||
# branches to build
|
||||
branches:
|
||||
# whitelist
|
||||
only:
|
||||
- master
|
||||
|
||||
install:
|
||||
- set PATH=C:\Program Files\Git\mingw64\bin;%PATH%
|
||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
||||
- rustup-init.exe -y --default-host %TARGET% --default-toolchain nightly
|
||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin;C:\Users\appveyor\.rustup\toolchains\nightly-%TARGET%\bin
|
||||
- if defined MSYS2_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS2_BITS%\bin
|
||||
- rustc -V
|
||||
- cargo -V
|
||||
- rustup component add rust-src
|
||||
- cargo install --git https://github.com/japaric/xargo.git
|
||||
- cd xargo
|
||||
- set RUSTFLAGS=-Zalways-encode-mir -Zmir-emit-validate=1
|
||||
- xargo build
|
||||
- set RUSTFLAGS=
|
||||
- cd ..
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- set RUST_BACKTRACE=1
|
||||
- cargo build --locked --release
|
||||
- cargo test --locked --release
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
on_build_success: false
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#![feature(test, rustc_private)]
|
||||
|
||||
extern crate test;
|
||||
use test::Bencher;
|
||||
mod helpers;
|
||||
use helpers::*;
|
||||
|
||||
#[bench]
|
||||
fn fib(bencher: &mut Bencher) {
|
||||
bencher.iter(|| { fibonacci_helper::main(); })
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib_miri(bencher: &mut Bencher) {
|
||||
miri_helper::run("fibonacci_helper", bencher);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib_iter(bencher: &mut Bencher) {
|
||||
bencher.iter(|| { fibonacci_helper_iterative::main(); })
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib_iter_miri(bencher: &mut Bencher) {
|
||||
miri_helper::run("fibonacci_helper_iterative", bencher);
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#[inline(never)]
|
||||
pub fn main() {
|
||||
assert_eq!(fib(10), 55);
|
||||
}
|
||||
|
||||
fn fib(n: usize) -> usize {
|
||||
if n <= 2 { 1 } else { fib(n - 1) + fib(n - 2) }
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#[inline(never)]
|
||||
pub fn main() {
|
||||
assert_eq!(fib(10), 55);
|
||||
}
|
||||
|
||||
fn fib(n: usize) -> usize {
|
||||
let mut a = 0;
|
||||
let mut b = 1;
|
||||
for _ in 0..n {
|
||||
let c = a;
|
||||
a = b;
|
||||
b = c + b;
|
||||
}
|
||||
a
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
extern crate getopts;
|
||||
extern crate miri;
|
||||
extern crate rustc;
|
||||
extern crate rustc_driver;
|
||||
extern crate test;
|
||||
|
||||
use self::miri::eval_main;
|
||||
use self::rustc::session::Session;
|
||||
use self::rustc_driver::{driver, CompilerCalls, Compilation};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use test::Bencher;
|
||||
|
||||
pub struct MiriCompilerCalls<'a>(Rc<RefCell<&'a mut Bencher>>);
|
||||
|
||||
fn find_sysroot() -> String {
|
||||
// Taken from https://github.com/Manishearth/rust-clippy/pull/911.
|
||||
let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
|
||||
let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
|
||||
match (home, toolchain) {
|
||||
(Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
|
||||
_ => {
|
||||
option_env!("RUST_SYSROOT")
|
||||
.expect(
|
||||
"need to specify RUST_SYSROOT env var or use rustup or multirust",
|
||||
)
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(filename: &str, bencher: &mut Bencher) {
|
||||
let args = &[
|
||||
"miri".to_string(),
|
||||
format!("benches/helpers/{}.rs", filename),
|
||||
"--sysroot".to_string(),
|
||||
find_sysroot(),
|
||||
];
|
||||
let compiler_calls = &mut MiriCompilerCalls(Rc::new(RefCell::new(bencher)));
|
||||
rustc_driver::run_compiler(args, compiler_calls, None, None);
|
||||
}
|
||||
|
||||
impl<'a> CompilerCalls<'a> for MiriCompilerCalls<'a> {
|
||||
fn build_controller(
|
||||
&mut self,
|
||||
_: &Session,
|
||||
_: &getopts::Matches,
|
||||
) -> driver::CompileController<'a> {
|
||||
let mut control: driver::CompileController<'a> = driver::CompileController::basic();
|
||||
|
||||
let bencher = self.0.clone();
|
||||
|
||||
control.after_analysis.stop = Compilation::Stop;
|
||||
control.after_analysis.callback = Box::new(move |state| {
|
||||
state.session.abort_if_errors();
|
||||
|
||||
let tcx = state.tcx.unwrap();
|
||||
let (entry_node_id, _) = state.session.entry_fn.borrow().expect(
|
||||
"no main or start function found",
|
||||
);
|
||||
let entry_def_id = tcx.map.local_def_id(entry_node_id);
|
||||
|
||||
let memory_size = 100 * 1024 * 1024; // 100MB
|
||||
let step_limit = 1000_000;
|
||||
let stack_limit = 100;
|
||||
bencher.borrow_mut().iter(|| {
|
||||
eval_main(tcx, entry_def_id, memory_size, step_limit, stack_limit);
|
||||
});
|
||||
|
||||
state.session.abort_if_errors();
|
||||
});
|
||||
|
||||
control
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
// This module gets included in multiple crates, and they each only use part of it.
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub mod fibonacci_helper;
|
||||
pub mod fibonacci_helper_iterative;
|
||||
pub mod miri_helper;
|
||||
pub mod smoke_helper;
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
fn main() {
|
||||
let data: [u8; 1024] = [42; 1024];
|
||||
assert_eq!(data.len(), 1024);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fn main() {
|
||||
let mut data: [u8; 1024] = unsafe { std::mem::uninitialized() };
|
||||
for i in 0..data.len() {
|
||||
unsafe { std::ptr::write(&mut data[i], 0); }
|
||||
}
|
||||
assert_eq!(data.len(), 1024);
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#[inline(never)]
|
||||
pub fn main() {}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#![feature(test, rustc_private)]
|
||||
|
||||
extern crate test;
|
||||
use test::Bencher;
|
||||
mod helpers;
|
||||
use helpers::*;
|
||||
|
||||
#[bench]
|
||||
fn repeat(bencher: &mut Bencher) {
|
||||
miri_helper::run("repeat", bencher);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn repeat_manual(bencher: &mut Bencher) {
|
||||
miri_helper::run("repeat_manual", bencher);
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
#![feature(test, rustc_private)]
|
||||
|
||||
extern crate test;
|
||||
use test::Bencher;
|
||||
mod helpers;
|
||||
use helpers::*;
|
||||
|
||||
#[bench]
|
||||
fn noop(bencher: &mut Bencher) {
|
||||
bencher.iter(|| { smoke_helper::main(); })
|
||||
}
|
||||
|
||||
/*
|
||||
// really slow
|
||||
#[bench]
|
||||
fn noop_miri_full(bencher: &mut Bencher) {
|
||||
let path = std::env::var("RUST_SYSROOT").expect("env variable `RUST_SYSROOT` not set");
|
||||
bencher.iter(|| {
|
||||
let mut process = std::process::Command::new("target/release/miri");
|
||||
process.arg("benches/smoke_helper.rs")
|
||||
.arg("--sysroot").arg(&path);
|
||||
let output = process.output().unwrap();
|
||||
if !output.status.success() {
|
||||
println!("{}", String::from_utf8(output.stdout).unwrap());
|
||||
println!("{}", String::from_utf8(output.stderr).unwrap());
|
||||
panic!("failed to run miri");
|
||||
}
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
#[bench]
|
||||
fn noop_miri_interpreter(bencher: &mut Bencher) {
|
||||
miri_helper::run("smoke_helper", bencher);
|
||||
}
|
||||
8
build.rs
8
build.rs
|
|
@ -1,8 +0,0 @@
|
|||
use std::env;
|
||||
|
||||
fn main() {
|
||||
// Forward the profile to the main compilation
|
||||
println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
|
||||
// Don't rebuild miri even if nothing changed
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
||||
14
cargo-miri-test/Cargo.lock
generated
14
cargo-miri-test/Cargo.lock
generated
|
|
@ -1,14 +0,0 @@
|
|||
[root]
|
||||
name = "cargo-miri-test"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8"
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
[package]
|
||||
name = "cargo-miri-test"
|
||||
version = "0.1.0"
|
||||
authors = ["Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>"]
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.0"
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
extern crate byteorder;
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
|
||||
fn main() {
|
||||
let buf = &[1,2,3,4];
|
||||
let n = <BigEndian as ByteOrder>::read_u32(buf);
|
||||
assert_eq!(n, 0x01020304);
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#[test]
|
||||
fn bar() {
|
||||
assert_eq!(4, 4);
|
||||
}
|
||||
|
|
@ -1,212 +0,0 @@
|
|||
extern crate cargo_metadata;
|
||||
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::io::Write;
|
||||
use std::process::Command;
|
||||
|
||||
|
||||
const CARGO_MIRI_HELP: &str = r#"Interprets bin crates
|
||||
|
||||
Usage:
|
||||
cargo miri [options] [--] [<opts>...]
|
||||
|
||||
Common options:
|
||||
-h, --help Print this message
|
||||
--features Features to compile for the package
|
||||
-V, --version Print version info and exit
|
||||
|
||||
Other options are the same as `cargo rustc`.
|
||||
|
||||
The feature `cargo-miri` is automatically defined for convenience. You can use
|
||||
it to configure the resource limits
|
||||
|
||||
#![cfg_attr(feature = "cargo-miri", memory_size = 42)]
|
||||
|
||||
available resource limits are `memory_size`, `step_limit`, `stack_limit`
|
||||
"#;
|
||||
|
||||
fn show_help() {
|
||||
println!("{}", CARGO_MIRI_HELP);
|
||||
}
|
||||
|
||||
fn show_version() {
|
||||
println!("{}", env!("CARGO_PKG_VERSION"));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Check for version and help flags even when invoked as 'cargo-miri'
|
||||
if std::env::args().any(|a| a == "--help" || a == "-h") {
|
||||
show_help();
|
||||
return;
|
||||
}
|
||||
if std::env::args().any(|a| a == "--version" || a == "-V") {
|
||||
show_version();
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
|
||||
// this arm is when `cargo miri` is called
|
||||
|
||||
let test = std::env::args().nth(2).map_or(false, |text| text == "test");
|
||||
let skip = if test { 3 } else { 2 };
|
||||
|
||||
let manifest_path_arg = std::env::args().skip(skip).find(|val| {
|
||||
val.starts_with("--manifest-path=")
|
||||
});
|
||||
|
||||
let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(
|
||||
manifest_path_arg.as_ref().map(AsRef::as_ref),
|
||||
)
|
||||
{
|
||||
metadata
|
||||
} else {
|
||||
let _ = std::io::stderr().write_fmt(format_args!(
|
||||
"error: Could not obtain cargo metadata."
|
||||
));
|
||||
std::process::exit(101);
|
||||
};
|
||||
|
||||
let manifest_path = manifest_path_arg.map(|arg| {
|
||||
PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))
|
||||
});
|
||||
|
||||
let current_dir = std::env::current_dir();
|
||||
|
||||
let package_index = metadata
|
||||
.packages
|
||||
.iter()
|
||||
.position(|package| {
|
||||
let package_manifest_path = Path::new(&package.manifest_path);
|
||||
if let Some(ref manifest_path) = manifest_path {
|
||||
package_manifest_path == manifest_path
|
||||
} else {
|
||||
let current_dir = current_dir.as_ref().expect(
|
||||
"could not read current directory",
|
||||
);
|
||||
let package_manifest_directory = package_manifest_path.parent().expect(
|
||||
"could not find parent directory of package manifest",
|
||||
);
|
||||
package_manifest_directory == current_dir
|
||||
}
|
||||
})
|
||||
.expect("could not find matching package");
|
||||
let package = metadata.packages.remove(package_index);
|
||||
for target in package.targets {
|
||||
let args = std::env::args().skip(skip);
|
||||
let kind = target.kind.get(0).expect(
|
||||
"badly formatted cargo metadata: target::kind is an empty array",
|
||||
);
|
||||
if test && kind == "test" {
|
||||
if let Err(code) = process(
|
||||
vec!["--test".to_string(), target.name].into_iter().chain(
|
||||
args,
|
||||
),
|
||||
)
|
||||
{
|
||||
std::process::exit(code);
|
||||
}
|
||||
} else if !test && kind == "bin" {
|
||||
if let Err(code) = process(
|
||||
vec!["--bin".to_string(), target.name].into_iter().chain(
|
||||
args,
|
||||
),
|
||||
)
|
||||
{
|
||||
std::process::exit(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// this arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself
|
||||
|
||||
let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
|
||||
let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
|
||||
let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) {
|
||||
format!("{}/toolchains/{}", home, toolchain)
|
||||
} else {
|
||||
option_env!("RUST_SYSROOT")
|
||||
.map(|s| s.to_owned())
|
||||
.or_else(|| {
|
||||
Command::new("rustc")
|
||||
.arg("--print")
|
||||
.arg("sysroot")
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|out| String::from_utf8(out.stdout).ok())
|
||||
.map(|s| s.trim().to_owned())
|
||||
})
|
||||
.expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust")
|
||||
};
|
||||
|
||||
// this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly
|
||||
// without having to pass --sysroot or anything
|
||||
let mut args: Vec<String> = if std::env::args().any(|s| s == "--sysroot") {
|
||||
std::env::args().skip(1).collect()
|
||||
} else {
|
||||
std::env::args()
|
||||
.skip(1)
|
||||
.chain(Some("--sysroot".to_owned()))
|
||||
.chain(Some(sys_root))
|
||||
.collect()
|
||||
};
|
||||
|
||||
// this check ensures that dependencies are built but not interpreted and the final crate is
|
||||
// interpreted but not built
|
||||
let miri_enabled = std::env::args().any(|s| s == "-Zno-trans");
|
||||
|
||||
let mut command = if miri_enabled {
|
||||
let mut path = std::env::current_exe().expect("current executable path invalid");
|
||||
path.set_file_name("miri");
|
||||
Command::new(path)
|
||||
} else {
|
||||
Command::new("rustc")
|
||||
};
|
||||
|
||||
args.extend_from_slice(&["-Z".to_owned(), "always-encode-mir".to_owned()]);
|
||||
args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]);
|
||||
|
||||
match command.args(&args).status() {
|
||||
Ok(exit) => {
|
||||
if !exit.success() {
|
||||
std::process::exit(exit.code().unwrap_or(42));
|
||||
}
|
||||
}
|
||||
Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e),
|
||||
Err(ref e) => panic!("error during rustc call: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process<I>(old_args: I) -> Result<(), i32>
|
||||
where
|
||||
I: Iterator<Item = String>,
|
||||
{
|
||||
let mut args = vec!["rustc".to_owned()];
|
||||
|
||||
let mut found_dashes = false;
|
||||
for arg in old_args {
|
||||
found_dashes |= arg == "--";
|
||||
args.push(arg);
|
||||
}
|
||||
if !found_dashes {
|
||||
args.push("--".to_owned());
|
||||
}
|
||||
args.push("-Zno-trans".to_owned());
|
||||
args.push("--cfg".to_owned());
|
||||
args.push(r#"feature="cargo-miri""#.to_owned());
|
||||
|
||||
let path = std::env::current_exe().expect("current executable path invalid");
|
||||
let exit_status = std::process::Command::new("cargo")
|
||||
.args(&args)
|
||||
.env("RUSTC", path)
|
||||
.spawn()
|
||||
.expect("could not run cargo")
|
||||
.wait()
|
||||
.expect("failed to wait for cargo?");
|
||||
|
||||
if exit_status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(exit_status.code().unwrap_or(-1))
|
||||
}
|
||||
}
|
||||
265
miri/bin/miri.rs
265
miri/bin/miri.rs
|
|
@ -1,265 +0,0 @@
|
|||
#![feature(rustc_private, i128_type)]
|
||||
|
||||
extern crate getopts;
|
||||
extern crate miri;
|
||||
extern crate rustc;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_errors;
|
||||
extern crate env_logger;
|
||||
extern crate log_settings;
|
||||
extern crate syntax;
|
||||
extern crate log;
|
||||
|
||||
use rustc::session::Session;
|
||||
use rustc::middle::cstore::CrateStore;
|
||||
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
|
||||
use rustc_driver::driver::{CompileState, CompileController};
|
||||
use rustc::session::config::{self, Input, ErrorOutputType};
|
||||
use rustc::hir::{self, itemlikevisit};
|
||||
use rustc::ty::TyCtxt;
|
||||
use syntax::ast::{self, MetaItemKind, NestedMetaItemKind};
|
||||
use std::path::PathBuf;
|
||||
|
||||
struct MiriCompilerCalls {
|
||||
default: RustcDefaultCalls,
|
||||
}
|
||||
|
||||
impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
|
||||
fn early_callback(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sopts: &config::Options,
|
||||
cfg: &ast::CrateConfig,
|
||||
descriptions: &rustc_errors::registry::Registry,
|
||||
output: ErrorOutputType,
|
||||
) -> Compilation {
|
||||
self.default.early_callback(
|
||||
matches,
|
||||
sopts,
|
||||
cfg,
|
||||
descriptions,
|
||||
output,
|
||||
)
|
||||
}
|
||||
fn no_input(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sopts: &config::Options,
|
||||
cfg: &ast::CrateConfig,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
descriptions: &rustc_errors::registry::Registry,
|
||||
) -> Option<(Input, Option<PathBuf>)> {
|
||||
self.default.no_input(
|
||||
matches,
|
||||
sopts,
|
||||
cfg,
|
||||
odir,
|
||||
ofile,
|
||||
descriptions,
|
||||
)
|
||||
}
|
||||
fn late_callback(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sess: &Session,
|
||||
cstore: &CrateStore,
|
||||
input: &Input,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
) -> Compilation {
|
||||
self.default.late_callback(matches, sess, cstore, input, odir, ofile)
|
||||
}
|
||||
fn build_controller(
|
||||
&mut self,
|
||||
sess: &Session,
|
||||
matches: &getopts::Matches,
|
||||
) -> CompileController<'a> {
|
||||
let mut control = self.default.build_controller(sess, matches);
|
||||
control.after_hir_lowering.callback = Box::new(after_hir_lowering);
|
||||
control.after_analysis.callback = Box::new(after_analysis);
|
||||
if sess.target.target != sess.host {
|
||||
// only fully compile targets on the host. linking will fail for cross-compilation.
|
||||
control.after_analysis.stop = Compilation::Stop;
|
||||
}
|
||||
control
|
||||
}
|
||||
}
|
||||
|
||||
fn after_hir_lowering(state: &mut CompileState) {
|
||||
let attr = (
|
||||
String::from("miri"),
|
||||
syntax::feature_gate::AttributeType::Whitelisted,
|
||||
);
|
||||
state.session.plugin_attributes.borrow_mut().push(attr);
|
||||
}
|
||||
|
||||
fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
|
||||
state.session.abort_if_errors();
|
||||
|
||||
let tcx = state.tcx.unwrap();
|
||||
let limits = resource_limits_from_attributes(state);
|
||||
|
||||
if std::env::args().any(|arg| arg == "--test") {
|
||||
struct Visitor<'a, 'tcx: 'a>(
|
||||
miri::ResourceLimits,
|
||||
TyCtxt<'a, 'tcx, 'tcx>,
|
||||
&'a CompileState<'a, 'tcx>
|
||||
);
|
||||
impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
|
||||
fn visit_item(&mut self, i: &'hir hir::Item) {
|
||||
if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node {
|
||||
if i.attrs.iter().any(|attr| {
|
||||
attr.name().map_or(false, |n| n == "test")
|
||||
})
|
||||
{
|
||||
let did = self.1.hir.body_owner_def_id(body_id);
|
||||
println!(
|
||||
"running test: {}",
|
||||
self.1.hir.def_path(did).to_string(self.1)
|
||||
);
|
||||
miri::eval_main(self.1, did, None, self.0);
|
||||
self.2.session.abort_if_errors();
|
||||
}
|
||||
}
|
||||
}
|
||||
fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
|
||||
fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
|
||||
}
|
||||
state.hir_crate.unwrap().visit_all_item_likes(
|
||||
&mut Visitor(limits, tcx, state),
|
||||
);
|
||||
} else if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
|
||||
let entry_def_id = tcx.hir.local_def_id(entry_node_id);
|
||||
let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| {
|
||||
if tcx.is_mir_available(start_fn) {
|
||||
Some(start_fn)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
miri::eval_main(tcx, entry_def_id, start_wrapper, limits);
|
||||
|
||||
state.session.abort_if_errors();
|
||||
} else {
|
||||
println!("no main function found, assuming auxiliary build");
|
||||
}
|
||||
}
|
||||
|
||||
fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits {
|
||||
let mut limits = miri::ResourceLimits::default();
|
||||
let krate = state.hir_crate.as_ref().unwrap();
|
||||
let err_msg = "miri attributes need to be in the form `miri(key = value)`";
|
||||
let extract_int = |lit: &syntax::ast::Lit| -> u128 {
|
||||
match lit.node {
|
||||
syntax::ast::LitKind::Int(i, _) => i,
|
||||
_ => {
|
||||
state.session.span_fatal(
|
||||
lit.span,
|
||||
"expected an integer literal",
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for attr in krate.attrs.iter().filter(|a| {
|
||||
a.name().map_or(false, |n| n == "miri")
|
||||
})
|
||||
{
|
||||
if let Some(items) = attr.meta_item_list() {
|
||||
for item in items {
|
||||
if let NestedMetaItemKind::MetaItem(ref inner) = item.node {
|
||||
if let MetaItemKind::NameValue(ref value) = inner.node {
|
||||
match &inner.name().as_str()[..] {
|
||||
"memory_size" => limits.memory_size = extract_int(value) as u64,
|
||||
"step_limit" => limits.step_limit = extract_int(value) as u64,
|
||||
"stack_limit" => limits.stack_limit = extract_int(value) as usize,
|
||||
_ => state.session.span_err(item.span, "unknown miri attribute"),
|
||||
}
|
||||
} else {
|
||||
state.session.span_err(inner.span, err_msg);
|
||||
}
|
||||
} else {
|
||||
state.session.span_err(item.span, err_msg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
state.session.span_err(attr.span, err_msg);
|
||||
}
|
||||
}
|
||||
limits
|
||||
}
|
||||
|
||||
fn init_logger() {
|
||||
let format = |record: &log::LogRecord| {
|
||||
if record.level() == log::LogLevel::Trace {
|
||||
// prepend spaces to indent the final string
|
||||
let indentation = log_settings::settings().indentation;
|
||||
format!(
|
||||
"{lvl}:{module}:{indent:<indentation$} {text}",
|
||||
lvl = record.level(),
|
||||
module = record.location().module_path(),
|
||||
indentation = indentation,
|
||||
indent = "",
|
||||
text = record.args(),
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"{lvl}:{module}: {text}",
|
||||
lvl = record.level(),
|
||||
module = record.location().module_path(),
|
||||
text = record.args(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let mut builder = env_logger::LogBuilder::new();
|
||||
builder.format(format).filter(
|
||||
None,
|
||||
log::LogLevelFilter::Info,
|
||||
);
|
||||
|
||||
if std::env::var("MIRI_LOG").is_ok() {
|
||||
builder.parse(&std::env::var("MIRI_LOG").unwrap());
|
||||
}
|
||||
|
||||
builder.init().unwrap();
|
||||
}
|
||||
|
||||
fn find_sysroot() -> String {
|
||||
if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
|
||||
return sysroot;
|
||||
}
|
||||
|
||||
// Taken from https://github.com/Manishearth/rust-clippy/pull/911.
|
||||
let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
|
||||
let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
|
||||
match (home, toolchain) {
|
||||
(Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
|
||||
_ => {
|
||||
option_env!("RUST_SYSROOT")
|
||||
.expect(
|
||||
"need to specify RUST_SYSROOT env var or use rustup or multirust",
|
||||
)
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
init_logger();
|
||||
let mut args: Vec<String> = std::env::args().collect();
|
||||
|
||||
let sysroot_flag = String::from("--sysroot");
|
||||
if !args.contains(&sysroot_flag) {
|
||||
args.push(sysroot_flag);
|
||||
args.push(find_sysroot());
|
||||
}
|
||||
|
||||
// Make sure we always have all the MIR (e.g. for auxilary builds in unit tests).
|
||||
args.push("-Zalways-encode-mir".to_owned());
|
||||
|
||||
rustc_driver::run_compiler(&args, &mut MiriCompilerCalls {
|
||||
default: RustcDefaultCalls,
|
||||
}, None, None);
|
||||
}
|
||||
656
miri/fn_call.rs
656
miri/fn_call.rs
|
|
@ -1,656 +0,0 @@
|
|||
use rustc::ty::{self, Ty};
|
||||
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
use rustc::mir;
|
||||
use syntax::attr;
|
||||
use syntax::abi::Abi;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use std::mem;
|
||||
|
||||
use rustc_miri::interpret::*;
|
||||
|
||||
use super::{TlsKey, EvalContext};
|
||||
|
||||
use tls::MemoryExt;
|
||||
|
||||
use super::memory::MemoryKind;
|
||||
|
||||
pub trait EvalContextExt<'tcx> {
|
||||
fn call_c_abi(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
args: &[ValTy<'tcx>],
|
||||
dest: Lvalue,
|
||||
dest_ty: Ty<'tcx>,
|
||||
dest_block: mir::BasicBlock,
|
||||
) -> EvalResult<'tcx>;
|
||||
|
||||
fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>;
|
||||
|
||||
fn call_missing_fn(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||
args: &[ValTy<'tcx>],
|
||||
sig: ty::FnSig<'tcx>,
|
||||
path: String,
|
||||
) -> EvalResult<'tcx>;
|
||||
|
||||
fn eval_fn_call(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||
args: &[ValTy<'tcx>],
|
||||
span: Span,
|
||||
sig: ty::FnSig<'tcx>,
|
||||
) -> EvalResult<'tcx, bool>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> {
|
||||
fn eval_fn_call(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||
args: &[ValTy<'tcx>],
|
||||
span: Span,
|
||||
sig: ty::FnSig<'tcx>,
|
||||
) -> EvalResult<'tcx, bool> {
|
||||
trace!("eval_fn_call: {:#?}, {:#?}", instance, destination);
|
||||
|
||||
let mir = match self.load_mir(instance.def) {
|
||||
Ok(mir) => mir,
|
||||
Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => {
|
||||
self.call_missing_fn(
|
||||
instance,
|
||||
destination,
|
||||
args,
|
||||
sig,
|
||||
path,
|
||||
)?;
|
||||
return Ok(true);
|
||||
}
|
||||
Err(other) => return Err(other),
|
||||
};
|
||||
|
||||
let (return_lvalue, return_to_block) = match destination {
|
||||
Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)),
|
||||
None => (Lvalue::undef(), StackPopCleanup::None),
|
||||
};
|
||||
|
||||
self.push_stack_frame(
|
||||
instance,
|
||||
span,
|
||||
mir,
|
||||
return_lvalue,
|
||||
return_to_block,
|
||||
)?;
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn call_c_abi(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
args: &[ValTy<'tcx>],
|
||||
dest: Lvalue,
|
||||
dest_ty: Ty<'tcx>,
|
||||
dest_block: mir::BasicBlock,
|
||||
) -> EvalResult<'tcx> {
|
||||
let attrs = self.tcx.get_attrs(def_id);
|
||||
let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
|
||||
Some(name) => name.as_str(),
|
||||
None => self.tcx.item_name(def_id),
|
||||
};
|
||||
|
||||
match &link_name[..] {
|
||||
"malloc" => {
|
||||
let size = self.value_to_primval(args[0])?.to_u64()?;
|
||||
if size == 0 {
|
||||
self.write_null(dest, dest_ty)?;
|
||||
} else {
|
||||
let align = self.memory.pointer_size();
|
||||
let ptr = self.memory.allocate(size, align, MemoryKind::C.into())?;
|
||||
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
|
||||
}
|
||||
}
|
||||
|
||||
"free" => {
|
||||
let ptr = args[0].into_ptr(&mut self.memory)?;
|
||||
if !ptr.is_null()? {
|
||||
self.memory.deallocate(
|
||||
ptr.to_ptr()?,
|
||||
None,
|
||||
MemoryKind::C.into(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
"syscall" => {
|
||||
// TODO: read `syscall` ids like `sysconf` ids and
|
||||
// figure out some way to actually process some of them
|
||||
//
|
||||
// libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)
|
||||
// is called if a `HashMap` is created the regular way.
|
||||
match self.value_to_primval(args[0])?.to_u64()? {
|
||||
318 | 511 => {
|
||||
return err!(Unimplemented(
|
||||
"miri does not support random number generators".to_owned(),
|
||||
))
|
||||
}
|
||||
id => {
|
||||
return err!(Unimplemented(
|
||||
format!("miri does not support syscall id {}", id),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"dlsym" => {
|
||||
let _handle = args[0].into_ptr(&mut self.memory)?;
|
||||
let symbol = args[1].into_ptr(&mut self.memory)?.to_ptr()?;
|
||||
let symbol_name = self.memory.read_c_str(symbol)?;
|
||||
let err = format!("bad c unicode symbol: {:?}", symbol_name);
|
||||
let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
|
||||
return err!(Unimplemented(format!(
|
||||
"miri does not support dynamically loading libraries (requested symbol: {})",
|
||||
symbol_name
|
||||
)));
|
||||
}
|
||||
|
||||
"__rust_maybe_catch_panic" => {
|
||||
// fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32
|
||||
// We abort on panic, so not much is going on here, but we still have to call the closure
|
||||
let u8_ptr_ty = self.tcx.mk_mut_ptr(self.tcx.types.u8);
|
||||
let f = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
|
||||
let data = args[1].into_ptr(&mut self.memory)?;
|
||||
let f_instance = self.memory.get_fn(f)?;
|
||||
self.write_null(dest, dest_ty)?;
|
||||
|
||||
// Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors,
|
||||
// and of course eval_main.
|
||||
let mir = self.load_mir(f_instance.def)?;
|
||||
self.push_stack_frame(
|
||||
f_instance,
|
||||
mir.span,
|
||||
mir,
|
||||
Lvalue::undef(),
|
||||
StackPopCleanup::Goto(dest_block),
|
||||
)?;
|
||||
let mut args = self.frame().mir.args_iter();
|
||||
|
||||
let arg_local = args.next().ok_or(
|
||||
EvalErrorKind::AbiViolation(
|
||||
"Argument to __rust_maybe_catch_panic does not take enough arguments."
|
||||
.to_owned(),
|
||||
),
|
||||
)?;
|
||||
let arg_dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
|
||||
self.write_ptr(arg_dest, data, u8_ptr_ty)?;
|
||||
|
||||
assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected");
|
||||
|
||||
// We ourselves return 0
|
||||
self.write_null(dest, dest_ty)?;
|
||||
|
||||
// Don't fall through
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
"__rust_start_panic" => {
|
||||
return err!(Panic);
|
||||
}
|
||||
|
||||
"memcmp" => {
|
||||
let left = args[0].into_ptr(&mut self.memory)?;
|
||||
let right = args[1].into_ptr(&mut self.memory)?;
|
||||
let n = self.value_to_primval(args[2])?.to_u64()?;
|
||||
|
||||
let result = {
|
||||
let left_bytes = self.memory.read_bytes(left, n)?;
|
||||
let right_bytes = self.memory.read_bytes(right, n)?;
|
||||
|
||||
use std::cmp::Ordering::*;
|
||||
match left_bytes.cmp(right_bytes) {
|
||||
Less => -1i8,
|
||||
Equal => 0,
|
||||
Greater => 1,
|
||||
}
|
||||
};
|
||||
|
||||
self.write_primval(
|
||||
dest,
|
||||
PrimVal::Bytes(result as u128),
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"memrchr" => {
|
||||
let ptr = args[0].into_ptr(&mut self.memory)?;
|
||||
let val = self.value_to_primval(args[1])?.to_u64()? as u8;
|
||||
let num = self.value_to_primval(args[2])?.to_u64()?;
|
||||
if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(
|
||||
|&c| c == val,
|
||||
)
|
||||
{
|
||||
let new_ptr = ptr.offset(num - idx as u64 - 1, &self)?;
|
||||
self.write_ptr(dest, new_ptr, dest_ty)?;
|
||||
} else {
|
||||
self.write_null(dest, dest_ty)?;
|
||||
}
|
||||
}
|
||||
|
||||
"memchr" => {
|
||||
let ptr = args[0].into_ptr(&mut self.memory)?;
|
||||
let val = self.value_to_primval(args[1])?.to_u64()? as u8;
|
||||
let num = self.value_to_primval(args[2])?.to_u64()?;
|
||||
if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(
|
||||
|&c| c == val,
|
||||
)
|
||||
{
|
||||
let new_ptr = ptr.offset(idx as u64, &self)?;
|
||||
self.write_ptr(dest, new_ptr, dest_ty)?;
|
||||
} else {
|
||||
self.write_null(dest, dest_ty)?;
|
||||
}
|
||||
}
|
||||
|
||||
"getenv" => {
|
||||
let result = {
|
||||
let name_ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
|
||||
let name = self.memory.read_c_str(name_ptr)?;
|
||||
match self.machine_data.env_vars.get(name) {
|
||||
Some(&var) => PrimVal::Ptr(var),
|
||||
None => PrimVal::Bytes(0),
|
||||
}
|
||||
};
|
||||
self.write_primval(dest, result, dest_ty)?;
|
||||
}
|
||||
|
||||
"unsetenv" => {
|
||||
let mut success = None;
|
||||
{
|
||||
let name_ptr = args[0].into_ptr(&mut self.memory)?;
|
||||
if !name_ptr.is_null()? {
|
||||
let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
|
||||
if !name.is_empty() && !name.contains(&b'=') {
|
||||
success = Some(self.machine_data.env_vars.remove(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(old) = success {
|
||||
if let Some(var) = old {
|
||||
self.memory.deallocate(var, None, MemoryKind::Env.into())?;
|
||||
}
|
||||
self.write_null(dest, dest_ty)?;
|
||||
} else {
|
||||
self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?;
|
||||
}
|
||||
}
|
||||
|
||||
"setenv" => {
|
||||
let mut new = None;
|
||||
{
|
||||
let name_ptr = args[0].into_ptr(&mut self.memory)?;
|
||||
let value_ptr = args[1].into_ptr(&mut self.memory)?.to_ptr()?;
|
||||
let value = self.memory.read_c_str(value_ptr)?;
|
||||
if !name_ptr.is_null()? {
|
||||
let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
|
||||
if !name.is_empty() && !name.contains(&b'=') {
|
||||
new = Some((name.to_owned(), value.to_owned()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some((name, value)) = new {
|
||||
// +1 for the null terminator
|
||||
let value_copy = self.memory.allocate(
|
||||
(value.len() + 1) as u64,
|
||||
1,
|
||||
MemoryKind::Env.into(),
|
||||
)?;
|
||||
self.memory.write_bytes(value_copy.into(), &value)?;
|
||||
let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into();
|
||||
self.memory.write_bytes(trailing_zero_ptr, &[0])?;
|
||||
if let Some(var) = self.machine_data.env_vars.insert(
|
||||
name.to_owned(),
|
||||
value_copy,
|
||||
)
|
||||
{
|
||||
self.memory.deallocate(var, None, MemoryKind::Env.into())?;
|
||||
}
|
||||
self.write_null(dest, dest_ty)?;
|
||||
} else {
|
||||
self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?;
|
||||
}
|
||||
}
|
||||
|
||||
"write" => {
|
||||
let fd = self.value_to_primval(args[0])?.to_u64()?;
|
||||
let buf = args[1].into_ptr(&mut self.memory)?;
|
||||
let n = self.value_to_primval(args[2])?.to_u64()?;
|
||||
trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
|
||||
let result = if fd == 1 || fd == 2 {
|
||||
// stdout/stderr
|
||||
use std::io::{self, Write};
|
||||
|
||||
let buf_cont = self.memory.read_bytes(buf, n)?;
|
||||
let res = if fd == 1 {
|
||||
io::stdout().write(buf_cont)
|
||||
} else {
|
||||
io::stderr().write(buf_cont)
|
||||
};
|
||||
match res {
|
||||
Ok(n) => n as isize,
|
||||
Err(_) => -1,
|
||||
}
|
||||
} else {
|
||||
warn!("Ignored output to FD {}", fd);
|
||||
n as isize // pretend it all went well
|
||||
}; // now result is the value we return back to the program
|
||||
self.write_primval(
|
||||
dest,
|
||||
PrimVal::Bytes(result as u128),
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"strlen" => {
|
||||
let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
|
||||
let n = self.memory.read_c_str(ptr)?.len();
|
||||
self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?;
|
||||
}
|
||||
|
||||
// Some things needed for sys::thread initialization to go through
|
||||
"signal" | "sigaction" | "sigaltstack" => {
|
||||
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
|
||||
}
|
||||
|
||||
"sysconf" => {
|
||||
let name = self.value_to_primval(args[0])?.to_u64()?;
|
||||
trace!("sysconf() called with name {}", name);
|
||||
// cache the sysconf integers via miri's global cache
|
||||
let paths = &[
|
||||
(&["libc", "_SC_PAGESIZE"], PrimVal::Bytes(4096)),
|
||||
(&["libc", "_SC_GETPW_R_SIZE_MAX"], PrimVal::from_i128(-1)),
|
||||
];
|
||||
let mut result = None;
|
||||
for &(path, path_value) in paths {
|
||||
if let Ok(instance) = self.resolve_path(path) {
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None,
|
||||
};
|
||||
// compute global if not cached
|
||||
let val = match self.globals.get(&cid).cloned() {
|
||||
Some(ptr) => self.value_to_primval(ValTy { value: Value::ByRef(ptr), ty: args[0].ty })?.to_u64()?,
|
||||
None => eval_body_as_primval(self.tcx, instance)?.0.to_u64()?,
|
||||
};
|
||||
if val == name {
|
||||
result = Some(path_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(result) = result {
|
||||
self.write_primval(dest, result, dest_ty)?;
|
||||
} else {
|
||||
return err!(Unimplemented(
|
||||
format!("Unimplemented sysconf name: {}", name),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Hook pthread calls that go to the thread-local storage memory subsystem
|
||||
"pthread_key_create" => {
|
||||
let key_ptr = args[0].into_ptr(&mut self.memory)?;
|
||||
|
||||
// Extract the function type out of the signature (that seems easier than constructing it ourselves...)
|
||||
let dtor = match args[1].into_ptr(&mut self.memory)?.into_inner_primval() {
|
||||
PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?),
|
||||
PrimVal::Bytes(0) => None,
|
||||
PrimVal::Bytes(_) => return err!(ReadBytesAsPointer),
|
||||
PrimVal::Undef => return err!(ReadUndefBytes),
|
||||
};
|
||||
|
||||
// Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t.
|
||||
let key_type = args[0].ty.builtin_deref(true, ty::LvaluePreference::NoPreference)
|
||||
.ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty;
|
||||
let key_size = {
|
||||
let layout = self.type_layout(key_type)?;
|
||||
layout.size(&self.tcx.data_layout)
|
||||
};
|
||||
|
||||
// Create key and write it into the memory where key_ptr wants it
|
||||
let key = self.memory.create_tls_key(dtor) as u128;
|
||||
if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) {
|
||||
return err!(OutOfTls);
|
||||
}
|
||||
self.memory.write_primval(
|
||||
key_ptr.to_ptr()?,
|
||||
PrimVal::Bytes(key),
|
||||
key_size.bytes(),
|
||||
false,
|
||||
)?;
|
||||
|
||||
// Return success (0)
|
||||
self.write_null(dest, dest_ty)?;
|
||||
}
|
||||
"pthread_key_delete" => {
|
||||
// The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
|
||||
let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey;
|
||||
self.memory.delete_tls_key(key)?;
|
||||
// Return success (0)
|
||||
self.write_null(dest, dest_ty)?;
|
||||
}
|
||||
"pthread_getspecific" => {
|
||||
// The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
|
||||
let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey;
|
||||
let ptr = self.memory.load_tls(key)?;
|
||||
self.write_ptr(dest, ptr, dest_ty)?;
|
||||
}
|
||||
"pthread_setspecific" => {
|
||||
// The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
|
||||
let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey;
|
||||
let new_ptr = args[1].into_ptr(&mut self.memory)?;
|
||||
self.memory.store_tls(key, new_ptr)?;
|
||||
|
||||
// Return success (0)
|
||||
self.write_null(dest, dest_ty)?;
|
||||
}
|
||||
|
||||
// Stub out all the other pthread calls to just return 0
|
||||
link_name if link_name.starts_with("pthread_") => {
|
||||
info!("ignoring C ABI call: {}", link_name);
|
||||
self.write_null(dest, dest_ty)?;
|
||||
}
|
||||
|
||||
_ => {
|
||||
return err!(Unimplemented(
|
||||
format!("can't call C ABI function: {}", link_name),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Since we pushed no stack frame, the main loop will act
|
||||
// as if the call just completed and it's returning to the
|
||||
// current frame.
|
||||
self.dump_local(dest);
|
||||
self.goto_block(dest_block);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get an instance for a path.
|
||||
fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> {
|
||||
self.tcx
|
||||
.crates()
|
||||
.iter()
|
||||
.find(|&&krate| self.tcx.original_crate_name(krate) == path[0])
|
||||
.and_then(|krate| {
|
||||
let krate = DefId {
|
||||
krate: *krate,
|
||||
index: CRATE_DEF_INDEX,
|
||||
};
|
||||
let mut items = self.tcx.item_children(krate);
|
||||
let mut path_it = path.iter().skip(1).peekable();
|
||||
|
||||
while let Some(segment) = path_it.next() {
|
||||
for item in mem::replace(&mut items, Default::default()).iter() {
|
||||
if item.ident.name == *segment {
|
||||
if path_it.peek().is_none() {
|
||||
return Some(ty::Instance::mono(self.tcx, item.def.def_id()));
|
||||
}
|
||||
|
||||
items = self.tcx.item_children(item.def.def_id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
let path = path.iter().map(|&s| s.to_owned()).collect();
|
||||
EvalErrorKind::PathNotFound(path).into()
|
||||
})
|
||||
}
|
||||
|
||||
fn call_missing_fn(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||
args: &[ValTy<'tcx>],
|
||||
sig: ty::FnSig<'tcx>,
|
||||
path: String,
|
||||
) -> EvalResult<'tcx> {
|
||||
// In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early.
|
||||
match &path[..] {
|
||||
"std::panicking::rust_panic_with_hook" |
|
||||
"core::panicking::panic_fmt::::panic_impl" |
|
||||
"std::rt::begin_panic_fmt" => return err!(Panic),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let dest_ty = sig.output();
|
||||
let (dest, dest_block) = destination.ok_or_else(
|
||||
|| EvalErrorKind::NoMirFor(path.clone()),
|
||||
)?;
|
||||
|
||||
if sig.abi == Abi::C {
|
||||
// An external C function
|
||||
// TODO: That functions actually has a similar preamble to what follows here. May make sense to
|
||||
// unify these two mechanisms for "hooking into missing functions".
|
||||
self.call_c_abi(
|
||||
instance.def_id(),
|
||||
args,
|
||||
dest,
|
||||
dest_ty,
|
||||
dest_block,
|
||||
)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match &path[..] {
|
||||
// Allocators are magic. They have no MIR, even when the rest of libstd does.
|
||||
"alloc::heap::::__rust_alloc" => {
|
||||
let size = self.value_to_primval(args[0])?.to_u64()?;
|
||||
let align = self.value_to_primval(args[1])?.to_u64()?;
|
||||
if size == 0 {
|
||||
return err!(HeapAllocZeroBytes);
|
||||
}
|
||||
if !align.is_power_of_two() {
|
||||
return err!(HeapAllocNonPowerOfTwoAlignment(align));
|
||||
}
|
||||
let ptr = self.memory.allocate(size, align, MemoryKind::Rust.into())?;
|
||||
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
|
||||
}
|
||||
"alloc::heap::::__rust_alloc_zeroed" => {
|
||||
let size = self.value_to_primval(args[0])?.to_u64()?;
|
||||
let align = self.value_to_primval(args[1])?.to_u64()?;
|
||||
if size == 0 {
|
||||
return err!(HeapAllocZeroBytes);
|
||||
}
|
||||
if !align.is_power_of_two() {
|
||||
return err!(HeapAllocNonPowerOfTwoAlignment(align));
|
||||
}
|
||||
let ptr = self.memory.allocate(size, align, MemoryKind::Rust.into())?;
|
||||
self.memory.write_repeat(ptr.into(), 0, size)?;
|
||||
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
|
||||
}
|
||||
"alloc::heap::::__rust_dealloc" => {
|
||||
let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
|
||||
let old_size = self.value_to_primval(args[1])?.to_u64()?;
|
||||
let align = self.value_to_primval(args[2])?.to_u64()?;
|
||||
if old_size == 0 {
|
||||
return err!(HeapAllocZeroBytes);
|
||||
}
|
||||
if !align.is_power_of_two() {
|
||||
return err!(HeapAllocNonPowerOfTwoAlignment(align));
|
||||
}
|
||||
self.memory.deallocate(
|
||||
ptr,
|
||||
Some((old_size, align)),
|
||||
MemoryKind::Rust.into(),
|
||||
)?;
|
||||
}
|
||||
"alloc::heap::::__rust_realloc" => {
|
||||
let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
|
||||
let old_size = self.value_to_primval(args[1])?.to_u64()?;
|
||||
let old_align = self.value_to_primval(args[2])?.to_u64()?;
|
||||
let new_size = self.value_to_primval(args[3])?.to_u64()?;
|
||||
let new_align = self.value_to_primval(args[4])?.to_u64()?;
|
||||
if old_size == 0 || new_size == 0 {
|
||||
return err!(HeapAllocZeroBytes);
|
||||
}
|
||||
if !old_align.is_power_of_two() {
|
||||
return err!(HeapAllocNonPowerOfTwoAlignment(old_align));
|
||||
}
|
||||
if !new_align.is_power_of_two() {
|
||||
return err!(HeapAllocNonPowerOfTwoAlignment(new_align));
|
||||
}
|
||||
let new_ptr = self.memory.reallocate(
|
||||
ptr,
|
||||
old_size,
|
||||
old_align,
|
||||
new_size,
|
||||
new_align,
|
||||
MemoryKind::Rust.into(),
|
||||
)?;
|
||||
self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
|
||||
}
|
||||
|
||||
// A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies).
|
||||
// Still, we can make many things mostly work by "emulating" or ignoring some functions.
|
||||
"std::io::_print" => {
|
||||
warn!(
|
||||
"Ignoring output. To run programs that print, make sure you have a libstd with full MIR."
|
||||
);
|
||||
}
|
||||
"std::thread::Builder::new" => {
|
||||
return err!(Unimplemented("miri does not support threading".to_owned()))
|
||||
}
|
||||
"std::env::args" => {
|
||||
return err!(Unimplemented(
|
||||
"miri does not support program arguments".to_owned(),
|
||||
))
|
||||
}
|
||||
"std::panicking::panicking" |
|
||||
"std::rt::panicking" => {
|
||||
// we abort on panic -> `std::rt::panicking` always returns false
|
||||
let bool = self.tcx.types.bool;
|
||||
self.write_primval(dest, PrimVal::from_bool(false), bool)?;
|
||||
}
|
||||
"std::sys::imp::c::::AddVectoredExceptionHandler" |
|
||||
"std::sys::imp::c::::SetThreadStackGuarantee" => {
|
||||
let usize = self.tcx.types.usize;
|
||||
// any non zero value works for the stdlib. This is just used for stackoverflows anyway
|
||||
self.write_primval(dest, PrimVal::Bytes(1), usize)?;
|
||||
},
|
||||
_ => return err!(NoMirFor(path)),
|
||||
}
|
||||
|
||||
// Since we pushed no stack frame, the main loop will act
|
||||
// as if the call just completed and it's returning to the
|
||||
// current frame.
|
||||
self.dump_local(dest);
|
||||
self.goto_block(dest_block);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
use rustc_miri::interpret::{Pointer, EvalResult, PrimVal, EvalContext};
|
||||
|
||||
use rustc::ty::Ty;
|
||||
|
||||
pub trait EvalContextExt<'tcx> {
|
||||
fn wrapping_pointer_offset(
|
||||
&self,
|
||||
ptr: Pointer,
|
||||
pointee_ty: Ty<'tcx>,
|
||||
offset: i64,
|
||||
) -> EvalResult<'tcx, Pointer>;
|
||||
|
||||
fn pointer_offset(
|
||||
&self,
|
||||
ptr: Pointer,
|
||||
pointee_ty: Ty<'tcx>,
|
||||
offset: i64,
|
||||
) -> EvalResult<'tcx, Pointer>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> {
|
||||
fn wrapping_pointer_offset(
|
||||
&self,
|
||||
ptr: Pointer,
|
||||
pointee_ty: Ty<'tcx>,
|
||||
offset: i64,
|
||||
) -> EvalResult<'tcx, Pointer> {
|
||||
// FIXME: assuming here that type size is < i64::max_value()
|
||||
let pointee_size = self.type_size(pointee_ty)?.expect(
|
||||
"cannot offset a pointer to an unsized type",
|
||||
) as i64;
|
||||
let offset = offset.overflowing_mul(pointee_size).0;
|
||||
ptr.wrapping_signed_offset(offset, self)
|
||||
}
|
||||
|
||||
fn pointer_offset(
|
||||
&self,
|
||||
ptr: Pointer,
|
||||
pointee_ty: Ty<'tcx>,
|
||||
offset: i64,
|
||||
) -> EvalResult<'tcx, Pointer> {
|
||||
// This function raises an error if the offset moves the pointer outside of its allocation. We consider
|
||||
// ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0).
|
||||
// We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own
|
||||
// allocation.
|
||||
|
||||
if ptr.is_null()? {
|
||||
// NULL pointers must only be offset by 0
|
||||
return if offset == 0 {
|
||||
Ok(ptr)
|
||||
} else {
|
||||
err!(InvalidNullPointerUsage)
|
||||
};
|
||||
}
|
||||
// FIXME: assuming here that type size is < i64::max_value()
|
||||
let pointee_size = self.type_size(pointee_ty)?.expect(
|
||||
"cannot offset a pointer to an unsized type",
|
||||
) as i64;
|
||||
return if let Some(offset) = offset.checked_mul(pointee_size) {
|
||||
let ptr = ptr.signed_offset(offset, self)?;
|
||||
// Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
|
||||
if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() {
|
||||
self.memory.check_bounds(ptr, false)?;
|
||||
} else if ptr.is_null()? {
|
||||
// We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now.
|
||||
return err!(InvalidNullPointerUsage);
|
||||
}
|
||||
Ok(ptr)
|
||||
} else {
|
||||
err!(OverflowingMath)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,685 +0,0 @@
|
|||
use rustc::mir;
|
||||
use rustc::traits::Reveal;
|
||||
use rustc::ty::layout::Layout;
|
||||
use rustc::ty::{self, Ty};
|
||||
|
||||
use rustc_miri::interpret::{EvalResult, Lvalue, LvalueExtra, PrimVal, PrimValKind, Value, Pointer,
|
||||
HasMemory, AccessKind, EvalContext, PtrAndAlign, ValTy};
|
||||
|
||||
use helpers::EvalContextExt as HelperEvalContextExt;
|
||||
|
||||
pub trait EvalContextExt<'tcx> {
|
||||
fn call_intrinsic(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[ValTy<'tcx>],
|
||||
dest: Lvalue,
|
||||
dest_ty: Ty<'tcx>,
|
||||
dest_layout: &'tcx Layout,
|
||||
target: mir::BasicBlock,
|
||||
) -> EvalResult<'tcx>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> {
|
||||
fn call_intrinsic(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[ValTy<'tcx>],
|
||||
dest: Lvalue,
|
||||
dest_ty: Ty<'tcx>,
|
||||
dest_layout: &'tcx Layout,
|
||||
target: mir::BasicBlock,
|
||||
) -> EvalResult<'tcx> {
|
||||
let substs = instance.substs;
|
||||
|
||||
let intrinsic_name = &self.tcx.item_name(instance.def_id())[..];
|
||||
match intrinsic_name {
|
||||
"align_offset" => {
|
||||
// FIXME: return a real value in case the target allocation has an
|
||||
// alignment bigger than the one requested
|
||||
self.write_primval(dest, PrimVal::Bytes(u128::max_value()), dest_ty)?;
|
||||
},
|
||||
|
||||
"add_with_overflow" => {
|
||||
self.intrinsic_with_overflow(
|
||||
mir::BinOp::Add,
|
||||
args[0],
|
||||
args[1],
|
||||
dest,
|
||||
dest_ty,
|
||||
)?
|
||||
}
|
||||
|
||||
"sub_with_overflow" => {
|
||||
self.intrinsic_with_overflow(
|
||||
mir::BinOp::Sub,
|
||||
args[0],
|
||||
args[1],
|
||||
dest,
|
||||
dest_ty,
|
||||
)?
|
||||
}
|
||||
|
||||
"mul_with_overflow" => {
|
||||
self.intrinsic_with_overflow(
|
||||
mir::BinOp::Mul,
|
||||
args[0],
|
||||
args[1],
|
||||
dest,
|
||||
dest_ty,
|
||||
)?
|
||||
}
|
||||
|
||||
"arith_offset" => {
|
||||
let offset = self.value_to_primval(args[1])?.to_i128()? as i64;
|
||||
let ptr = args[0].into_ptr(&self.memory)?;
|
||||
let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?;
|
||||
self.write_ptr(dest, result_ptr, dest_ty)?;
|
||||
}
|
||||
|
||||
"assume" => {
|
||||
let cond = self.value_to_primval(args[0])?.to_bool()?;
|
||||
if !cond {
|
||||
return err!(AssumptionNotHeld);
|
||||
}
|
||||
}
|
||||
|
||||
"atomic_load" |
|
||||
"atomic_load_relaxed" |
|
||||
"atomic_load_acq" |
|
||||
"volatile_load" => {
|
||||
let ptr = args[0].into_ptr(&self.memory)?;
|
||||
let valty = ValTy {
|
||||
value: Value::by_ref(ptr),
|
||||
ty: substs.type_at(0),
|
||||
};
|
||||
self.write_value(valty, dest)?;
|
||||
}
|
||||
|
||||
"atomic_store" |
|
||||
"atomic_store_relaxed" |
|
||||
"atomic_store_rel" |
|
||||
"volatile_store" => {
|
||||
let ty = substs.type_at(0);
|
||||
let dest = args[0].into_ptr(&self.memory)?;
|
||||
self.write_value_to_ptr(args[1].value, dest, ty)?;
|
||||
}
|
||||
|
||||
"atomic_fence_acq" => {
|
||||
// we are inherently singlethreaded and singlecored, this is a nop
|
||||
}
|
||||
|
||||
_ if intrinsic_name.starts_with("atomic_xchg") => {
|
||||
let ty = substs.type_at(0);
|
||||
let ptr = args[0].into_ptr(&self.memory)?;
|
||||
let change = self.value_to_primval(args[1])?;
|
||||
let old = self.read_value(ptr, ty)?;
|
||||
let old = match old {
|
||||
Value::ByVal(val) => val,
|
||||
Value::ByRef { .. } => bug!("just read the value, can't be byref"),
|
||||
Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"),
|
||||
};
|
||||
self.write_primval(dest, old, ty)?;
|
||||
self.write_primval(
|
||||
Lvalue::from_primval_ptr(ptr),
|
||||
change,
|
||||
ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
_ if intrinsic_name.starts_with("atomic_cxchg") => {
|
||||
let ty = substs.type_at(0);
|
||||
let ptr = args[0].into_ptr(&self.memory)?;
|
||||
let expect_old = self.value_to_primval(args[1])?;
|
||||
let change = self.value_to_primval(args[2])?;
|
||||
let old = self.read_value(ptr, ty)?;
|
||||
let old = match old {
|
||||
Value::ByVal(val) => val,
|
||||
Value::ByRef { .. } => bug!("just read the value, can't be byref"),
|
||||
Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"),
|
||||
};
|
||||
let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?;
|
||||
let dest = self.force_allocation(dest)?.to_ptr()?;
|
||||
self.write_pair_to_ptr(old, val, dest, dest_ty)?;
|
||||
self.write_primval(
|
||||
Lvalue::from_primval_ptr(ptr),
|
||||
change,
|
||||
ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"atomic_or" |
|
||||
"atomic_or_acq" |
|
||||
"atomic_or_rel" |
|
||||
"atomic_or_acqrel" |
|
||||
"atomic_or_relaxed" |
|
||||
"atomic_xor" |
|
||||
"atomic_xor_acq" |
|
||||
"atomic_xor_rel" |
|
||||
"atomic_xor_acqrel" |
|
||||
"atomic_xor_relaxed" |
|
||||
"atomic_and" |
|
||||
"atomic_and_acq" |
|
||||
"atomic_and_rel" |
|
||||
"atomic_and_acqrel" |
|
||||
"atomic_and_relaxed" |
|
||||
"atomic_xadd" |
|
||||
"atomic_xadd_acq" |
|
||||
"atomic_xadd_rel" |
|
||||
"atomic_xadd_acqrel" |
|
||||
"atomic_xadd_relaxed" |
|
||||
"atomic_xsub" |
|
||||
"atomic_xsub_acq" |
|
||||
"atomic_xsub_rel" |
|
||||
"atomic_xsub_acqrel" |
|
||||
"atomic_xsub_relaxed" => {
|
||||
let ty = substs.type_at(0);
|
||||
let ptr = args[0].into_ptr(&self.memory)?;
|
||||
let change = self.value_to_primval(args[1])?;
|
||||
let old = self.read_value(ptr, ty)?;
|
||||
let old = match old {
|
||||
Value::ByVal(val) => val,
|
||||
Value::ByRef { .. } => bug!("just read the value, can't be byref"),
|
||||
Value::ByValPair(..) => {
|
||||
bug!("atomic_xadd_relaxed doesn't work with nonprimitives")
|
||||
}
|
||||
};
|
||||
self.write_primval(dest, old, ty)?;
|
||||
let op = match intrinsic_name.split('_').nth(1).unwrap() {
|
||||
"or" => mir::BinOp::BitOr,
|
||||
"xor" => mir::BinOp::BitXor,
|
||||
"and" => mir::BinOp::BitAnd,
|
||||
"xadd" => mir::BinOp::Add,
|
||||
"xsub" => mir::BinOp::Sub,
|
||||
_ => bug!(),
|
||||
};
|
||||
// FIXME: what do atomics do on overflow?
|
||||
let (val, _) = self.binary_op(op, old, ty, change, ty)?;
|
||||
self.write_primval(Lvalue::from_primval_ptr(ptr), val, ty)?;
|
||||
}
|
||||
|
||||
"breakpoint" => unimplemented!(), // halt miri
|
||||
|
||||
"copy" |
|
||||
"copy_nonoverlapping" => {
|
||||
let elem_ty = substs.type_at(0);
|
||||
let elem_size = self.type_size(elem_ty)?.expect("cannot copy unsized value");
|
||||
let count = self.value_to_primval(args[2])?.to_u64()?;
|
||||
if count * elem_size != 0 {
|
||||
// TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next.
|
||||
// Also see the write_bytes intrinsic.
|
||||
let elem_align = self.type_align(elem_ty)?;
|
||||
let src = args[0].into_ptr(&self.memory)?;
|
||||
let dest = args[1].into_ptr(&self.memory)?;
|
||||
self.memory.copy(
|
||||
src,
|
||||
dest,
|
||||
count * elem_size,
|
||||
elem_align,
|
||||
intrinsic_name.ends_with("_nonoverlapping"),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
"ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => {
|
||||
let ty = substs.type_at(0);
|
||||
let num = self.value_to_primval(args[0])?.to_bytes()?;
|
||||
let kind = self.ty_to_primval_kind(ty)?;
|
||||
let num = if intrinsic_name.ends_with("_nonzero") {
|
||||
if num == 0 {
|
||||
return err!(Intrinsic(format!("{} called on 0", intrinsic_name)));
|
||||
}
|
||||
numeric_intrinsic(intrinsic_name.trim_right_matches("_nonzero"), num, kind)?
|
||||
} else {
|
||||
numeric_intrinsic(intrinsic_name, num, kind)?
|
||||
};
|
||||
self.write_primval(dest, num, ty)?;
|
||||
}
|
||||
|
||||
"discriminant_value" => {
|
||||
let ty = substs.type_at(0);
|
||||
let adt_ptr = args[0].into_ptr(&self.memory)?.to_ptr()?;
|
||||
let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
|
||||
self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
|
||||
}
|
||||
|
||||
"sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" |
|
||||
"log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => {
|
||||
let f = self.value_to_primval(args[0])?.to_f32()?;
|
||||
let f = match intrinsic_name {
|
||||
"sinf32" => f.sin(),
|
||||
"fabsf32" => f.abs(),
|
||||
"cosf32" => f.cos(),
|
||||
"sqrtf32" => f.sqrt(),
|
||||
"expf32" => f.exp(),
|
||||
"exp2f32" => f.exp2(),
|
||||
"logf32" => f.ln(),
|
||||
"log10f32" => f.log10(),
|
||||
"log2f32" => f.log2(),
|
||||
"floorf32" => f.floor(),
|
||||
"ceilf32" => f.ceil(),
|
||||
"truncf32" => f.trunc(),
|
||||
_ => bug!(),
|
||||
};
|
||||
self.write_primval(dest, PrimVal::from_f32(f), dest_ty)?;
|
||||
}
|
||||
|
||||
"sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" |
|
||||
"log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => {
|
||||
let f = self.value_to_primval(args[0])?.to_f64()?;
|
||||
let f = match intrinsic_name {
|
||||
"sinf64" => f.sin(),
|
||||
"fabsf64" => f.abs(),
|
||||
"cosf64" => f.cos(),
|
||||
"sqrtf64" => f.sqrt(),
|
||||
"expf64" => f.exp(),
|
||||
"exp2f64" => f.exp2(),
|
||||
"logf64" => f.ln(),
|
||||
"log10f64" => f.log10(),
|
||||
"log2f64" => f.log2(),
|
||||
"floorf64" => f.floor(),
|
||||
"ceilf64" => f.ceil(),
|
||||
"truncf64" => f.trunc(),
|
||||
_ => bug!(),
|
||||
};
|
||||
self.write_primval(dest, PrimVal::from_f64(f), dest_ty)?;
|
||||
}
|
||||
|
||||
"fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
|
||||
let ty = substs.type_at(0);
|
||||
let a = self.value_to_primval(args[0])?;
|
||||
let b = self.value_to_primval(args[1])?;
|
||||
let op = match intrinsic_name {
|
||||
"fadd_fast" => mir::BinOp::Add,
|
||||
"fsub_fast" => mir::BinOp::Sub,
|
||||
"fmul_fast" => mir::BinOp::Mul,
|
||||
"fdiv_fast" => mir::BinOp::Div,
|
||||
"frem_fast" => mir::BinOp::Rem,
|
||||
_ => bug!(),
|
||||
};
|
||||
let result = self.binary_op(op, a, ty, b, ty)?;
|
||||
self.write_primval(dest, result.0, dest_ty)?;
|
||||
}
|
||||
|
||||
"likely" | "unlikely" | "forget" => {}
|
||||
|
||||
"init" => {
|
||||
let size = self.type_size(dest_ty)?.expect("cannot zero unsized value");
|
||||
let init = |this: &mut Self, val: Value| {
|
||||
let zero_val = match val {
|
||||
Value::ByRef(PtrAndAlign { ptr, .. }) => {
|
||||
// These writes have no alignment restriction anyway.
|
||||
this.memory.write_repeat(ptr, 0, size)?;
|
||||
val
|
||||
}
|
||||
// TODO(solson): Revisit this, it's fishy to check for Undef here.
|
||||
Value::ByVal(PrimVal::Undef) => {
|
||||
match this.ty_to_primval_kind(dest_ty) {
|
||||
Ok(_) => Value::ByVal(PrimVal::Bytes(0)),
|
||||
Err(_) => {
|
||||
let ptr = this.alloc_ptr_with_substs(dest_ty, substs)?;
|
||||
let ptr = Pointer::from(PrimVal::Ptr(ptr));
|
||||
this.memory.write_repeat(ptr, 0, size)?;
|
||||
Value::by_ref(ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::ByVal(_) => Value::ByVal(PrimVal::Bytes(0)),
|
||||
Value::ByValPair(..) => {
|
||||
Value::ByValPair(PrimVal::Bytes(0), PrimVal::Bytes(0))
|
||||
}
|
||||
};
|
||||
Ok(zero_val)
|
||||
};
|
||||
match dest {
|
||||
Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?,
|
||||
Lvalue::Ptr {
|
||||
ptr: PtrAndAlign { ptr, aligned: true },
|
||||
extra: LvalueExtra::None,
|
||||
} => self.memory.write_repeat(ptr, 0, size)?,
|
||||
Lvalue::Ptr { .. } => {
|
||||
bug!("init intrinsic tried to write to fat or unaligned ptr target")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"min_align_of" => {
|
||||
let elem_ty = substs.type_at(0);
|
||||
let elem_align = self.type_align(elem_ty)?;
|
||||
let align_val = PrimVal::from_u128(elem_align as u128);
|
||||
self.write_primval(dest, align_val, dest_ty)?;
|
||||
}
|
||||
|
||||
"pref_align_of" => {
|
||||
let ty = substs.type_at(0);
|
||||
let layout = self.type_layout(ty)?;
|
||||
let align = layout.align(&self.tcx.data_layout).pref();
|
||||
let align_val = PrimVal::from_u128(align as u128);
|
||||
self.write_primval(dest, align_val, dest_ty)?;
|
||||
}
|
||||
|
||||
"move_val_init" => {
|
||||
let ty = substs.type_at(0);
|
||||
let ptr = args[0].into_ptr(&self.memory)?;
|
||||
self.write_value_to_ptr(args[1].value, ptr, ty)?;
|
||||
}
|
||||
|
||||
"needs_drop" => {
|
||||
let ty = substs.type_at(0);
|
||||
let env = ty::ParamEnv::empty(Reveal::All);
|
||||
let needs_drop = ty.needs_drop(self.tcx, env);
|
||||
self.write_primval(
|
||||
dest,
|
||||
PrimVal::from_bool(needs_drop),
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"offset" => {
|
||||
let offset = self.value_to_primval(args[1])?.to_i128()? as i64;
|
||||
let ptr = args[0].into_ptr(&self.memory)?;
|
||||
let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?;
|
||||
self.write_ptr(dest, result_ptr, dest_ty)?;
|
||||
}
|
||||
|
||||
"overflowing_sub" => {
|
||||
self.intrinsic_overflowing(
|
||||
mir::BinOp::Sub,
|
||||
args[0],
|
||||
args[1],
|
||||
dest,
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"overflowing_mul" => {
|
||||
self.intrinsic_overflowing(
|
||||
mir::BinOp::Mul,
|
||||
args[0],
|
||||
args[1],
|
||||
dest,
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"overflowing_add" => {
|
||||
self.intrinsic_overflowing(
|
||||
mir::BinOp::Add,
|
||||
args[0],
|
||||
args[1],
|
||||
dest,
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"powf32" => {
|
||||
let f = self.value_to_primval(args[0])?.to_f32()?;
|
||||
let f2 = self.value_to_primval(args[1])?.to_f32()?;
|
||||
self.write_primval(
|
||||
dest,
|
||||
PrimVal::from_f32(f.powf(f2)),
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"powf64" => {
|
||||
let f = self.value_to_primval(args[0])?.to_f64()?;
|
||||
let f2 = self.value_to_primval(args[1])?.to_f64()?;
|
||||
self.write_primval(
|
||||
dest,
|
||||
PrimVal::from_f64(f.powf(f2)),
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"fmaf32" => {
|
||||
let a = self.value_to_primval(args[0])?.to_f32()?;
|
||||
let b = self.value_to_primval(args[1])?.to_f32()?;
|
||||
let c = self.value_to_primval(args[2])?.to_f32()?;
|
||||
self.write_primval(
|
||||
dest,
|
||||
PrimVal::from_f32(a * b + c),
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"fmaf64" => {
|
||||
let a = self.value_to_primval(args[0])?.to_f64()?;
|
||||
let b = self.value_to_primval(args[1])?.to_f64()?;
|
||||
let c = self.value_to_primval(args[2])?.to_f64()?;
|
||||
self.write_primval(
|
||||
dest,
|
||||
PrimVal::from_f64(a * b + c),
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"powif32" => {
|
||||
let f = self.value_to_primval(args[0])?.to_f32()?;
|
||||
let i = self.value_to_primval(args[1])?.to_i128()?;
|
||||
self.write_primval(
|
||||
dest,
|
||||
PrimVal::from_f32(f.powi(i as i32)),
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"powif64" => {
|
||||
let f = self.value_to_primval(args[0])?.to_f64()?;
|
||||
let i = self.value_to_primval(args[1])?.to_i128()?;
|
||||
self.write_primval(
|
||||
dest,
|
||||
PrimVal::from_f64(f.powi(i as i32)),
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"size_of" => {
|
||||
let ty = substs.type_at(0);
|
||||
let size = self.type_size(ty)?.expect(
|
||||
"size_of intrinsic called on unsized value",
|
||||
) as u128;
|
||||
self.write_primval(dest, PrimVal::from_u128(size), dest_ty)?;
|
||||
}
|
||||
|
||||
"size_of_val" => {
|
||||
let ty = substs.type_at(0);
|
||||
let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?;
|
||||
self.write_primval(
|
||||
dest,
|
||||
PrimVal::from_u128(size as u128),
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"min_align_of_val" |
|
||||
"align_of_val" => {
|
||||
let ty = substs.type_at(0);
|
||||
let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?;
|
||||
self.write_primval(
|
||||
dest,
|
||||
PrimVal::from_u128(align as u128),
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"type_name" => {
|
||||
let ty = substs.type_at(0);
|
||||
let ty_name = ty.to_string();
|
||||
let value = self.str_to_value(&ty_name)?;
|
||||
self.write_value(ValTy { value, ty: dest_ty }, dest)?;
|
||||
}
|
||||
"type_id" => {
|
||||
let ty = substs.type_at(0);
|
||||
let n = self.tcx.type_id_hash(ty);
|
||||
self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?;
|
||||
}
|
||||
|
||||
"transmute" => {
|
||||
let src_ty = substs.type_at(0);
|
||||
let ptr = self.force_allocation(dest)?.to_ptr()?;
|
||||
self.write_maybe_aligned_mut(
|
||||
/*aligned*/
|
||||
false,
|
||||
|ectx| {
|
||||
ectx.write_value_to_ptr(args[0].value, ptr.into(), src_ty)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
"unchecked_shl" => {
|
||||
let bits = self.type_size(dest_ty)?.expect(
|
||||
"intrinsic can't be called on unsized type",
|
||||
) as u128 * 8;
|
||||
let rhs = self.value_to_primval(args[1])?
|
||||
.to_bytes()?;
|
||||
if rhs >= bits {
|
||||
return err!(Intrinsic(
|
||||
format!("Overflowing shift by {} in unchecked_shl", rhs),
|
||||
));
|
||||
}
|
||||
self.intrinsic_overflowing(
|
||||
mir::BinOp::Shl,
|
||||
args[0],
|
||||
args[1],
|
||||
dest,
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"unchecked_shr" => {
|
||||
let bits = self.type_size(dest_ty)?.expect(
|
||||
"intrinsic can't be called on unsized type",
|
||||
) as u128 * 8;
|
||||
let rhs = self.value_to_primval(args[1])?
|
||||
.to_bytes()?;
|
||||
if rhs >= bits {
|
||||
return err!(Intrinsic(
|
||||
format!("Overflowing shift by {} in unchecked_shr", rhs),
|
||||
));
|
||||
}
|
||||
self.intrinsic_overflowing(
|
||||
mir::BinOp::Shr,
|
||||
args[0],
|
||||
args[1],
|
||||
dest,
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"unchecked_div" => {
|
||||
let rhs = self.value_to_primval(args[1])?
|
||||
.to_bytes()?;
|
||||
if rhs == 0 {
|
||||
return err!(Intrinsic(format!("Division by 0 in unchecked_div")));
|
||||
}
|
||||
self.intrinsic_overflowing(
|
||||
mir::BinOp::Div,
|
||||
args[0],
|
||||
args[1],
|
||||
dest,
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"unchecked_rem" => {
|
||||
let rhs = self.value_to_primval(args[1])?
|
||||
.to_bytes()?;
|
||||
if rhs == 0 {
|
||||
return err!(Intrinsic(format!("Division by 0 in unchecked_rem")));
|
||||
}
|
||||
self.intrinsic_overflowing(
|
||||
mir::BinOp::Rem,
|
||||
args[0],
|
||||
args[1],
|
||||
dest,
|
||||
dest_ty,
|
||||
)?;
|
||||
}
|
||||
|
||||
"uninit" => {
|
||||
let size = dest_layout.size(&self.tcx.data_layout).bytes();
|
||||
let uninit = |this: &mut Self, val: Value| match val {
|
||||
Value::ByRef(PtrAndAlign { ptr, .. }) => {
|
||||
this.memory.mark_definedness(ptr, size, false)?;
|
||||
Ok(val)
|
||||
}
|
||||
_ => Ok(Value::ByVal(PrimVal::Undef)),
|
||||
};
|
||||
match dest {
|
||||
Lvalue::Local { frame, local } => self.modify_local(frame, local, uninit)?,
|
||||
Lvalue::Ptr {
|
||||
ptr: PtrAndAlign { ptr, aligned: true },
|
||||
extra: LvalueExtra::None,
|
||||
} => self.memory.mark_definedness(ptr, size, false)?,
|
||||
Lvalue::Ptr { .. } => {
|
||||
bug!("uninit intrinsic tried to write to fat or unaligned ptr target")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"write_bytes" => {
|
||||
let ty = substs.type_at(0);
|
||||
let ty_align = self.type_align(ty)?;
|
||||
let val_byte = self.value_to_primval(args[1])?.to_u128()? as u8;
|
||||
let size = self.type_size(ty)?.expect(
|
||||
"write_bytes() type must be sized",
|
||||
);
|
||||
let ptr = args[0].into_ptr(&self.memory)?;
|
||||
let count = self.value_to_primval(args[2])?.to_u64()?;
|
||||
if count > 0 {
|
||||
// HashMap relies on write_bytes on a NULL ptr with count == 0 to work
|
||||
// TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic)
|
||||
self.memory.check_align(ptr, ty_align, Some(AccessKind::Write))?;
|
||||
self.memory.write_repeat(ptr, val_byte, size * count)?;
|
||||
}
|
||||
}
|
||||
|
||||
name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))),
|
||||
}
|
||||
|
||||
self.goto_block(target);
|
||||
|
||||
// Since we pushed no stack frame, the main loop will act
|
||||
// as if the call just completed and it's returning to the
|
||||
// current frame.
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn numeric_intrinsic<'tcx>(
|
||||
name: &str,
|
||||
bytes: u128,
|
||||
kind: PrimValKind,
|
||||
) -> EvalResult<'tcx, PrimVal> {
|
||||
macro_rules! integer_intrinsic {
|
||||
($method:ident) => ({
|
||||
use rustc_miri::interpret::PrimValKind::*;
|
||||
let result_bytes = match kind {
|
||||
I8 => (bytes as i8).$method() as u128,
|
||||
U8 => (bytes as u8).$method() as u128,
|
||||
I16 => (bytes as i16).$method() as u128,
|
||||
U16 => (bytes as u16).$method() as u128,
|
||||
I32 => (bytes as i32).$method() as u128,
|
||||
U32 => (bytes as u32).$method() as u128,
|
||||
I64 => (bytes as i64).$method() as u128,
|
||||
U64 => (bytes as u64).$method() as u128,
|
||||
I128 => (bytes as i128).$method() as u128,
|
||||
U128 => bytes.$method() as u128,
|
||||
_ => bug!("invalid `{}` argument: {:?}", name, bytes),
|
||||
};
|
||||
|
||||
PrimVal::Bytes(result_bytes)
|
||||
});
|
||||
}
|
||||
|
||||
let result_val = match name {
|
||||
"bswap" => integer_intrinsic!(swap_bytes),
|
||||
"ctlz" => integer_intrinsic!(leading_zeros),
|
||||
"ctpop" => integer_intrinsic!(count_ones),
|
||||
"cttz" => integer_intrinsic!(trailing_zeros),
|
||||
_ => bug!("not a numeric intrinsic: {}", name),
|
||||
};
|
||||
|
||||
Ok(result_val)
|
||||
}
|
||||
311
miri/lib.rs
311
miri/lib.rs
|
|
@ -1,311 +0,0 @@
|
|||
#![feature(
|
||||
i128_type,
|
||||
rustc_private,
|
||||
)]
|
||||
|
||||
// From rustc.
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate rustc;
|
||||
extern crate syntax;
|
||||
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::layout::Layout;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir;
|
||||
|
||||
use syntax::ast::Mutability;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use std::collections::{HashMap, BTreeMap};
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_miri;
|
||||
pub use rustc_miri::interpret::*;
|
||||
|
||||
mod fn_call;
|
||||
mod operator;
|
||||
mod intrinsic;
|
||||
mod helpers;
|
||||
mod memory;
|
||||
mod tls;
|
||||
|
||||
use fn_call::EvalContextExt as MissingFnsEvalContextExt;
|
||||
use operator::EvalContextExt as OperatorEvalContextExt;
|
||||
use intrinsic::EvalContextExt as IntrinsicEvalContextExt;
|
||||
use tls::EvalContextExt as TlsEvalContextExt;
|
||||
|
||||
pub fn eval_main<'a, 'tcx: 'a>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
main_id: DefId,
|
||||
start_wrapper: Option<DefId>,
|
||||
limits: ResourceLimits,
|
||||
) {
|
||||
fn run_main<'a, 'tcx: 'a>(
|
||||
ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Evaluator>,
|
||||
main_id: DefId,
|
||||
start_wrapper: Option<DefId>,
|
||||
) -> EvalResult<'tcx> {
|
||||
let main_instance = ty::Instance::mono(ecx.tcx, main_id);
|
||||
let main_mir = ecx.load_mir(main_instance.def)?;
|
||||
let mut cleanup_ptr = None; // Pointer to be deallocated when we are done
|
||||
|
||||
if !main_mir.return_ty.is_nil() || main_mir.arg_count != 0 {
|
||||
return err!(Unimplemented(
|
||||
"miri does not support main functions without `fn()` type signatures"
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(start_id) = start_wrapper {
|
||||
let start_instance = ty::Instance::mono(ecx.tcx, start_id);
|
||||
let start_mir = ecx.load_mir(start_instance.def)?;
|
||||
|
||||
if start_mir.arg_count != 3 {
|
||||
return err!(AbiViolation(format!(
|
||||
"'start' lang item should have three arguments, but has {}",
|
||||
start_mir.arg_count
|
||||
)));
|
||||
}
|
||||
|
||||
// Return value
|
||||
let size = ecx.tcx.data_layout.pointer_size.bytes();
|
||||
let align = ecx.tcx.data_layout.pointer_align.abi();
|
||||
let ret_ptr = ecx.memory_mut().allocate(size, align, MemoryKind::Stack)?;
|
||||
cleanup_ptr = Some(ret_ptr);
|
||||
|
||||
// Push our stack frame
|
||||
ecx.push_stack_frame(
|
||||
start_instance,
|
||||
start_mir.span,
|
||||
start_mir,
|
||||
Lvalue::from_ptr(ret_ptr),
|
||||
StackPopCleanup::None,
|
||||
)?;
|
||||
|
||||
let mut args = ecx.frame().mir.args_iter();
|
||||
|
||||
// First argument: pointer to main()
|
||||
let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance);
|
||||
let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
|
||||
let main_ty = main_instance.def.def_ty(ecx.tcx);
|
||||
let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx));
|
||||
ecx.write_value(
|
||||
ValTy {
|
||||
value: Value::ByVal(PrimVal::Ptr(main_ptr)),
|
||||
ty: main_ptr_ty,
|
||||
},
|
||||
dest,
|
||||
)?;
|
||||
|
||||
// Second argument (argc): 1
|
||||
let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
|
||||
let ty = ecx.tcx.types.isize;
|
||||
ecx.write_primval(dest, PrimVal::Bytes(1), ty)?;
|
||||
|
||||
// FIXME: extract main source file path
|
||||
// Third argument (argv): &[b"foo"]
|
||||
let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
|
||||
let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8));
|
||||
let foo = ecx.memory.allocate_cached(b"foo\0")?;
|
||||
let ptr_size = ecx.memory.pointer_size();
|
||||
let foo_ptr = ecx.memory.allocate(ptr_size * 1, ptr_size, MemoryKind::UninitializedStatic)?;
|
||||
ecx.memory.write_primval(foo_ptr.into(), PrimVal::Ptr(foo.into()), ptr_size, false)?;
|
||||
ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?;
|
||||
ecx.write_ptr(dest, foo_ptr.into(), ty)?;
|
||||
|
||||
assert!(args.next().is_none(), "start lang item has more arguments than expected");
|
||||
} else {
|
||||
ecx.push_stack_frame(
|
||||
main_instance,
|
||||
main_mir.span,
|
||||
main_mir,
|
||||
Lvalue::undef(),
|
||||
StackPopCleanup::None,
|
||||
)?;
|
||||
|
||||
// No arguments
|
||||
let mut args = ecx.frame().mir.args_iter();
|
||||
assert!(args.next().is_none(), "main function must not have arguments");
|
||||
}
|
||||
|
||||
while ecx.step()? {}
|
||||
ecx.run_tls_dtors()?;
|
||||
if let Some(cleanup_ptr) = cleanup_ptr {
|
||||
ecx.memory_mut().deallocate(
|
||||
cleanup_ptr,
|
||||
None,
|
||||
MemoryKind::Stack,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let mut ecx = EvalContext::new(tcx, limits, Default::default(), Default::default());
|
||||
match run_main(&mut ecx, main_id, start_wrapper) {
|
||||
Ok(()) => {
|
||||
let leaks = ecx.memory().leak_report();
|
||||
if leaks != 0 {
|
||||
tcx.sess.err("the evaluated program leaked memory");
|
||||
}
|
||||
}
|
||||
Err(mut e) => {
|
||||
ecx.report(&mut e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Evaluator;
|
||||
#[derive(Default)]
|
||||
pub struct EvaluatorData {
|
||||
/// Environment variables set by `setenv`
|
||||
/// Miri does not expose env vars from the host to the emulated program
|
||||
pub(crate) env_vars: HashMap<Vec<u8>, MemoryPointer>,
|
||||
}
|
||||
|
||||
pub type TlsKey = usize;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct TlsEntry<'tcx> {
|
||||
data: Pointer, // Will eventually become a map from thread IDs to `Pointer`s, if we ever support more than one thread.
|
||||
dtor: Option<ty::Instance<'tcx>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MemoryData<'tcx> {
|
||||
/// The Key to use for the next thread-local allocation.
|
||||
next_thread_local: TlsKey,
|
||||
|
||||
/// pthreads-style thread-local storage.
|
||||
thread_local: BTreeMap<TlsKey, TlsEntry<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> Machine<'tcx> for Evaluator {
|
||||
type Data = EvaluatorData;
|
||||
type MemoryData = MemoryData<'tcx>;
|
||||
type MemoryKinds = memory::MemoryKind;
|
||||
|
||||
/// Returns Ok() when the function was handled, fail otherwise
|
||||
fn eval_fn_call<'a>(
|
||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||
args: &[ValTy<'tcx>],
|
||||
span: Span,
|
||||
sig: ty::FnSig<'tcx>,
|
||||
) -> EvalResult<'tcx, bool> {
|
||||
ecx.eval_fn_call(instance, destination, args, span, sig)
|
||||
}
|
||||
|
||||
fn call_intrinsic<'a>(
|
||||
ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[ValTy<'tcx>],
|
||||
dest: Lvalue,
|
||||
dest_ty: ty::Ty<'tcx>,
|
||||
dest_layout: &'tcx Layout,
|
||||
target: mir::BasicBlock,
|
||||
) -> EvalResult<'tcx> {
|
||||
ecx.call_intrinsic(instance, args, dest, dest_ty, dest_layout, target)
|
||||
}
|
||||
|
||||
fn try_ptr_op<'a>(
|
||||
ecx: &rustc_miri::interpret::EvalContext<'a, 'tcx, Self>,
|
||||
bin_op: mir::BinOp,
|
||||
left: PrimVal,
|
||||
left_ty: ty::Ty<'tcx>,
|
||||
right: PrimVal,
|
||||
right_ty: ty::Ty<'tcx>,
|
||||
) -> EvalResult<'tcx, Option<(PrimVal, bool)>> {
|
||||
ecx.ptr_op(bin_op, left, left_ty, right, right_ty)
|
||||
}
|
||||
|
||||
fn mark_static_initialized(m: memory::MemoryKind) -> EvalResult<'tcx> {
|
||||
use memory::MemoryKind::*;
|
||||
match m {
|
||||
// FIXME: This could be allowed, but not for env vars set during miri execution
|
||||
Env => err!(Unimplemented("statics can't refer to env vars".to_owned())),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn box_alloc<'a>(
|
||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
ty: ty::Ty<'tcx>,
|
||||
dest: Lvalue,
|
||||
) -> EvalResult<'tcx> {
|
||||
let size = ecx.type_size(ty)?.expect("box only works with sized types");
|
||||
let align = ecx.type_align(ty)?;
|
||||
|
||||
// Call the `exchange_malloc` lang item
|
||||
let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap();
|
||||
let malloc = ty::Instance::mono(ecx.tcx, malloc);
|
||||
let malloc_mir = ecx.load_mir(malloc.def)?;
|
||||
ecx.push_stack_frame(
|
||||
malloc,
|
||||
malloc_mir.span,
|
||||
malloc_mir,
|
||||
dest,
|
||||
// Don't do anything when we are done. The statement() function will increment
|
||||
// the old stack frame's stmt counter to the next statement, which means that when
|
||||
// exchange_malloc returns, we go on evaluating exactly where we want to be.
|
||||
StackPopCleanup::None,
|
||||
)?;
|
||||
|
||||
let mut args = ecx.frame().mir.args_iter();
|
||||
let usize = ecx.tcx.types.usize;
|
||||
|
||||
// First argument: size
|
||||
let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
|
||||
ecx.write_value(
|
||||
ValTy {
|
||||
value: Value::ByVal(PrimVal::Bytes(size as u128)),
|
||||
ty: usize,
|
||||
},
|
||||
dest,
|
||||
)?;
|
||||
|
||||
// Second argument: align
|
||||
let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
|
||||
ecx.write_value(
|
||||
ValTy {
|
||||
value: Value::ByVal(PrimVal::Bytes(align as u128)),
|
||||
ty: usize,
|
||||
},
|
||||
dest,
|
||||
)?;
|
||||
|
||||
// No more arguments
|
||||
assert!(args.next().is_none(), "exchange_malloc lang item has more arguments than expected");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn global_item_with_linkage<'a>(
|
||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
mutability: Mutability,
|
||||
) -> EvalResult<'tcx> {
|
||||
// FIXME: check that it's `#[linkage = "extern_weak"]`
|
||||
trace!("Initializing an extern global with NULL");
|
||||
let ptr_size = ecx.memory.pointer_size();
|
||||
let ptr = ecx.memory.allocate(
|
||||
ptr_size,
|
||||
ptr_size,
|
||||
MemoryKind::UninitializedStatic,
|
||||
)?;
|
||||
ecx.memory.write_ptr_sized_unsigned(ptr, PrimVal::Bytes(0))?;
|
||||
ecx.memory.mark_static_initalized(ptr.alloc_id, mutability)?;
|
||||
ecx.globals.insert(
|
||||
GlobalId {
|
||||
instance,
|
||||
promoted: None,
|
||||
},
|
||||
PtrAndAlign {
|
||||
ptr: ptr.into(),
|
||||
aligned: true,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub enum MemoryKind {
|
||||
/// Error if deallocated any other way than `rust_deallocate`
|
||||
Rust,
|
||||
/// Error if deallocated any other way than `free`
|
||||
C,
|
||||
/// Part of env var emulation
|
||||
Env,
|
||||
}
|
||||
|
||||
impl Into<::rustc_miri::interpret::MemoryKind<MemoryKind>> for MemoryKind {
|
||||
fn into(self) -> ::rustc_miri::interpret::MemoryKind<MemoryKind> {
|
||||
::rustc_miri::interpret::MemoryKind::Machine(self)
|
||||
}
|
||||
}
|
||||
175
miri/operator.rs
175
miri/operator.rs
|
|
@ -1,175 +0,0 @@
|
|||
use rustc::ty;
|
||||
use rustc::mir;
|
||||
|
||||
use rustc_miri::interpret::*;
|
||||
|
||||
use helpers::EvalContextExt as HelperEvalContextExt;
|
||||
|
||||
pub trait EvalContextExt<'tcx> {
|
||||
fn ptr_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: PrimVal,
|
||||
left_ty: ty::Ty<'tcx>,
|
||||
right: PrimVal,
|
||||
right_ty: ty::Ty<'tcx>,
|
||||
) -> EvalResult<'tcx, Option<(PrimVal, bool)>>;
|
||||
|
||||
fn ptr_int_arithmetic(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: MemoryPointer,
|
||||
right: i128,
|
||||
signed: bool,
|
||||
) -> EvalResult<'tcx, (PrimVal, bool)>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> {
|
||||
fn ptr_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: PrimVal,
|
||||
left_ty: ty::Ty<'tcx>,
|
||||
right: PrimVal,
|
||||
right_ty: ty::Ty<'tcx>,
|
||||
) -> EvalResult<'tcx, Option<(PrimVal, bool)>> {
|
||||
use rustc_miri::interpret::PrimValKind::*;
|
||||
use rustc::mir::BinOp::*;
|
||||
let usize = PrimValKind::from_uint_size(self.memory.pointer_size());
|
||||
let isize = PrimValKind::from_int_size(self.memory.pointer_size());
|
||||
let left_kind = self.ty_to_primval_kind(left_ty)?;
|
||||
let right_kind = self.ty_to_primval_kind(right_ty)?;
|
||||
match bin_op {
|
||||
Offset if left_kind == Ptr && right_kind == usize => {
|
||||
let pointee_ty = left_ty
|
||||
.builtin_deref(true, ty::LvaluePreference::NoPreference)
|
||||
.expect("Offset called on non-ptr type")
|
||||
.ty;
|
||||
let ptr = self.pointer_offset(
|
||||
left.into(),
|
||||
pointee_ty,
|
||||
right.to_bytes()? as i64,
|
||||
)?;
|
||||
Ok(Some((ptr.into_inner_primval(), false)))
|
||||
}
|
||||
// These work on anything
|
||||
Eq if left_kind == right_kind => {
|
||||
let result = match (left, right) {
|
||||
(PrimVal::Bytes(left), PrimVal::Bytes(right)) => left == right,
|
||||
(PrimVal::Ptr(left), PrimVal::Ptr(right)) => left == right,
|
||||
(PrimVal::Undef, _) |
|
||||
(_, PrimVal::Undef) => return err!(ReadUndefBytes),
|
||||
_ => false,
|
||||
};
|
||||
Ok(Some((PrimVal::from_bool(result), false)))
|
||||
}
|
||||
Ne if left_kind == right_kind => {
|
||||
let result = match (left, right) {
|
||||
(PrimVal::Bytes(left), PrimVal::Bytes(right)) => left != right,
|
||||
(PrimVal::Ptr(left), PrimVal::Ptr(right)) => left != right,
|
||||
(PrimVal::Undef, _) |
|
||||
(_, PrimVal::Undef) => return err!(ReadUndefBytes),
|
||||
_ => true,
|
||||
};
|
||||
Ok(Some((PrimVal::from_bool(result), false)))
|
||||
}
|
||||
// These need both pointers to be in the same allocation
|
||||
Lt | Le | Gt | Ge | Sub
|
||||
if left_kind == right_kind &&
|
||||
(left_kind == Ptr || left_kind == usize || left_kind == isize) &&
|
||||
left.is_ptr() && right.is_ptr() => {
|
||||
let left = left.to_ptr()?;
|
||||
let right = right.to_ptr()?;
|
||||
if left.alloc_id == right.alloc_id {
|
||||
let res = match bin_op {
|
||||
Lt => left.offset < right.offset,
|
||||
Le => left.offset <= right.offset,
|
||||
Gt => left.offset > right.offset,
|
||||
Ge => left.offset >= right.offset,
|
||||
Sub => {
|
||||
return self.binary_op(
|
||||
Sub,
|
||||
PrimVal::Bytes(left.offset as u128),
|
||||
self.tcx.types.usize,
|
||||
PrimVal::Bytes(right.offset as u128),
|
||||
self.tcx.types.usize,
|
||||
).map(Some)
|
||||
}
|
||||
_ => bug!("We already established it has to be one of these operators."),
|
||||
};
|
||||
Ok(Some((PrimVal::from_bool(res), false)))
|
||||
} else {
|
||||
// Both are pointers, but from different allocations.
|
||||
err!(InvalidPointerMath)
|
||||
}
|
||||
}
|
||||
// These work if one operand is a pointer, the other an integer
|
||||
Add | BitAnd | Sub
|
||||
if left_kind == right_kind && (left_kind == usize || left_kind == isize) &&
|
||||
left.is_ptr() && right.is_bytes() => {
|
||||
// Cast to i128 is fine as we checked the kind to be ptr-sized
|
||||
self.ptr_int_arithmetic(
|
||||
bin_op,
|
||||
left.to_ptr()?,
|
||||
right.to_bytes()? as i128,
|
||||
left_kind == isize,
|
||||
).map(Some)
|
||||
}
|
||||
Add | BitAnd
|
||||
if left_kind == right_kind && (left_kind == usize || left_kind == isize) &&
|
||||
left.is_bytes() && right.is_ptr() => {
|
||||
// This is a commutative operation, just swap the operands
|
||||
self.ptr_int_arithmetic(
|
||||
bin_op,
|
||||
right.to_ptr()?,
|
||||
left.to_bytes()? as i128,
|
||||
left_kind == isize,
|
||||
).map(Some)
|
||||
}
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn ptr_int_arithmetic(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: MemoryPointer,
|
||||
right: i128,
|
||||
signed: bool,
|
||||
) -> EvalResult<'tcx, (PrimVal, bool)> {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
fn map_to_primval((res, over): (MemoryPointer, bool)) -> (PrimVal, bool) {
|
||||
(PrimVal::Ptr(res), over)
|
||||
}
|
||||
|
||||
Ok(match bin_op {
|
||||
Sub =>
|
||||
// The only way this can overflow is by underflowing, so signdeness of the right operands does not matter
|
||||
map_to_primval(left.overflowing_signed_offset(-right, self)),
|
||||
Add if signed =>
|
||||
map_to_primval(left.overflowing_signed_offset(right, self)),
|
||||
Add if !signed =>
|
||||
map_to_primval(left.overflowing_offset(right as u64, self)),
|
||||
|
||||
BitAnd if !signed => {
|
||||
let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align - 1);
|
||||
let right = right as u64;
|
||||
if right & base_mask == base_mask {
|
||||
// Case 1: The base address bits are all preserved, i.e., right is all-1 there
|
||||
(PrimVal::Ptr(MemoryPointer::new(left.alloc_id, left.offset & right)), false)
|
||||
} else if right & base_mask == 0 {
|
||||
// Case 2: The base address bits are all taken away, i.e., right is all-0 there
|
||||
(PrimVal::from_u128((left.offset & right) as u128), false)
|
||||
} else {
|
||||
return err!(ReadPointerAsBytes);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
let msg = format!("unimplemented binary op on pointer {:?}: {:?}, {:?} ({})", bin_op, left, right, if signed { "signed" } else { "unsigned" });
|
||||
return err!(Unimplemented(msg));
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
142
miri/tls.rs
142
miri/tls.rs
|
|
@ -1,142 +0,0 @@
|
|||
use rustc::{ty, mir};
|
||||
|
||||
use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Pointer, Memory, Evaluator, Lvalue,
|
||||
StackPopCleanup, EvalContext};
|
||||
|
||||
pub trait MemoryExt<'tcx> {
|
||||
fn create_tls_key(&mut self, dtor: Option<ty::Instance<'tcx>>) -> TlsKey;
|
||||
fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx>;
|
||||
fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer>;
|
||||
fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx>;
|
||||
fn fetch_tls_dtor(
|
||||
&mut self,
|
||||
key: Option<TlsKey>,
|
||||
) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>>;
|
||||
}
|
||||
|
||||
pub trait EvalContextExt<'tcx> {
|
||||
fn run_tls_dtors(&mut self) -> EvalResult<'tcx>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator> {
|
||||
fn create_tls_key(&mut self, dtor: Option<ty::Instance<'tcx>>) -> TlsKey {
|
||||
let new_key = self.data.next_thread_local;
|
||||
self.data.next_thread_local += 1;
|
||||
self.data.thread_local.insert(
|
||||
new_key,
|
||||
TlsEntry {
|
||||
data: Pointer::null(),
|
||||
dtor,
|
||||
},
|
||||
);
|
||||
trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor);
|
||||
return new_key;
|
||||
}
|
||||
|
||||
fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> {
|
||||
return match self.data.thread_local.remove(&key) {
|
||||
Some(_) => {
|
||||
trace!("TLS key {} removed", key);
|
||||
Ok(())
|
||||
}
|
||||
None => err!(TlsOutOfBounds),
|
||||
};
|
||||
}
|
||||
|
||||
fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer> {
|
||||
return match self.data.thread_local.get(&key) {
|
||||
Some(&TlsEntry { data, .. }) => {
|
||||
trace!("TLS key {} loaded: {:?}", key, data);
|
||||
Ok(data)
|
||||
}
|
||||
None => err!(TlsOutOfBounds),
|
||||
};
|
||||
}
|
||||
|
||||
fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx> {
|
||||
return match self.data.thread_local.get_mut(&key) {
|
||||
Some(&mut TlsEntry { ref mut data, .. }) => {
|
||||
trace!("TLS key {} stored: {:?}", key, new_data);
|
||||
*data = new_data;
|
||||
Ok(())
|
||||
}
|
||||
None => err!(TlsOutOfBounds),
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns a dtor, its argument and its index, if one is supposed to run
|
||||
///
|
||||
/// An optional destructor function may be associated with each key value.
|
||||
/// At thread exit, if a key value has a non-NULL destructor pointer,
|
||||
/// and the thread has a non-NULL value associated with that key,
|
||||
/// the value of the key is set to NULL, and then the function pointed
|
||||
/// to is called with the previously associated value as its sole argument.
|
||||
/// The order of destructor calls is unspecified if more than one destructor
|
||||
/// exists for a thread when it exits.
|
||||
///
|
||||
/// If, after all the destructors have been called for all non-NULL values
|
||||
/// with associated destructors, there are still some non-NULL values with
|
||||
/// associated destructors, then the process is repeated.
|
||||
/// If, after at least {PTHREAD_DESTRUCTOR_ITERATIONS} iterations of destructor
|
||||
/// calls for outstanding non-NULL values, there are still some non-NULL values
|
||||
/// with associated destructors, implementations may stop calling destructors,
|
||||
/// or they may continue calling destructors until no non-NULL values with
|
||||
/// associated destructors exist, even though this might result in an infinite loop.
|
||||
fn fetch_tls_dtor(
|
||||
&mut self,
|
||||
key: Option<TlsKey>,
|
||||
) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>> {
|
||||
use std::collections::Bound::*;
|
||||
let start = match key {
|
||||
Some(key) => Excluded(key),
|
||||
None => Unbounded,
|
||||
};
|
||||
for (&key, &mut TlsEntry { ref mut data, dtor }) in
|
||||
self.data.thread_local.range_mut((start, Unbounded))
|
||||
{
|
||||
if !data.is_null()? {
|
||||
if let Some(dtor) = dtor {
|
||||
let ret = Some((dtor, *data, key));
|
||||
*data = Pointer::null();
|
||||
return Ok(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, Evaluator> {
|
||||
fn run_tls_dtors(&mut self) -> EvalResult<'tcx> {
|
||||
let mut dtor = self.memory.fetch_tls_dtor(None)?;
|
||||
// FIXME: replace loop by some structure that works with stepping
|
||||
while let Some((instance, ptr, key)) = dtor {
|
||||
trace!("Running TLS dtor {:?} on {:?}", instance, ptr);
|
||||
// TODO: Potentially, this has to support all the other possible instances?
|
||||
// See eval_fn_call in interpret/terminator/mod.rs
|
||||
let mir = self.load_mir(instance.def)?;
|
||||
self.push_stack_frame(
|
||||
instance,
|
||||
mir.span,
|
||||
mir,
|
||||
Lvalue::undef(),
|
||||
StackPopCleanup::None,
|
||||
)?;
|
||||
let arg_local = self.frame().mir.args_iter().next().ok_or(
|
||||
EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()),
|
||||
)?;
|
||||
let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
|
||||
let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8);
|
||||
self.write_ptr(dest, ptr, ty)?;
|
||||
|
||||
// step until out of stackframes
|
||||
while self.step()? {}
|
||||
|
||||
dtor = match self.memory.fetch_tls_dtor(Some(key))? {
|
||||
dtor @ Some(_) => dtor,
|
||||
None => self.memory.fetch_tls_dtor(None)?,
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
217
rustc_tests/Cargo.lock
generated
217
rustc_tests/Cargo.lock
generated
|
|
@ -1,217 +0,0 @@
|
|||
[root]
|
||||
name = "rustc_tests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"miri 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace-sys"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "dbghelp-sys"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log_settings"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miri"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_miri 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_miri"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
|
||||
"checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983"
|
||||
"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c"
|
||||
"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
|
||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
|
||||
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
|
||||
"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
|
||||
"checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915"
|
||||
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
|
||||
"checksum log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3d382732ea0fbc09790c4899db3255bdea0fc78b54bf234bd18a63bb603915b6"
|
||||
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
|
||||
"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
|
||||
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
|
||||
"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e"
|
||||
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
[package]
|
||||
name = "rustc_tests"
|
||||
version = "0.1.0"
|
||||
authors = ["Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>"]
|
||||
|
||||
[dependencies]
|
||||
miri = { path = ".." }
|
||||
|
|
@ -1,292 +0,0 @@
|
|||
#![feature(rustc_private, i128_type)]
|
||||
extern crate miri;
|
||||
extern crate getopts;
|
||||
extern crate rustc;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_errors;
|
||||
extern crate syntax;
|
||||
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::io::Write;
|
||||
use std::sync::{Mutex, Arc};
|
||||
use std::io;
|
||||
|
||||
|
||||
use rustc::session::Session;
|
||||
use rustc::middle::cstore::CrateStore;
|
||||
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
|
||||
use rustc_driver::driver::{CompileState, CompileController};
|
||||
use rustc::session::config::{self, Input, ErrorOutputType};
|
||||
use rustc::hir::{self, itemlikevisit};
|
||||
use rustc::ty::TyCtxt;
|
||||
use syntax::ast;
|
||||
|
||||
struct MiriCompilerCalls {
|
||||
default: RustcDefaultCalls,
|
||||
/// whether we are building for the host
|
||||
host_target: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
|
||||
fn early_callback(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sopts: &config::Options,
|
||||
cfg: &ast::CrateConfig,
|
||||
descriptions: &rustc_errors::registry::Registry,
|
||||
output: ErrorOutputType
|
||||
) -> Compilation {
|
||||
self.default.early_callback(matches, sopts, cfg, descriptions, output)
|
||||
}
|
||||
fn no_input(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sopts: &config::Options,
|
||||
cfg: &ast::CrateConfig,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
descriptions: &rustc_errors::registry::Registry
|
||||
) -> Option<(Input, Option<PathBuf>)> {
|
||||
self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions)
|
||||
}
|
||||
fn late_callback(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sess: &Session,
|
||||
cstore: &CrateStore,
|
||||
input: &Input,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>
|
||||
) -> Compilation {
|
||||
self.default.late_callback(matches, sess, cstore, input, odir, ofile)
|
||||
}
|
||||
fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> {
|
||||
let mut control = self.default.build_controller(sess, matches);
|
||||
control.after_hir_lowering.callback = Box::new(after_hir_lowering);
|
||||
control.after_analysis.callback = Box::new(after_analysis);
|
||||
if !self.host_target {
|
||||
// only fully compile targets on the host
|
||||
control.after_analysis.stop = Compilation::Stop;
|
||||
}
|
||||
control
|
||||
}
|
||||
}
|
||||
|
||||
fn after_hir_lowering(state: &mut CompileState) {
|
||||
let attr = (String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted);
|
||||
state.session.plugin_attributes.borrow_mut().push(attr);
|
||||
}
|
||||
|
||||
fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
|
||||
state.session.abort_if_errors();
|
||||
|
||||
let tcx = state.tcx.unwrap();
|
||||
let limits = Default::default();
|
||||
|
||||
if std::env::args().any(|arg| arg == "--test") {
|
||||
struct Visitor<'a, 'tcx: 'a>(miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>);
|
||||
impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
|
||||
fn visit_item(&mut self, i: &'hir hir::Item) {
|
||||
if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node {
|
||||
if i.attrs.iter().any(|attr| attr.name().map_or(false, |n| n == "test")) {
|
||||
let did = self.1.hir.body_owner_def_id(body_id);
|
||||
println!("running test: {}", self.1.hir.def_path(did).to_string(self.1));
|
||||
miri::eval_main(self.1, did, None, self.0);
|
||||
self.2.session.abort_if_errors();
|
||||
}
|
||||
}
|
||||
}
|
||||
fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
|
||||
fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
|
||||
}
|
||||
state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(limits, tcx, state));
|
||||
} else if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
|
||||
let entry_def_id = tcx.hir.local_def_id(entry_node_id);
|
||||
let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn|
|
||||
if tcx.is_mir_available(start_fn) { Some(start_fn) } else { None });
|
||||
miri::eval_main(tcx, entry_def_id, start_wrapper, limits);
|
||||
|
||||
state.session.abort_if_errors();
|
||||
} else {
|
||||
println!("no main function found, assuming auxiliary build");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let path = option_env!("MIRI_RUSTC_TEST")
|
||||
.map(String::from)
|
||||
.unwrap_or_else(|| {
|
||||
std::env::var("MIRI_RUSTC_TEST")
|
||||
.expect("need to set MIRI_RUSTC_TEST to path of rustc tests")
|
||||
});
|
||||
|
||||
let mut mir_not_found = Vec::new();
|
||||
let mut crate_not_found = Vec::new();
|
||||
let mut success = 0;
|
||||
let mut failed = Vec::new();
|
||||
let mut c_abi_fns = Vec::new();
|
||||
let mut abi = Vec::new();
|
||||
let mut unsupported = Vec::new();
|
||||
let mut unimplemented_intrinsic = Vec::new();
|
||||
let mut limits = Vec::new();
|
||||
let mut files: Vec<_> = std::fs::read_dir(path).unwrap().collect();
|
||||
while let Some(file) = files.pop() {
|
||||
let file = file.unwrap();
|
||||
let path = file.path();
|
||||
if file.metadata().unwrap().is_dir() {
|
||||
if !path.to_str().unwrap().ends_with("auxiliary") {
|
||||
// add subdirs recursively
|
||||
files.extend(std::fs::read_dir(path).unwrap());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
|
||||
continue;
|
||||
}
|
||||
let stderr = std::io::stderr();
|
||||
write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
|
||||
let mut host_target = false;
|
||||
let mut args: Vec<String> = std::env::args().filter(|arg| {
|
||||
if arg == "--miri_host_target" {
|
||||
host_target = true;
|
||||
false // remove the flag, rustc doesn't know it
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}).collect();
|
||||
// file to process
|
||||
args.push(path.display().to_string());
|
||||
|
||||
let sysroot_flag = String::from("--sysroot");
|
||||
if !args.contains(&sysroot_flag) {
|
||||
args.push(sysroot_flag);
|
||||
args.push(Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST").display().to_string());
|
||||
}
|
||||
|
||||
args.push("-Zmir-opt-level=3".to_owned());
|
||||
// for auxilary builds in unit tests
|
||||
args.push("-Zalways-encode-mir".to_owned());
|
||||
|
||||
// A threadsafe buffer for writing.
|
||||
#[derive(Default, Clone)]
|
||||
struct BufWriter(Arc<Mutex<Vec<u8>>>);
|
||||
|
||||
impl Write for BufWriter {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.lock().unwrap().write(buf)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.0.lock().unwrap().flush()
|
||||
}
|
||||
}
|
||||
let buf = BufWriter::default();
|
||||
let output = buf.clone();
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
rustc_driver::run_compiler(&args, &mut MiriCompilerCalls {
|
||||
default: RustcDefaultCalls,
|
||||
host_target,
|
||||
}, None, Some(Box::new(buf)));
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(()) => {
|
||||
success += 1;
|
||||
writeln!(stderr.lock(), "ok").unwrap()
|
||||
},
|
||||
Err(_) => {
|
||||
let output = output.0.lock().unwrap();
|
||||
let output_err = std::str::from_utf8(&output).unwrap();
|
||||
if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) {
|
||||
let end = text.find('`').unwrap();
|
||||
mir_not_found.push(text[..end].to_string());
|
||||
writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap();
|
||||
} else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) {
|
||||
let end = text.find('`').unwrap();
|
||||
crate_not_found.push(text[..end].to_string());
|
||||
writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap();
|
||||
} else {
|
||||
for text in output_err.split("error: ").skip(1) {
|
||||
let end = text.find('\n').unwrap_or(text.len());
|
||||
let c_abi = "can't call C ABI function: ";
|
||||
let unimplemented_intrinsic_s = "unimplemented intrinsic: ";
|
||||
let unsupported_s = "miri does not support ";
|
||||
let abi_s = "can't handle function with ";
|
||||
let limit_s = "reached the configured maximum ";
|
||||
if text.starts_with(c_abi) {
|
||||
c_abi_fns.push(text[c_abi.len()..end].to_string());
|
||||
} else if text.starts_with(unimplemented_intrinsic_s) {
|
||||
unimplemented_intrinsic.push(text[unimplemented_intrinsic_s.len()..end].to_string());
|
||||
} else if text.starts_with(unsupported_s) {
|
||||
unsupported.push(text[unsupported_s.len()..end].to_string());
|
||||
} else if text.starts_with(abi_s) {
|
||||
abi.push(text[abi_s.len()..end].to_string());
|
||||
} else if text.starts_with(limit_s) {
|
||||
limits.push(text[limit_s.len()..end].to_string());
|
||||
} else if text.find("aborting").is_none() {
|
||||
failed.push(text[..end].to_string());
|
||||
}
|
||||
}
|
||||
writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let stderr = std::io::stderr();
|
||||
let mut stderr = stderr.lock();
|
||||
writeln!(stderr, "{} success, {} no mir, {} crate not found, {} failed, \
|
||||
{} C fn, {} ABI, {} unsupported, {} intrinsic",
|
||||
success, mir_not_found.len(), crate_not_found.len(), failed.len(),
|
||||
c_abi_fns.len(), abi.len(), unsupported.len(), unimplemented_intrinsic.len()).unwrap();
|
||||
writeln!(stderr, "# The \"other reasons\" errors").unwrap();
|
||||
writeln!(stderr, "(sorted, deduplicated)").unwrap();
|
||||
print_vec(&mut stderr, failed);
|
||||
|
||||
writeln!(stderr, "# can't call C ABI function").unwrap();
|
||||
print_vec(&mut stderr, c_abi_fns);
|
||||
|
||||
writeln!(stderr, "# unsupported ABI").unwrap();
|
||||
print_vec(&mut stderr, abi);
|
||||
|
||||
writeln!(stderr, "# unsupported").unwrap();
|
||||
print_vec(&mut stderr, unsupported);
|
||||
|
||||
writeln!(stderr, "# unimplemented intrinsics").unwrap();
|
||||
print_vec(&mut stderr, unimplemented_intrinsic);
|
||||
|
||||
writeln!(stderr, "# mir not found").unwrap();
|
||||
print_vec(&mut stderr, mir_not_found);
|
||||
|
||||
writeln!(stderr, "# crate not found").unwrap();
|
||||
print_vec(&mut stderr, crate_not_found);
|
||||
}
|
||||
|
||||
fn print_vec<W: std::io::Write>(stderr: &mut W, v: Vec<String>) {
|
||||
writeln!(stderr, "```").unwrap();
|
||||
for (n, s) in vec_to_hist(v).into_iter().rev() {
|
||||
writeln!(stderr, "{:4} {}", n, s).unwrap();
|
||||
}
|
||||
writeln!(stderr, "```").unwrap();
|
||||
}
|
||||
|
||||
fn vec_to_hist<T: PartialEq + Ord>(mut v: Vec<T>) -> Vec<(usize, T)> {
|
||||
v.sort();
|
||||
let mut v = v.into_iter();
|
||||
let mut result = Vec::new();
|
||||
let mut current = v.next();
|
||||
'outer: while let Some(current_val) = current {
|
||||
let mut n = 1;
|
||||
for next in &mut v {
|
||||
if next == current_val {
|
||||
n += 1;
|
||||
} else {
|
||||
result.push((n, current_val));
|
||||
current = Some(next);
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
result.push((n, current_val));
|
||||
break;
|
||||
}
|
||||
result.sort();
|
||||
result
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
[package]
|
||||
authors = ["Scott Olson <scott@solson.me>"]
|
||||
description = "An experimental interpreter for Rust MIR."
|
||||
license = "MIT/Apache-2.0"
|
||||
name = "rustc_miri"
|
||||
repository = "https://github.com/solson/miri"
|
||||
version = "0.1.0"
|
||||
workspace = "../.."
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
byteorder = { version = "1.1", features = ["i128"]}
|
||||
log = "0.3.6"
|
||||
log_settings = "0.1.1"
|
||||
lazy_static = "0.2.8"
|
||||
regex = "0.2.2"
|
||||
backtrace = "0.3.3"
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#![feature(
|
||||
i128_type,
|
||||
rustc_private,
|
||||
conservative_impl_trait,
|
||||
never_type,
|
||||
catch_expr,
|
||||
)]
|
||||
|
||||
// From rustc.
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate log_settings;
|
||||
#[macro_use]
|
||||
extern crate rustc;
|
||||
extern crate rustc_const_math;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate syntax;
|
||||
|
||||
// From crates.io.
|
||||
extern crate byteorder;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate regex;
|
||||
extern crate backtrace;
|
||||
|
||||
pub mod interpret;
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
// This should fail even without validation
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
|
||||
fn main() {
|
||||
let v: Vec<u8> = Vec::with_capacity(10);
|
||||
let undef = unsafe { *v.get_unchecked(5) };
|
||||
let x = undef + 1; //~ ERROR: attempted to read undefined bytes
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fn main() {
|
||||
// miri always gives allocations the worst possible alignment, so a `u8` array is guaranteed
|
||||
// to be at the virtual location 1 (so one byte offset from the ultimate alignemnt location 0)
|
||||
let mut x = [0u8; 20];
|
||||
let x_ptr: *mut u8 = &mut x[0];
|
||||
let y_ptr = x_ptr as *mut u64;
|
||||
unsafe {
|
||||
*y_ptr = 42; //~ ERROR tried to access memory with alignment 1, but alignment
|
||||
}
|
||||
panic!("unreachable in miri");
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#![feature(core_intrinsics)]
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
unsafe {
|
||||
std::intrinsics::assume(x < 10);
|
||||
std::intrinsics::assume(x > 1);
|
||||
std::intrinsics::assume(x > 42); //~ ERROR: `assume` argument was false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::mem;
|
||||
|
||||
enum Tag<A> {
|
||||
Tag2(A)
|
||||
}
|
||||
|
||||
struct Rec {
|
||||
c8: u8,
|
||||
t: Tag<u64>
|
||||
}
|
||||
|
||||
fn mk_rec() -> Rec {
|
||||
return Rec { c8:0, t:Tag::Tag2(0) };
|
||||
}
|
||||
|
||||
fn is_u64_aligned(u: &Tag<u64>) -> bool {
|
||||
let p: usize = unsafe { mem::transmute(u) };
|
||||
let u64_align = std::mem::align_of::<u64>();
|
||||
return (p & (u64_align + 1)) == 0; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let x = mk_rec();
|
||||
assert!(is_u64_aligned(&x.t));
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
// Validation makes this fail in the wrong place
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
|
||||
fn main() {
|
||||
let b = Box::new(42);
|
||||
let g = unsafe {
|
||||
std::mem::transmute::<&usize, &fn(i32)>(&b)
|
||||
};
|
||||
|
||||
(*g)(42) //~ ERROR a memory access tried to interpret some bytes as a pointer
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
fn main() {
|
||||
fn f() {}
|
||||
|
||||
let g = unsafe {
|
||||
std::mem::transmute::<fn(), fn(i32)>(f)
|
||||
};
|
||||
|
||||
g(42) //~ ERROR tried to call a function with sig fn() through a function pointer of type fn(i32)
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
fn main() {
|
||||
fn f(_ : (i32,i32)) {}
|
||||
|
||||
let g = unsafe {
|
||||
std::mem::transmute::<fn((i32,i32)), fn(i32)>(f)
|
||||
};
|
||||
|
||||
g(42) //~ ERROR tried to call a function with sig fn((i32, i32)) through a function pointer of type fn(i32)
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
// just making sure that fn -> unsafe fn casts are handled by rustc so miri doesn't have to
|
||||
fn main() {
|
||||
fn f() {}
|
||||
|
||||
let g = f as fn() as unsafe fn(i32); //~ERROR: non-primitive cast: `fn()` as `unsafe fn(i32)`
|
||||
|
||||
unsafe {
|
||||
g(42);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
// just making sure that fn -> unsafe fn casts are handled by rustc so miri doesn't have to
|
||||
fn main() {
|
||||
fn f() {}
|
||||
|
||||
let g = f as fn() as fn(i32) as unsafe fn(i32); //~ERROR: non-primitive cast: `fn()` as `fn(i32)`
|
||||
|
||||
unsafe {
|
||||
g(42);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
// Validation makes this fail in the wrong place
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
|
||||
fn main() {
|
||||
let g = unsafe {
|
||||
std::mem::transmute::<usize, fn(i32)>(42)
|
||||
};
|
||||
|
||||
g(42) //~ ERROR a memory access tried to interpret some bytes as a pointer
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
use std::intrinsics::*;
|
||||
|
||||
//error-pattern: copy_nonoverlapping called on overlapping ranges
|
||||
|
||||
fn main() {
|
||||
let mut data = [0u8; 16];
|
||||
unsafe {
|
||||
let a = &data[0] as *const _;
|
||||
let b = &mut data[1] as *mut _;
|
||||
std::ptr::copy_nonoverlapping(a, b, 2);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#![feature(intrinsics)]
|
||||
|
||||
mod rusti {
|
||||
extern "rust-intrinsic" {
|
||||
pub fn ctlz_nonzero<T>(x: T) -> T;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
use rusti::*;
|
||||
|
||||
ctlz_nonzero(0u8); //~ ERROR: ctlz_nonzero called on 0
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#![feature(intrinsics)]
|
||||
|
||||
mod rusti {
|
||||
extern "rust-intrinsic" {
|
||||
pub fn cttz_nonzero<T>(x: T) -> T;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
use rusti::*;
|
||||
|
||||
cttz_nonzero(0u8); //~ ERROR: cttz_nonzero called on 0
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fn main() {
|
||||
let p = {
|
||||
let b = Box::new(42);
|
||||
&*b as *const i32
|
||||
};
|
||||
let x = unsafe { *p }; //~ ERROR: dangling pointer was dereferenced
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#![feature(alloc, allocator_api)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::heap::Heap;
|
||||
use alloc::allocator::*;
|
||||
|
||||
// error-pattern: tried to deallocate or reallocate using incorrect alignment or size
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
|
||||
Heap.dealloc(x, Layout::from_size_align_unchecked(1, 2));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#![feature(alloc, allocator_api)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::heap::Heap;
|
||||
use alloc::allocator::*;
|
||||
|
||||
// error-pattern: tried to deallocate or reallocate using incorrect alignment or size
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
|
||||
Heap.dealloc(x, Layout::from_size_align_unchecked(2, 1));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#![feature(alloc, allocator_api)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::heap::Heap;
|
||||
use alloc::allocator::*;
|
||||
|
||||
// error-pattern: tried to deallocate dangling pointer
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
|
||||
Heap.dealloc(x, Layout::from_size_align_unchecked(1, 1));
|
||||
Heap.dealloc(x, Layout::from_size_align_unchecked(1, 1));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fn f() {}
|
||||
|
||||
fn main() {
|
||||
let x: i32 = unsafe {
|
||||
*std::mem::transmute::<fn(), *const i32>(f) //~ ERROR: tried to dereference a function pointer
|
||||
};
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(const_err)]
|
||||
|
||||
fn main() {
|
||||
let _n = 1 / 0; //~ ERROR: DivisionByZero
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
use std::intrinsics::*;
|
||||
|
||||
//error-pattern: Division by 0 in unchecked_div
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let _n = unchecked_div(1i64, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
// Validation makes this fail in the wrong place
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn main() {
|
||||
let x = box 42;
|
||||
unsafe {
|
||||
let f = std::mem::transmute::<Box<i32>, fn()>(x);
|
||||
f() //~ ERROR: tried to treat a memory pointer as a function pointer
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
// Validation makes this fail in the wrong place
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
|
||||
use std::mem;
|
||||
|
||||
fn f() {}
|
||||
|
||||
fn main() {
|
||||
let x : fn() = f;
|
||||
let y : *mut u8 = unsafe { mem::transmute(x) };
|
||||
let y = y.wrapping_offset(1);
|
||||
let x : fn() = unsafe { mem::transmute(y) };
|
||||
x(); //~ ERROR: tried to use a function pointer after offsetting it
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
fn main() {
|
||||
let b = unsafe { std::mem::transmute::<u8, bool>(2) }; //~ ERROR: invalid boolean value read
|
||||
if b { unreachable!() } else { unreachable!() }
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
// Validation makes this fail in the wrong place
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
|
||||
#[repr(C)]
|
||||
pub enum Foo {
|
||||
A, B, C, D
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let f = unsafe { std::mem::transmute::<i32, Foo>(42) };
|
||||
match f {
|
||||
Foo::A => {}, //~ ERROR invalid enum discriminant value read
|
||||
Foo::B => {},
|
||||
Foo::C => {},
|
||||
Foo::D => {},
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fn main() {
|
||||
assert!(std::char::from_u32(-1_i32 as u32).is_none());
|
||||
match unsafe { std::mem::transmute::<i32, char>(-1) } { //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295
|
||||
'a' => {},
|
||||
'b' => {},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
//error-pattern: the evaluated program leaked memory
|
||||
|
||||
fn main() {
|
||||
std::mem::forget(Box::new(42));
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
//error-pattern: the evaluated program leaked memory
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
|
||||
struct Dummy(Rc<RefCell<Option<Dummy>>>);
|
||||
|
||||
fn main() {
|
||||
let x = Dummy(Rc::new(RefCell::new(None)));
|
||||
let y = Dummy(x.0.clone());
|
||||
*x.0.borrow_mut() = Some(y);
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
fn main() {
|
||||
let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee
|
||||
let y = unsafe { &mut *(x as *const i32 as *mut i32) };
|
||||
*y = 42; //~ ERROR tried to modify constant memory
|
||||
assert_eq!(*x, 42);
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// This should fail even without validation
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
|
||||
#![feature(never_type)]
|
||||
#![allow(unreachable_code)]
|
||||
|
||||
fn main() {
|
||||
let y = &5;
|
||||
let x: ! = unsafe {
|
||||
*(y as *const _ as *const !) //~ ERROR tried to access a dead local variable
|
||||
};
|
||||
f(x)
|
||||
}
|
||||
|
||||
fn f(x: !) -> ! { x }
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
// This should fail even without validation
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
|
||||
#![feature(never_type)]
|
||||
#![allow(unreachable_code)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
struct Human;
|
||||
|
||||
fn main() {
|
||||
let x: ! = unsafe {
|
||||
std::mem::transmute::<Human, !>(Human) //~ ERROR entered unreachable code
|
||||
};
|
||||
f(x)
|
||||
}
|
||||
|
||||
fn f(x: !) -> ! { x }
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// This should fail even without validation
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
|
||||
#![feature(never_type)]
|
||||
#![allow(unreachable_code)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
enum Void {}
|
||||
|
||||
fn f(v: Void) -> ! {
|
||||
match v {} //~ ERROR entered unreachable code
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let v: Void = unsafe {
|
||||
std::mem::transmute::<(), Void>(())
|
||||
};
|
||||
f(v);
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
fn main() {
|
||||
let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: invalid use of NULL pointer
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#![feature(custom_attribute, attr_literals)]
|
||||
#![miri(memory_size=4095)]
|
||||
|
||||
fn main() {
|
||||
let _x = [42; 1024];
|
||||
//~^ERROR tried to allocate 4096 more bytes, but only
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
// Validation forces more allocation; disable it.
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
#![feature(box_syntax, custom_attribute, attr_literals)]
|
||||
#![miri(memory_size=1024)]
|
||||
|
||||
// On 64bit platforms, the allocator needs 32 bytes allocated to pass a return value, so that's the error we see.
|
||||
// On 32bit platforms, it's just 16 bytes.
|
||||
// error-pattern: tried to allocate
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
::std::mem::forget(box 42);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
// error-pattern: pointer computed at offset 5, outside bounds of allocation
|
||||
fn main() {
|
||||
let v = [0i8; 4];
|
||||
let x = &v as *const i8;
|
||||
// The error is inside another function, so we cannot match it by line
|
||||
let x = unsafe { x.offset(5) };
|
||||
panic!("this should never print: {:?}", x);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
// error-pattern: overflowing math
|
||||
fn main() {
|
||||
let v = [0i8; 4];
|
||||
let x = &v as *const i8;
|
||||
let x = unsafe { x.offset(-1) };
|
||||
panic!("this should never print: {:?}", x);
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
fn main() {
|
||||
let v: Vec<u8> = vec![1, 2];
|
||||
let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: which has size 2
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
fn main() {
|
||||
let v: Vec<u8> = vec![1, 2];
|
||||
let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: memory access at offset 6, outside bounds of allocation
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(exceeding_bitshifts)]
|
||||
#![allow(const_err)]
|
||||
|
||||
fn main() {
|
||||
let _n = 2i64 << -1; //~ Overflow(Shl)
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(exceeding_bitshifts, const_err)]
|
||||
|
||||
fn main() {
|
||||
// Make sure we catch overflows that would be hidden by first casting the RHS to u32
|
||||
let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ Overflow(Shr)
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(exceeding_bitshifts)]
|
||||
|
||||
fn main() {
|
||||
let _n = 1i64 >> 64; //~ Overflow(Shr)
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
use std::intrinsics::*;
|
||||
|
||||
//error-pattern: Overflowing shift by 64 in unchecked_shr
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let _n = unchecked_shr(1i64, 64);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fn main() {
|
||||
let mut p = &42;
|
||||
unsafe {
|
||||
let ptr: *mut _ = &mut p;
|
||||
*(ptr as *mut u8) = 123; // if we ever support 8 bit pointers, this is gonna cause
|
||||
// "attempted to interpret some raw bytes as a pointer address" instead of
|
||||
// "attempted to read undefined bytes"
|
||||
}
|
||||
let x = *p; //~ ERROR: attempted to read undefined bytes
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
// FIXME: Something in panic handling fails validation with full-MIR
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
//error-pattern: the evaluated program panicked
|
||||
|
||||
fn main() {
|
||||
assert_eq!(5, 6);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fn main() {
|
||||
let x = 13;
|
||||
let y = &x;
|
||||
let z = &y as *const &i32 as *const usize;
|
||||
let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once
|
||||
let _ = ptr_bytes % 432; //~ ERROR: tried to access part of a pointer value as raw bytes
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fn main() {
|
||||
let x = 13;
|
||||
let y = &x;
|
||||
let z = &y as *const &i32 as *const u8;
|
||||
// the deref fails, because we are reading only a part of the pointer
|
||||
let _ = unsafe { *z }; //~ ERROR: tried to access part of a pointer value as raw bytes
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fn main() {
|
||||
let x: *const u8 = &1;
|
||||
let y: *const u8 = &2;
|
||||
if x < y { //~ ERROR: attempted to do invalid arithmetic on pointers
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fn main() {
|
||||
let bytes = [0i8, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
let one = bytes.as_ptr().wrapping_offset(1);
|
||||
let three = bytes.as_ptr().wrapping_offset(3);
|
||||
let res = (one as usize) | (three as usize); //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes
|
||||
println!("{}", res);
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fn main() {
|
||||
let x = &1;
|
||||
// Casting down to u8 and back up to a pointer loses too much precision; this must not work.
|
||||
let x = x as *const i32;
|
||||
let x = x as u8; //~ ERROR: a raw memory access tried to access part of a pointer value as raw bytes
|
||||
let x = x as *const i32;
|
||||
let _ = unsafe { *x };
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
//error-pattern: overflowing math
|
||||
fn main() {
|
||||
let v = [1i8, 2];
|
||||
let x = &v[1] as *const i8;
|
||||
let _ = unsafe { x.offset(isize::min_value()) };
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
// We use packed structs to get around alignment restrictions
|
||||
#[repr(packed)]
|
||||
struct Data {
|
||||
pad: u8,
|
||||
ptr: &'static i32,
|
||||
}
|
||||
|
||||
// But we need to gurantee some alignment
|
||||
struct Wrapper {
|
||||
align: u64,
|
||||
data: Data,
|
||||
}
|
||||
|
||||
static G : i32 = 0;
|
||||
|
||||
fn main() {
|
||||
let mut w = Wrapper { align: 0, data: Data { pad: 0, ptr: &G } };
|
||||
|
||||
// Get a pointer to the beginning of the Data struct (one u8 byte, then the pointer bytes).
|
||||
// Thanks to the wrapper, we know this is aligned-enough to perform a load at ptr size.
|
||||
// We load at pointer type, so having a relocation is okay -- but here, the relocation
|
||||
// starts 1 byte to the right, so using it would actually be wrong!
|
||||
let d_alias = &mut w.data as *mut _ as *mut *const u8;
|
||||
unsafe {
|
||||
let _x = *d_alias; //~ ERROR: tried to access part of a pointer value as raw bytes
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#![feature(alloc, allocator_api)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::heap::Heap;
|
||||
use alloc::allocator::*;
|
||||
|
||||
// error-pattern: tried to deallocate or reallocate using incorrect alignment or size
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
|
||||
// Try realloc with a too big alignment.
|
||||
let _y = Heap.realloc(x, Layout::from_size_align_unchecked(1, 2), Layout::from_size_align_unchecked(1, 1)).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#![feature(alloc, allocator_api)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::heap::Heap;
|
||||
use alloc::allocator::*;
|
||||
|
||||
// error-pattern: tried to deallocate or reallocate using incorrect alignment or size
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 2)).unwrap();
|
||||
// Try realloc with a too small alignment.
|
||||
let _y = Heap.realloc(x, Layout::from_size_align_unchecked(1, 1), Layout::from_size_align_unchecked(1, 2)).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#![feature(alloc, allocator_api)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::heap::Heap;
|
||||
use alloc::allocator::*;
|
||||
|
||||
// error-pattern: tried to deallocate or reallocate using incorrect alignment or size
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
|
||||
let _y = Heap.realloc(x, Layout::from_size_align_unchecked(2, 1), Layout::from_size_align_unchecked(1, 1)).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#![feature(alloc, allocator_api)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::heap::Heap;
|
||||
use alloc::allocator::*;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
|
||||
let _y = Heap.realloc(x, Layout::from_size_align_unchecked(1, 1), Layout::from_size_align_unchecked(1, 1)).unwrap();
|
||||
let _z = *x; //~ ERROR: dangling pointer was dereferenced
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#![feature(alloc, allocator_api)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::heap::Heap;
|
||||
use alloc::allocator::*;
|
||||
|
||||
// error-pattern: dangling pointer was dereferenced
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
|
||||
Heap.dealloc(x, Layout::from_size_align_unchecked(1, 1));
|
||||
Heap.realloc(x, Layout::from_size_align_unchecked(1, 1), Layout::from_size_align_unchecked(1, 1));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// This should fail even without validation
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
#[repr(packed)]
|
||||
struct Foo {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo = Foo {
|
||||
x: 42,
|
||||
y: 99,
|
||||
};
|
||||
let p = &foo.x;
|
||||
let i = *p; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
fn main() {
|
||||
let data: [u8; std::usize::MAX] = [42; std::usize::MAX];
|
||||
//~^ ERROR: rustc layout computation failed: SizeOverflow([u8;
|
||||
assert_eq!(data.len(), 1024);
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
fn main() {
|
||||
let data: [u8; 1024*1024*1024] = [42; 1024*1024*1024];
|
||||
//~^ ERROR: reached the configured maximum execution time
|
||||
assert_eq!(data.len(), 1024*1024*1024);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
// error-pattern: tried to deallocate Stack memory but gave Machine(Rust) as the kind
|
||||
|
||||
fn main() {
|
||||
let x = 42;
|
||||
let bad_box = unsafe { std::mem::transmute::<&i32, Box<i32>>(&x) };
|
||||
drop(bad_box);
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#![feature(custom_attribute, attr_literals)]
|
||||
#![miri(stack_limit=16)]
|
||||
|
||||
//error-pattern: reached the configured maximum number of stack frames
|
||||
|
||||
fn bar() {
|
||||
foo();
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
cake();
|
||||
}
|
||||
|
||||
fn cake() {
|
||||
bar();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
bar();
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
static X: usize = 5;
|
||||
|
||||
#[allow(mutable_transmutes)]
|
||||
fn main() {
|
||||
unsafe {
|
||||
*std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR: tried to modify constant memory
|
||||
assert_eq!(X, 6);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
// Validation detects that we are casting & to &mut and so it changes why we fail
|
||||
// compile-flags: -Zmir-emit-validate=0
|
||||
|
||||
use std::mem::transmute;
|
||||
|
||||
#[allow(mutable_transmutes)]
|
||||
fn main() {
|
||||
unsafe {
|
||||
let s = "this is a test";
|
||||
transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR: tried to modify constant memory
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue