Miri는 Rust용 정의되지 않은 동작 탐지 도구입니다. 화물 프로젝트의 바이너리와 테스트 스위트를 실행하고 안전 요구 사항을 준수하지 못하는 안전하지 않은 코드를 감지할 수 있습니다. 예를 들어:
unreachable_unchecked
에 도달하고, 겹치는 범위로 copy_nonoverlapping
호출하는 등...)bool
또는 잘못된 열거형 판별자) 게다가 Miri는 메모리 누수에 대해서도 알려줄 것입니다. 실행이 끝날 때 메모리가 아직 할당되어 있고 전역 static
에서 해당 메모리에 접근할 수 없으면 Miri는 오류를 발생시킵니다.
Miri를 사용하면 다른 대상의 프로그램을 에뮬레이션할 수 있습니다. 예를 들어 바이트 수준 데이터 조작이 리틀 엔디안 및 빅 엔디안 시스템 모두에서 올바르게 작동하는지 확인할 수 있습니다. 아래의 교차 해석을 참조하세요.
Miri는 이미 실제 버그를 많이 발견했습니다. Miri에서 버그를 발견한 경우 알려주시면 감사하겠습니다. 목록에 추가하겠습니다!
기본적으로 Miri는 완전히 결정적인 실행을 보장하고 프로그램을 호스트 시스템에서 격리합니다. 난수 생성기, 환경 변수 및 시계에 대한 엔트로피 수집과 같이 일반적으로 호스트에 액세스하는 일부 API는 결정론적 "가짜" 구현으로 대체됩니다. 대신 실제 시스템 API에 액세스하려면 MIRIFLAGS="-Zmiri-disable-isolation"
설정하십시오. (특히 "가짜" 시스템 RNG API로 인해 Miri는 암호화 사용에 적합하지 않습니다 ! Miri를 사용하여 키를 생성하지 마세요.)
그렇긴 하지만, Miri가 프로그램의 Rust 사양에 대한 모든 위반을 포착하지는 않는다는 점에 유의하십시오. 특히 그러한 사양이 없기 때문입니다. Miri는 Rust의 정의되지 않은 동작이 무엇인지, 그렇지 않은지에 대한 자체 근사치를 사용합니다. 우리가 아는 한, 프로그램의 정확성에 영향을 미칠 수 있는 모든 정의되지 않은 동작은 Miri(모듈로 버그)에 의해 감지 되지만 정의되지 않은 동작의 공식 정의는 참조 문서를 참조해야 합니다. Miri는 현재 컴파일러에서 이해되는 대로 UB로부터 보호하기 위해 Rust 컴파일러로 업데이트될 예정이지만 Rustc의 향후 버전에 대해서는 약속하지 않습니다.
Miri 사용자가 주의해야 할 추가 주의 사항은 다음과 같습니다.
-Zrandomize-layout
사용하여 이러한 경우 중 일부를 감지할 수 있습니다.)-Zmiri-seed
에 대해 다른 값을 사용하여 Miri를 실행하면 이 문제를 어느 정도 완화할 수 있지만 여전히 가능한 모든 실행을 탐색하지는 않습니다.--target x86_64-unknown-linux-gnu
사용하여 더 나은 지원을 받는 것이 좋습니다.SeqCst
펜스가 사용될 때 Rust 메모리 모델에서 실제로 허용되지 않는 약한 동작을 생성할 수 있으며 실제 하드웨어에서 관찰할 수 있는 모든 동작을 생성할 수 없습니다.더욱이 Miri는 기본적으로 코드가 건전 하다는 것을 보장할 수 없습니다. 건전성은 다른 사운드 코드와 결합하더라도 임의의 안전 코드에서 호출될 때 정의되지 않은 동작을 발생시키지 않는 속성입니다. 이와 대조적으로 Miri는 코드와 상호 작용하는 특정 방식 (예: 테스트 도구 모음)으로 인해 특정 실행에서 정의되지 않은 동작이 발생하는지 여부만 알려줄 수 있습니다(예: 동시성 또는 기타 형태의 비결정론이 있는 경우 등 여러 가지가 있을 수 있음). 참여하고 있습니다). Miri가 UB를 찾으면 코드는 확실히 건전하지 않지만 Miri가 UB를 찾지 못하면 더 많은 입력이나 가능한 비결정적 선택을 테스트해야 할 수도 있습니다.
rustup
통해 밤마다 Rust에 Miri를 설치합니다.
rustup +nightly component add miri
다음 명령은 모두 nightly 툴체인이 rustup override set nightly
통해 고정되어 있다고 가정합니다. 또는 다음 각 명령에 대해 cargo +nightly
를 사용하십시오.
이제 Miri에서 프로젝트를 실행할 수 있습니다.
cargo miri test
사용하세요.cargo miri run
사용하여 Miri를 통해 실행할 수 있습니다.Miri를 처음 실행하면 몇 가지 추가 설정이 수행되고 일부 종속성이 설치됩니다. 아무것도 설치하기 전에 확인을 요청합니다.
cargo miri run/test
cargo run/test
와 정확히 동일한 플래그를 지원합니다. 예를 들어, cargo miri test filter
이름에 filter
포함된 테스트만 실행합니다.
MIRIFLAGS
를 통해 Miri에 플래그를 전달할 수 있습니다. 예를 들어 MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run
참조의 별칭을 확인하지 않고 프로그램을 실행합니다.
cargo miri
통해 코드를 컴파일할 때 Miri에서 해석될 코드에 대해 cfg(miri)
구성 플래그가 설정됩니다. Miri가 지원하지 않는 작업을 수행하기 때문에 Miri에서 실패한 테스트 사례를 무시하는 데 이를 사용할 수 있습니다.
# [ test ]
# [ cfg_attr ( miri , ignore ) ]
fn does_not_work_on_miri ( ) {
tokio :: run ( futures :: future :: ok :: < _ , ( ) > ( ( ) ) ) ;
}
Miri가 할 수 없는 무한한 일을 모두 나열할 방법은 없지만, 지원되지 않는 일을 발견하면 통역사가 명시적으로 알려줄 것입니다.
error: unsupported operation: can't call foreign function: bind
...
= help: this is likely not a bug in the program; it indicates that the program
performed an operation that Miri does not support
Miri는 호스트 대상에 대해 바이너리 또는 테스트 모음을 실행할 수 있을 뿐만 아니라 임의의 외부 대상에 대한 교차 해석도 수행할 수 있습니다. cargo miri run --target x86_64-unknown-linux-gnu
마치 Linux인 것처럼 프로그램을 실행합니다. 프로그램은 호스트 OS에 관계없이 가능합니다. 이는 Windows를 사용하는 경우 특히 유용합니다. Linux 대상이 Windows 대상보다 훨씬 더 잘 지원되기 때문입니다.
이를 사용하여 호스트 플랫폼과 다른 속성을 가진 플랫폼을 테스트할 수도 있습니다. 예를 들어, cargo miri test --target s390x-unknown-linux-gnu
엔디안에 민감한 코드를 테스트하는 데 유용한 빅엔디안 대상에서 테스트 스위트를 실행합니다.
정확한 기본 주소 할당이 저장되고 동시에 실행되는 스레드의 인터리빙과 같이 실행의 특정 부분은 Miri에 의해 무작위로 선택됩니다. 때로는 코드가 새로운 할당의 부수적인 "수퍼 정렬"에 의존하지 않는지 확인하고 다양한 스레드 인터리빙을 테스트하는 등 다양한 실행을 탐색하는 것이 유용할 수 있습니다. 이는 --many-seeds
플래그를 사용하여 수행할 수 있습니다:
cargo miri test --many-seeds # tries the seeds in 0..64
cargo miri test --many-seeds=0..16
64개 시드의 기본값은 매우 느리므로 더 작은 범위를 지정하는 것이 좋습니다.
CI에서 Miri를 실행할 때 다음 코드 조각을 사용하여 Miri 구성 요소가 포함된 야간 툴체인을 설치하세요.
rustup toolchain install nightly --component miri
rustup override set nightly
cargo miri test
다음은 GitHub Actions 작업의 예입니다.
miri :
name : " Miri "
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
- name : Install Miri
run : |
rustup toolchain install nightly --component miri
rustup override set nightly
cargo miri setup
- name : Test with Miri
run : cargo miri test
명시적인 cargo miri setup
실제 테스트 단계의 출력을 깨끗하게 유지하는 데 도움이 됩니다.
Miri는 Rust가 지원하는 모든 대상을 지원하지 않습니다. 그러나 좋은 소식은 호스트 OS/플랫폼에 관계없이 --target
사용하여 모든 대상에 대해 코드를 쉽게 실행할 수 있다는 것입니다!
다음 대상은 CI에서 테스트되었으므로 항상 작동해야 합니다(아래에 문서화된 수준까지).
s390x-unknown-linux-gnu
"선택한 빅엔디안 대상"으로 지원됩니다.linux
, macos
또는 windows
사용하는 다른 모든 대상의 경우 Miri는 일반적으로 작동하지만 그러한 대상에 대해서는 약속하지 않으며 테스트를 실행하지 않습니다.solaris
/ illumos
: @devnexen에서 관리합니다. std::{env, thread, sync}
지원하지만 std::fs
지원하지 않습니다.freebsd
: 관리자를 구했습니다 . std::env
및 std::{thread, fs}
의 일부를 지원하지만 std::sync
지원하지 않습니다.android
: 관리자를 구했습니다 . 지원은 매우 불완전하지만 기본적인 "hello world"는 작동합니다.wasi
: 관리자를 구했습니다 . 매우 불완전한 지원, 심지어 표준 출력도 작동하지 않지만 빈 main
기능은 작동합니다.main
기능에 도달하기도 전에 실패할 수 있습니다.그러나 우리가 지원하는 대상의 경우에도 플랫폼 API(예: 파일 시스템) 액세스에 대한 지원 정도는 대상마다 다릅니다. 일반적으로 Linux 대상이 가장 잘 지원되고 macOS 대상은 일반적으로 동등합니다. Windows는 덜 잘 지원됩니다.
Rust 스레딩을 구현하지만 Miri 자체는 단일 스레드 인터프리터입니다. 이는 cargo miri test
실행할 때 고유한 인터프리터 속도 저하 및 병렬성 손실로 인해 전체 테스트 스위트를 실행하는 데 걸리는 시간이 극적으로 증가하는 것을 볼 수 있음을 의미합니다.
cargo miri nextest run -jN
실행하여 테스트 스위트의 병렬성을 다시 얻을 수 있습니다( cargo-nextest
설치되어 있어야 합니다). 이는 cargo-nextest
모든 테스트 목록을 수집한 다음 각 테스트에 대해 별도의 cargo miri run
시작하기 때문에 작동합니다. -j
또는 --test-threads
지정해야 합니다. 기본적으로 cargo miri nextest run
한 번에 하나의 테스트를 실행합니다. 자세한 내용은 cargo-nextest
Miri 문서를 참고하세요.
참고: 이 프로세스당 하나의 테스트 모델은 cargo miri test
공유 리소스에서 두 테스트가 경쟁하는 데이터 경합을 감지할 수 있지만 cargo miri nextest run
이러한 경합을 감지하지 못한다는 것을 의미합니다.
참고: cargo-nextest
doctest를 지원하지 않습니다. nextest-rs/nextest#16을 참조하세요.
위의 지침을 사용할 때 여러 가지 혼란스러운 컴파일러 오류가 발생할 수 있습니다.
RUST_BACKTRACE=1
환경 변수를 사용하여 실행하세요." Miri가 역추적을 표시하도록 하려고 할 때 이 현상이 나타날 수 있습니다. 기본적으로 Miri는 프로그램에 어떤 환경도 노출하지 않으므로 RUST_BACKTRACE=1 cargo miri test
실행해도 예상한 대로 작동하지 않습니다.
역추적을 얻으려면 -Zmiri-disable-isolation
사용하여 격리를 비활성화해야 합니다.
RUST_BACKTRACE=1 MIRIFLAGS= " -Zmiri-disable-isolation " cargo miri test
std
발견했습니다" Miri가 사용하는 사용자 정의 libstd를 빌드하는 데 사용된 것과 다른 컴파일러 버전으로 cargo miri
실행 중일 수 있으며 Miri는 이를 감지하지 못했습니다. cargo miri clean
실행해 보세요.
-Z
플래그 및 환경 변수 Miri는 일반적으로 MIRIFLAGS
환경 변수를 통해 설정되는 자체 -Z
플래그 세트를 추가합니다. 먼저 가장 관련성이 높고 가장 일반적으로 사용되는 플래그를 문서화합니다.
-Zmiri-address-reuse-rate=
해제된 비스택 할당이 주소 재사용을 위해 풀에 추가될 확률과 풀에서 새로운 비스택 할당이 취해질 확률을 변경합니다. 스택 할당은 풀에 추가되거나 풀에서 가져오지 않습니다. 기본값은 0.5
입니다.-Zmiri-address-reuse-cross-thread-rate=
이전에 해제된 메모리 블록을 재사용하려는 할당이 다른 스레드 에 의해 해제된 블록도 고려할 확률을 변경합니다. 기본값은 0.1
입니다. 이는 기본적으로 주소 재사용 시도가 이루어진 경우의 90%에서 동일한 스레드의 주소만 고려됨을 의미합니다. 다른 스레드의 주소를 재사용하면 해당 스레드 간의 동기화가 유도되어 데이터 경합과 약한 메모리 버그를 가릴 수 있습니다.-Zmiri-compare-exchange-weak-failure-rate=
compare_exchange_weak
작업의 실패율을 변경합니다. 기본값은 0.8
입니다(따라서 약한 작업 5개 중 4개가 실패함). 0.0
에서 1.0
사이의 값으로 변경할 수 있습니다. 여기서 1.0
항상 실패함을 의미하고 0.0
절대 실패하지 않음을 의미합니다. 1.0
으로 설정하면 compare_exchange_weak
사용하는 프로그램이 진행할 수 없으므로 중단될 가능성이 높습니다.-Zmiri-disable-isolation
호스트 격리를 비활성화합니다. 결과적으로 프로그램은 환경 변수, 파일 시스템, 무작위성과 같은 호스트 리소스에 액세스할 수 있습니다.-Zmiri-disable-leak-backtraces
메모리 누수에 대한 역추적 보고서를 비활성화합니다. 기본적으로 누출이 발생할 경우를 대비해 할당이 생성될 때마다 역추적이 캡처됩니다. 거의 사용되지 않는 데이터를 저장하기 위해 약간의 메모리 오버헤드가 발생합니다. 이 플래그는 -Zmiri-ignore-leaks
에 의해 암시됩니다.-Zmiri-env-forward=
var
환경 변수를 해석된 프로그램에 전달합니다. 여러 변수를 전달하기 위해 여러 번 사용할 수 있습니다. 전달된 변수의 값이 동일하게 유지되는 경우 실행은 여전히 결정적입니다. -Zmiri-disable-isolation
이 설정된 경우 효과가 없습니다.-Zmiri-env-set==
해석된 프로그램에서 var
환경 변수를 value
로 설정합니다. 호스트 환경을 변경할 필요 없이 환경 변수를 전달하는 데 사용할 수 있습니다. 여러 변수를 설정하기 위해 여러 번 사용할 수 있습니다. -Zmiri-disable-isolation
또는 -Zmiri-env-forward
설정된 경우 이 옵션으로 설정된 값은 호스트 환경의 값보다 우선합니다.-Zmiri-ignore-leaks
메모리 누수 검사기를 비활성화하고 기본 스레드가 종료될 때 일부 나머지 스레드가 존재하도록 허용합니다.-Zmiri-isolation-error=
격리가 활성화된 동안 호스트 액세스가 필요한 작업에 대한 Miri의 응답을 구성합니다. abort
, hide
, warn
및 warn-nobacktrace
지원되는 작업입니다. 기본값은 abort
이며, 이는 시스템을 정지시킵니다. 전부는 아니지만 일부 작업은 프로그램에 반환되는 "권한 거부" 오류와 함께 계속 실행을 지원합니다. warn
발생할 때마다 전체 역추적을 인쇄합니다. warn-nobacktrace
덜 장황하며 작업당 최대 한 번만 표시됩니다. hide
경고를 완전히 숨깁니다.-Zmiri-num-cpus
miri가 보고할 수 있는 사용 가능한 CPU 수를 나타냅니다. 기본적으로 사용 가능한 CPU 수는 1
입니다. 이 플래그는 miri가 스레드를 처리하는 방식에 어떤 방식으로든 영향을 주지 않습니다.-Zmiri-permissive-provenance
정수-포인터 캐스트 및 ptr::with_exposed_provenance
에 대한 경고를 비활성화합니다. 이러한 작업은 새니타이저에서 효율적이고 정확하게 구현될 수 없기 때문에 일부 버그를 반드시 놓칠 수 있지만 이러한 작업의 대상이 되는 메모리/포인터와 관련된 버그만 놓칠 것입니다.-Zmiri-preemption-rate
기본 블록이 끝날 때 활성 스레드가 선점될 확률을 구성합니다. 기본값은 0.01
(즉, 1%)입니다. 이를 0
으로 설정하면 선점이 비활성화됩니다.-Zmiri-report-progress
사용하면 Miri가 가끔씩 현재 스택 추적을 인쇄하므로 프로그램이 계속 실행될 때 무엇을 하고 있는지 알 수 있습니다. N 기본 블록마다 보고서를 인쇄하는 -Zmiri-report-progress=
통해 보고서 인쇄 빈도를 사용자 정의할 수 있습니다.-Zmiri-seed=
Miri가 비결정성을 해결하는 데 사용하는 RNG의 시드를 구성합니다. 이 RNG는 할당을 위한 기본 주소를 선택하고, compare_exchange_weak
의 선점 및 실패를 확인하고, 약한 메모리 에뮬레이션을 위한 저장소 버퍼링을 제어하는 데 사용됩니다. 격리가 활성화되면(기본값) 시스템 엔트로피를 에뮬레이션하는 데에도 사용됩니다. 기본 시드는 0입니다. 다양한 시드로 Miri를 여러 번 실행하여 테스트 적용 범위를 늘릴 수 있습니다.-Zmiri-strict-provenance
미리에서 엄격한 출처 확인을 가능하게 합니다. 이는 정수를 포인터로 캐스팅하면 '잘못된' 출처, 즉 어떤 메모리 액세스에도 사용할 수 없는 출처의 결과가 생성된다는 것을 의미합니다.-Zmiri-symbolic-alignment-check
정렬 검사를 더욱 엄격하게 만듭니다. 기본적으로 포인터를 정수로 캐스팅하고 그것이 정렬의 배수인지 확인하여 정렬을 확인합니다. 이로 인해 프로그램이 순전히 우연으로 정렬 검사를 통과하는 경우가 발생할 수 있습니다. 왜냐하면 상황이 충분히 정렬되었기 때문입니다. 이 실행에는 UB가 없지만 다른 실행에는 UB가 있을 것입니다. 이러한 경우를 방지하기 위해 기호 정렬 검사에서는 관련 할당에 대해 요청된 정렬과 해당 할당에 대한 오프셋만 고려합니다. 이렇게 하면 이러한 버그가 누락되는 것을 방지할 수 있지만 코드가 정렬을 보장하기 위해 수동 정수 연산을 수행할 때 일부 잘못된 긍정이 발생하기도 합니다. (표준 라이브러리 align_to
메소드는 두 모드 모두에서 잘 작동합니다. 기호 정렬에서는 할당이 충분한 정렬을 보장할 때 중간 슬라이스만 채웁니다.)나머지 플래그는 고급 용도로만 사용되며 변경되거나 제거될 가능성이 높습니다. 이들 중 일부는 건전하지 않습니다 . 이는 Miri가 프로그램에서 정의되지 않은 동작 사례를 감지하지 못하게 할 수 있음을 의미합니다.
-Zmiri-disable-alignment-check
포인터 정렬 검사를 비활성화하므로 다른 오류에 집중할 수 있지만 이는 Miri가 프로그램의 버그를 놓칠 수 있음을 의미합니다. 이 플래그를 사용하는 것은 건전하지 않습니다 .-Zmiri-disable-data-race-detector
데이터 경합 확인을 비활성화합니다. 이 플래그를 사용하는 것은 건전하지 않습니다 . 이는 -Zmiri-disable-weak-memory-emulation
의미합니다.-Zmiri-disable-stacked-borrows
빌림(Stacked Borrows 및 Tree Borrows)을 추적하기 위해 실험적인 앨리어싱 규칙 검사를 비활성화합니다. 이렇게 하면 Miri가 더 빠르게 실행될 수 있지만 앨리어싱 위반이 감지되지 않는다는 의미이기도 합니다. 이 플래그를 사용하는 것은 건전하지 않습니다 (그러나 영향을 받는 건전성 규칙은 실험적입니다). 나중 플래그가 우선합니다. 차용 추적은 -Zmiri-tree-borrows
에 의해 다시 활성화될 수 있습니다.-Zmiri-disable-validation
기본적으로 시행되는 유효성 불변성 시행을 비활성화합니다. 이는 다른 오류(예: 범위를 벗어난 액세스)에 먼저 초점을 맞추는 데 주로 유용합니다. 이 플래그를 설정하면 Miri가 프로그램의 버그를 놓칠 수 있습니다. 그러나 이는 Miri를 더 빠르게 실행하는 데 도움이 될 수도 있습니다. 이 플래그를 사용하는 것은 건전하지 않습니다 .-Zmiri-disable-weak-memory-emulation
일부 C++11 약한 메모리 효과의 에뮬레이션을 비활성화합니다.-Zmiri-native-lib=
는 FFI를 통해 인터프리터 내부에서 네이티브 함수를 호출하기 위한 지원을 제공하기 위한 실험적 플래그입니다. 해당 파일에서 제공되지 않는 기능은 여전히 일반적인 Miri 심을 통해 실행됩니다. 경고 : 유효하지 않거나 잘못된 .so
파일을 지정하면 Miri 자체에서 정의되지 않은 동작이 발생할 수 있습니다! 물론 Miri는 네이티브 코드가 수행하는 작업에 대해 어떠한 검사도 수행할 수 없습니다. Miri에는 파일 설명자를 자체적으로 처리하는 기능이 있으므로 파일 설명자에서 작동하는 일부 기능을 바꾸려면 해당 기능을 모두 바꿔야 합니다. 그렇지 않으면 두 종류의 파일 설명자가 혼합됩니다. 이 작업은 진행 중입니다 . 현재는 정수 인수와 반환 값만 지원됩니다(아니요, 이 제한을 해결하기 위한 포인터/정수 캐스트는 작동하지 않습니다. 끔찍하게 실패합니다). 또한 현재는 Unix 호스트에서만 작동합니다.-Zmiri-measureme=
해석된 프로그램에 대한 measureme
프로파일링을 활성화합니다. 이는 Miri에서 프로그램의 어떤 부분이 느리게 실행되는지 찾는 데 사용할 수 있습니다. 프로필은
이라는 디렉터리 내의 파일에 기록되며 https://github.com/rust-lang/measureme 저장소의 도구를 사용하여 처리할 수 있습니다.-Zmiri-mute-stdout-stderr
stdout 및 stderr에 대한 모든 쓰기를 자동으로 무시하지만 실제로 썼다고 프로그램에 보고합니다. 이는 실제 프로그램의 출력에는 관심이 없고 Miri의 오류와 경고만 보고 싶을 때 유용합니다.-Zmiri-recursive-validation
참조 아래에서 유효성 검사를 반복적으로 수행하는 매우 실험적인 플래그입니다.-Zmiri-retag-fields[=]
Stacked Borrows 태그 재지정이 필드로 반복되는 시기를 제어합니다. all
항상 반복됨을 의미하고(기본값이며 명시적 값이 없는 -Zmiri-retag-fields
와 동일함) none
절대 반복되지 않음을 의미하고, scalar
생성된 LLVM IR에서 noalias
주석을 내보내는 유형에 대해서만 반복됨을 의미합니다( 유형은 개별 스칼라 또는 스칼라 쌍으로 전달됩니다. 이것을 none
으로 설정하는 것은 건전하지 않습니다 .-Zmiri-provenance-gc=
포인터 출처 가비지 수집기가 실행되는 빈도를 구성합니다. 기본값은 10000
기본 블록마다 도달할 수 없는 출처를 검색하고 제거하는 것입니다. 이 값을 0
으로 설정하면 가비지 수집기가 비활성화되어 일부 프로그램에서 폭발적인 메모리 사용량 및/또는 초선형 런타임이 발생하게 됩니다.-Zmiri-track-alloc-accesses
추적된 할당에 대한 할당 및 무료 이벤트뿐만 아니라 읽기 및 쓰기도 표시합니다.-Zmiri-track-alloc-id=,,...
주어진 할당이 할당되거나 해제될 때 역추적을 표시합니다. 이는 메모리 누수를 디버깅하고 무료 버그 이후에 사용하는 데 도움이 됩니다. 이 인수를 여러 번 지정하면 이전 값을 덮어쓰지 않고 대신 해당 값을 목록에 추가합니다. ID를 여러 번 나열해도 아무런 효과가 없습니다.-Zmiri-track-pointer-tag=,,...
주어진 포인터 태그가 생성될 때와 (있는 경우) 빌림 스택(태그가 생성되는 곳)에서 팝될 때 역추적을 표시합니다. 유효하지 않으며 나중에 사용하면 오류가 발생합니다). 이는 UB가 발생하는 이유와 코드에서 이를 찾기에 좋은 위치를 찾는 데 도움이 됩니다. 이 인수를 여러 번 지정하면 이전 값을 덮어쓰지 않고 대신 해당 값을 목록에 추가합니다. 태그를 여러 번 나열해도 아무런 효과가 없습니다.-Zmiri-track-weak-memory-loads
약한 메모리 에뮬레이션이 로드에서 오래된 값을 반환할 때 역추적을 표시합니다. 이는 -Zmiri-disable-weak-memory-emulation
에서 사라지는 문제를 진단하는 데 도움이 될 수 있습니다.-Zmiri-tree-borrows
Stacked Borrows를 Tree Borrows 규칙으로 대체합니다. Tree Borrows는 Stacked Borrows보다 훨씬 더 실험적입니다. Tree Borrows는 현재 버전의 컴파일러가 악용할 수 있는 모든 앨리어싱 위반을 포착한다는 점에서 여전히 건전하지만 Rust의 최종 최종 앨리어싱 모델은 Tree Borrows보다 더 엄격할 가능성이 높습니다. 즉, Tree Borrows를 사용하면 오늘 코드가 승인되더라도 나중에 UB로 선언될 수 있습니다. Stacked Borrows에서는 이런 일이 발생할 가능성이 훨씬 적습니다.-Zmiri-force-page-size=
아키텍처의 기본 페이지 크기를 1k의 배수로 재정의합니다. 대부분의 대상에서는 4
기본값입니다. 이 값은 항상 2의 거듭제곱이어야 하며 0이 아니어야 합니다.-Zmiri-unique-is-unique
core::ptr::Unique
에 대한 추가 앨리어싱 검사를 수행하여 이론적으로 noalias
로 간주될 수 있는지 확인합니다. 이 플래그는 실험적이며 -Zmiri-tree-borrows
와 함께 사용될 때만 효과가 있습니다. 일부 기본 Rustc -Z
플래그도 Miri와 매우 관련이 있습니다.
-Zmir-opt-level
수행되는 MIR 최적화 횟수를 제어합니다. Miri는 기본값을 0
으로 재정의합니다. 더 높은 수준을 사용하면 Miri가 최적화되었기 때문에 프로그램의 버그를 놓칠 수 있다는 점에 유의하세요.-Zalways-encode-mir
완전한 단일형 기능에 대해서도 Rustc 덤프 MIR을 만듭니다. 이는 Miri가 이러한 기능을 실행할 수 있도록 하기 위해 필요하므로 Miri는 기본적으로 이 플래그를 설정합니다.-Zmir-emit-retag
Retag
문을 내보낼지 여부를 제어합니다. Miri는 Stacked Borrows 및 Tree Borrows에 필요하기 때문에 기본적으로 이 기능을 활성화합니다.또한 Miri는 일부 환경 변수를 인식합니다.
MIRIFLAGS
Miri에 전달될 추가 플래그를 정의합니다.MIRI_LIB_SRC
Miri가 해석을 위해 구축하고 사용할 표준 라이브러리의 소스를 예상하는 디렉터리를 정의합니다. 이 디렉터리는 rust-lang/rust
저장소 체크아웃의 library
하위 디렉터리를 가리켜야 합니다.MIRI_SYSROOT
사용할 sysroot를 나타냅니다. cargo miri test
/ cargo miri run
사용할 때 자동 설정을 건너뜁니다. 자동으로 생성된 sysroot를 사용하지 않으려는 경우에만 설정하십시오. cargo miri setup
호출할 때 이는 sysroot가 배치될 위치를 나타냅니다.MIRI_NO_STD
대상의 sysroot가 libstd 없이 빌드되었는지 확인합니다. 이를 통해 no_std 프로그램을 테스트하고 실행할 수 있습니다. 이것은 일반적으로 사용되어서는 안 됩니다. Miri에는 대상 이름을 기반으로 표준이 아닌 대상을 탐지하는 경험적 방법이 있습니다. libstd를 지원하는 대상에 이를 설정하면 혼란스러운 결과가 발생할 수 있습니다. extern
기능 Miri는 프로그램이 Miri 관련 기능에 액세스하기 위해 가져올 수 있는 몇 가지 extern
기능을 제공합니다. /tests/utils/miri_extern.rs에 선언되어 있습니다.
표준 라이브러리를 사용하지 않는 바이너리는 Miri가 실행을 시작할 위치를 알 수 있도록 다음과 같은 함수를 선언해야 합니다.
# [ cfg ( miri ) ]
# [ no_mangle ]
fn miri_start ( argc : isize , argv : * const * const u8 ) -> isize {
// Call the actual start function that your project implements, based on your target's conventions.
}
Miri에 기여하고 싶다면 좋습니다! 기여 가이드를 확인해 보세요.
Miri 실행에 대한 도움이 필요하면 여기 GitHub에서 문제를 열거나 Rust Zulip에서 Miri 스트림을 사용할 수 있습니다.
이 프로젝트는 2015년 서스캐처원 대학교 @solson의 학부 연구 과정의 일부로 시작되었습니다. 해당 프로젝트에서 사용할 수 있는 슬라이드와 보고서가 있습니다. 2016년에 @oli-obk는 Miri가 결국 Rust 컴파일러 자체(기본적으로 const
및 static
항목의 경우)에서 const 평가자로 사용될 수 있도록 준비하기 위해 합류했으며, AST에서 직접 작동했던 이전 평가기를 대체했습니다. 2017년에 @RalfJung은 Mozilla에서 인턴십을 하면서 정의되지 않은 동작을 감지하는 도구로 Miri를 개발하기 시작했으며, Rust에서 정의되지 않은 동작에 대해 가능한 다양한 정의의 결과를 탐색하는 방법으로 Miri를 사용하기 시작했습니다. @oli-obk의 Miri 엔진을 컴파일러로 이전하는 작업은 마침내 2018년 초에 완료되었습니다. 한편, 그 해 말에 @RalfJung은 두 번째 인턴십을 수행하여 기본 유형 불변성을 확인하고 참조가 그에 따라 사용되는지 확인하는 지원을 통해 Miri를 더욱 발전시켰습니다. 앨리어싱 제한 사항.
Miri는 이미 Rust 표준 라이브러리와 그 이상에서 많은 버그를 발견했으며 그 중 일부는 여기에서 수집됩니다. Miri가 코드에서 미묘한 UB 버그를 찾는 데 도움을 주었다면 해당 버그를 목록에 추가해 주시면 감사하겠습니다!
확실한 버그가 발견되었습니다:
Debug for vec_deque::Iter
Vec::into_iter
정렬되지 않은 ZST 읽기를 수행하고 있습니다.From<&[T]> for Rc
BTreeMap
Vec::append
str
공유 참조를 변경 가능한 참조로 전환rand
posix_memalign
호출하는 Unix 할당자getrandom
잘못된 방식으로 getrandom
syscall을 호출합니다.Vec
및 BTreeMap
메모리 누수beef
누출 메모리EbrCell
servo_arc
매달린 공유 참조 생성encoding_rs
Vec::from_raw_parts
잘못 사용하는 TiKVAtomicPtr
및 Box::from_raw_in
에 대한 잘못된 doctestThinVec
의 정렬이 불충분함MaybeUninit
에서 assume_init
호출하는 crossbeam-epoch
integer-encoding
Box<[u8]>
생성하는 rkyv
arc-swap
의 데이터 경쟁thread::scope
의 데이터 경쟁Vec
버퍼를 잘못 처리하는 regex
once_cell
에서 compare_exchange_weak
의 잘못된 사용vec::IntoIter
에서 정렬되지 않은 포인터로 삭제Iterator::collect
에 대한 새로운 전문화에서 잘못된 레이아웃으로 할당 해제portable-atomic-util
에서 고도로 정렬된 유형에 대한 잘못된 오프셋 계산std::mpsc
채널에서 가끔 메모리 누수가 발생합니다(크로스빔의 원본 코드).버그일 가능성이 있는 Stacked Borrows 위반이 발견되었습니다(그러나 Stacked Borrows는 현재 단지 실험일 뿐입니다).
VecDeque::drain
겹치는 가변 참조를 생성함BTreeMap
문제BTreeMap
반복자BTreeMap::iter_mut
중복되는 변경 가능한 참조 생성BTreeMap
노드 삽입LinkedList
커서 삽입Vec::push
기존 참조를 벡터에 무효화align_to_mut
변경 가능한 참조의 고유성을 위반합니다.sized-chunks
String::push_str
문자열에 대한 기존 참조를 무효화합니다.ryu
유효한 메모리 영역 밖에서 원시 포인터를 사용합니다.Env
반복자VecDeque::iter_mut
중복되는 변경 가능한 참조 생성<[T]>::copy_within
대출 무효화 후 사용 다음 중 하나에 따라 라이선스가 부여됨
귀하의 선택에 따라.
귀하가 명시적으로 달리 명시하지 않는 한, 귀하가 저작물에 포함하기 위해 의도적으로 제출한 모든 기여는 추가 조건 없이 위와 같이 이중 라이센스가 부여됩니다.