Remove all non-CTFE stuff from the miri repository

This commit is contained in:
Oliver Schneider 2017-09-18 13:34:01 +02:00
parent ed674f7cb3
commit f035b3d246
No known key found for this signature in database
GPG key ID: A69F8D225B3AD7D9
285 changed files with 0 additions and 11610 deletions

6
.gitignore vendored
View file

@ -1,6 +0,0 @@
target
/doc
tex/*/out
*.dot
*.mir
*.rs.bk

View file

@ -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
View file

@ -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"

View file

@ -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"]

View file

@ -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.

View file

@ -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
View file

@ -1,103 +0,0 @@
# Miri [[slides](https://solson.me/miri-slides.pdf)] [[report](https://solson.me/miri-report.pdf)] [![Build Status](https://travis-ci.org/solson/miri.svg?branch=master)](https://travis-ci.org/solson/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/solson/miri?svg=true)](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

View file

@ -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

View file

@ -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);
}

View file

@ -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) }
}

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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;

View file

@ -1,4 +0,0 @@
fn main() {
let data: [u8; 1024] = [42; 1024];
assert_eq!(data.len(), 1024);
}

View file

@ -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);
}

View file

@ -1,2 +0,0 @@
#[inline(never)]
pub fn main() {}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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");
}

View file

@ -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"

View file

@ -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"

View file

@ -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);
}

View file

@ -1,4 +0,0 @@
#[test]
fn bar() {
assert_eq!(4, 4);
}

View file

@ -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))
}
}

View file

@ -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);
}

View file

@ -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(());
}
}

View file

@ -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)
};
}
}

View file

@ -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)
}

View file

@ -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(())
}
}

View file

@ -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)
}
}

View file

@ -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));
}
})
}
}

View file

@ -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
View file

@ -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"

View file

@ -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 = ".." }

View file

@ -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
}

View file

@ -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"

View file

@ -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;

View file

@ -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);
}

View file

@ -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");
}

View file

@ -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
}
}

View file

@ -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));
}

View file

@ -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
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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
}

View file

@ -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);
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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);
}

View file

@ -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));
}
}

View file

@ -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));
}
}

View file

@ -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));
}
}

View file

@ -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);
}

View file

@ -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
}

View file

@ -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);
}
}

View file

@ -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
}
}

View file

@ -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
}

View file

@ -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!() }
}

View file

@ -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 => {},
}
}

View file

@ -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' => {},
_ => {},
}
}

View file

@ -1,5 +0,0 @@
//error-pattern: the evaluated program leaked memory
fn main() {
std::mem::forget(Box::new(42));
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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 }

View file

@ -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 }

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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!()
}
}

View file

@ -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);
}

View file

@ -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 };
}

View file

@ -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()) };
}

View file

@ -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
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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
}
}

View file

@ -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));
}
}

View file

@ -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
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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);
}
}

View file

@ -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