Miri ist ein Tool zur Erkennung undefinierten Verhaltens für Rust. Es kann Binärdateien ausführen und Suiten von Frachtprojekten testen und unsicheren Code erkennen, der seine Sicherheitsanforderungen nicht erfüllt. Zum Beispiel:
unreachable_unchecked
wird erreicht, Aufruf von copy_nonoverlapping
mit überlappenden Bereichen, ...)bool
, der nicht 0 oder 1 ist, oder eine ungültige Enum-Diskriminante) Darüber hinaus informiert Sie Miri auch über Speicherlecks: Wenn am Ende der Ausführung noch Speicher zugewiesen ist und dieser Speicher nicht über ein globales static
erreichbar ist, löst Miri einen Fehler aus.
Sie können Miri verwenden, um Programme auf anderen Zielen zu emulieren, um beispielsweise sicherzustellen, dass die Datenmanipulation auf Byte-Ebene sowohl auf Little-Endian- als auch auf Big-Endian-Systemen korrekt funktioniert. Siehe Kreuzinterpretation unten.
Miri hat bereits viele echte Fehler entdeckt. Wenn Sie einen Fehler in Miri gefunden haben, würden wir uns freuen, wenn Sie ihn uns mitteilen, und wir werden ihn der Liste hinzufügen!
Standardmäßig gewährleistet Miri eine vollständig deterministische Ausführung und isoliert das Programm vom Hostsystem. Einige APIs, die normalerweise auf den Host zugreifen würden, wie etwa das Sammeln von Entropie für Zufallszahlengeneratoren, Umgebungsvariablen und Uhren, werden durch deterministische „falsche“ Implementierungen ersetzt. Legen Sie MIRIFLAGS="-Zmiri-disable-isolation"
fest, um stattdessen auf die echten System-APIs zuzugreifen. (Insbesondere aufgrund der „gefälschten“ System-RNG-APIs ist Miri nicht für den kryptografischen Einsatz geeignet ! Generieren Sie keine Schlüssel mit Miri.)
Beachten Sie jedoch, dass Miri nicht jeden Verstoß gegen die Rust-Spezifikation in Ihrem Programm erkennt , nicht zuletzt, weil es keine solche Spezifikation gibt. Miri verwendet eine eigene Annäherung an das, was in Rust undefiniertes Verhalten ist und was nicht. Nach unserem besten Wissen wird jedes undefinierte Verhalten, das möglicherweise die Korrektheit eines Programms beeinträchtigt, von Miri erkannt (Modulo-Fehler). Die offizielle Definition von undefiniertem Verhalten finden Sie jedoch in der Referenz. Miri wird mit dem Rust-Compiler aktualisiert, um vor UB zu schützen, wie es vom aktuellen Compiler verstanden wird, es gibt jedoch keine Zusagen über zukünftige Versionen von rustc.
Weitere Vorbehalte, die Miri-Benutzer beachten sollten:
-Zrandomize-layout
verwenden, um einige dieser Fälle zu erkennen.)-Zmiri-seed
ausführen, aber damit werden bei weitem nicht alle möglichen Ausführungen untersucht.--target x86_64-unknown-linux-gnu
zu verwenden, um eine bessere Unterstützung zu erhalten.SeqCst
Zäune verwendet werden, die vom Rust-Speichermodell eigentlich nicht zugelassen werden, und sie kann nicht alle Verhaltensweisen hervorrufen, die möglicherweise auf echter Hardware beobachtbar sind.Darüber hinaus kann Miri grundsätzlich nicht garantieren, dass Ihr Code korrekt ist. Unter Solidität versteht man die Eigenschaft, beim Aufruf aus beliebigem sicheren Code niemals undefiniertes Verhalten hervorzurufen, auch nicht in Kombination mit anderem Soundcode. Im Gegensatz dazu kann Miri Ihnen einfach sagen, ob eine bestimmte Art der Interaktion mit Ihrem Code (z. B. eine Testsuite) ein undefiniertes Verhalten in einer bestimmten Ausführung verursacht (von denen es viele geben kann, z. B. bei Parallelität oder anderen Formen des Nichtdeterminismus). beteiligt sind). Wenn Miri UB findet, ist Ihr Code definitiv fehlerhaft, aber wenn Miri UB nicht findet, müssen Sie möglicherweise einfach mehr Eingaben oder mehr mögliche nichtdeterministische Entscheidungen testen.
Installiere Miri jeden Abend über rustup
auf Rust:
rustup +nightly component add miri
Bei allen folgenden Befehlen wird davon ausgegangen, dass die Nightly-Toolchain über rustup override set nightly
fixiert ist. Alternativ können Sie für jeden der folgenden Befehle cargo +nightly
verwenden.
Jetzt können Sie Ihr Projekt in Miri ausführen:
cargo miri test
.cargo miri run
über Miri ausführen.Wenn Sie Miri zum ersten Mal ausführen, werden einige zusätzliche Setups durchgeführt und einige Abhängigkeiten installiert. Sie werden vor der Installation um eine Bestätigung gebeten.
cargo miri run/test
unterstützt genau die gleichen Flags wie cargo run/test
. Beispielsweise führt cargo miri test filter
nur die Tests aus, deren Name filter
enthält.
Über MIRIFLAGS
können Sie Flaggen an Miri übergeben. Beispielsweise führt MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run
das Programm aus, ohne das Aliasing von Referenzen zu überprüfen.
Beim Kompilieren von Code über cargo miri
wird das Konfigurationsflag cfg(miri)
für Code gesetzt, der unter Miri interpretiert wird. Damit können Sie Testfälle ignorieren, die unter Miri fehlschlagen, weil sie Dinge tun, die Miri nicht unterstützt:
# [ test ]
# [ cfg_attr ( miri , ignore ) ]
fn does_not_work_on_miri ( ) {
tokio :: run ( futures :: future :: ok :: < _ , ( ) > ( ( ) ) ) ;
}
Es gibt keine Möglichkeit, alle unendlichen Dinge aufzulisten, die Miri nicht kann, aber der Interpreter wird Sie explizit darauf hinweisen, wenn er etwas findet, das nicht unterstützt wird:
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 kann nicht nur eine Binär- oder Testsuite für Ihr Host-Ziel ausführen, sondern auch eine Kreuzinterpretation für beliebige fremde Ziele durchführen: cargo miri run --target x86_64-unknown-linux-gnu
führt Ihr Programm aus, als wäre es ein Linux Programm, unabhängig von Ihrem Host-Betriebssystem. Dies ist besonders nützlich, wenn Sie Windows verwenden, da das Linux-Ziel viel besser unterstützt wird als Windows-Ziele.
Sie können damit auch Plattformen testen, deren Eigenschaften sich von Ihrer Host-Plattform unterscheiden. Zum Beispiel führt cargo miri test --target s390x-unknown-linux-gnu
Ihre Testsuite auf einem Big-Endian-Ziel aus, was zum Testen von Endian-sensitivem Code nützlich ist.
Bestimmte Teile der Ausführung werden von Miri zufällig ausgewählt, z. B. die genauen Basisadressenzuordnungen, unter denen gespeichert wird, und die Verschachtelung gleichzeitig ausgeführter Threads. Manchmal kann es nützlich sein, mehrere unterschiedliche Ausführungen zu untersuchen, um beispielsweise sicherzustellen, dass Ihr Code nicht von einer zufälligen „Superausrichtung“ neuer Zuweisungen abhängt, und um verschiedene Thread-Interleavings zu testen. Dies kann mit der Flagge --many-seeds
erfolgen:
cargo miri test --many-seeds # tries the seeds in 0..64
cargo miri test --many-seeds=0..16
Die Standardeinstellung von 64 verschiedenen Seeds ist ziemlich langsam, daher möchten Sie wahrscheinlich einen kleineren Bereich angeben.
Wenn Sie Miri auf CI ausführen, verwenden Sie das folgende Snippet, um eine Nightly-Toolchain mit der Miri-Komponente zu installieren:
rustup toolchain install nightly --component miri
rustup override set nightly
cargo miri test
Hier ist ein Beispieljob für 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
Das explizite cargo miri setup
trägt dazu bei, die Ausgabe des eigentlichen Testschritts sauber zu halten.
Miri unterstützt nicht alle von Rust unterstützten Ziele. Die gute Nachricht ist jedoch, dass es unabhängig von Ihrem Host-Betriebssystem/Ihrer Host-Plattform einfach ist, Code für jedes Ziel mit --target
auszuführen!
Die folgenden Ziele werden auf CI getestet und sollten daher immer funktionieren (im unten dokumentierten Umfang):
s390x-unknown-linux-gnu
wird als unser „Big-Endian-Ziel der Wahl“ unterstützt.linux
, macos
oder windows
sollte Miri im Allgemeinen funktionieren, aber wir machen keine Versprechungen und führen keine Tests für solche Ziele durch.solaris
/ illumos
: gepflegt von @devnexen. Unterstützt std::{env, thread, sync}
, aber nicht std::fs
.freebsd
: Betreuer gesucht . Unterstützt std::env
und Teile von std::{thread, fs}
, jedoch nicht std::sync
.android
: Betreuer gesucht . Unterstützung sehr unvollständig, aber ein grundlegendes „Hallo Welt“ funktioniert.wasi
: Betreuer gesucht . Unterstützung sehr unvollständig, nicht einmal die Standardausgabe funktioniert, aber eine leere main
funktioniert.main
überhaupt erreicht wird.Doch selbst bei Zielen, die wir unterstützen, unterscheidet sich der Grad der Unterstützung für den Zugriff auf Plattform-APIs (z. B. das Dateisystem) zwischen den Zielen: Im Allgemeinen bieten Linux-Ziele die beste Unterstützung, und macOS-Ziele sind in der Regel gleichwertig. Windows wird weniger gut unterstützt.
Obwohl es Rust-Threading implementiert, ist Miri selbst ein Single-Threaded-Interpreter. Das bedeutet, dass Sie beim Ausführen cargo miri test
aufgrund der inhärenten Verlangsamung des Interpreters und des Verlusts der Parallelität wahrscheinlich einen dramatischen Anstieg der Zeit feststellen werden, die zum Ausführen Ihrer gesamten Testsuite benötigt wird.
Sie können die Parallelität Ihrer Testsuite wiederherstellen, indem Sie cargo miri nextest run -jN
ausführen (beachten Sie, dass Sie cargo-nextest
installiert haben müssen). Dies funktioniert, weil cargo-nextest
eine Liste aller Tests sammelt und dann für jeden Test einen separaten cargo miri run
startet. Sie müssen ein -j
oder --test-threads
angeben; Standardmäßig führt cargo miri nextest run
jeweils einen Test aus. Weitere Einzelheiten finden Sie in der Dokumentation cargo-nextest
Miri“.
Hinweis: Dieses Ein-Test-pro-Prozess-Modell bedeutet, dass cargo miri test
in der Lage ist, Datenrennen zu erkennen, bei denen zwei Tests auf einer gemeinsamen Ressource laufen, cargo miri nextest run
jedoch solche Rennen nicht erkennt.
Hinweis: cargo-nextest
unterstützt keine Doctests, siehe nextest-rs/nextest#16
Wenn Sie die obigen Anweisungen verwenden, können einige verwirrende Compilerfehler auftreten.
RUST_BACKTRACE=1
ausführen, um einen Backtrace anzuzeigen.“ Dies kann passieren, wenn Sie versuchen, Miri dazu zu bringen, einen Backtrace anzuzeigen. Standardmäßig stellt Miri dem Programm keine Umgebung zur Verfügung, daher führt die Ausführung RUST_BACKTRACE=1 cargo miri test
nicht zu dem, was Sie erwarten.
Um einen Backtrace zu erhalten, müssen Sie die Isolation mit -Zmiri-disable-isolation
deaktivieren:
RUST_BACKTRACE=1 MIRIFLAGS= " -Zmiri-disable-isolation " cargo miri test
std
gefunden, das mit einer inkompatiblen Version von rustc kompiliert wurde“ Möglicherweise führen Sie cargo miri
mit einer anderen Compilerversion aus als der, die zum Erstellen der benutzerdefinierten libstd verwendet wurde, die Miri verwendet, und Miri konnte dies nicht erkennen. Versuchen Sie, cargo miri clean
auszuführen.
-Z
Flags und Umgebungsvariablen Miri fügt seinen eigenen Satz von -Z
Flags hinzu, die normalerweise über die Umgebungsvariable MIRIFLAGS
gesetzt werden. Wir dokumentieren zunächst die relevantesten und am häufigsten verwendeten Flags:
-Zmiri-address-reuse-rate=
ändert die Wahrscheinlichkeit, dass eine freigegebene Nicht-Stack -Zuweisung zum Pool zur Adresswiederverwendung hinzugefügt wird, und die Wahrscheinlichkeit, dass eine neue Nicht-Stack -Zuweisung aus dem Pool entnommen wird. Stapelzuweisungen werden niemals zum Pool hinzugefügt oder daraus entnommen. Der Standardwert ist 0.5
.-Zmiri-address-reuse-cross-thread-rate=
ändert die Wahrscheinlichkeit, dass eine Zuweisung, die versucht, einen zuvor freigegebenen Speicherblock wiederzuverwenden, auch von anderen Threads freigegebene Blöcke berücksichtigt. Der Standardwert ist 0.1
, was bedeutet, dass standardmäßig in 90 % der Fälle, in denen ein Adresswiederverwendungsversuch unternommen wird, nur Adressen aus demselben Thread berücksichtigt werden. Die Wiederverwendung einer Adresse aus einem anderen Thread induziert eine Synchronisierung zwischen diesen Threads, wodurch Datenrennen und schwache Speicherfehler maskiert werden können.-Zmiri-compare-exchange-weak-failure-rate=
ändert die Fehlerrate von compare_exchange_weak
Vorgängen. Der Standardwert ist 0.8
(also schlagen 4 von 5 schwachen Operationen fehl). Sie können ihn auf einen beliebigen Wert zwischen 0.0
und 1.0
ändern, wobei 1.0
bedeutet, dass es immer fehlschlägt, und 0.0
bedeutet, dass es nie fehlschlägt. Beachten Sie, dass die Einstellung auf 1.0
wahrscheinlich zu Hängen führt, da dies bedeutet, dass Programme, compare_exchange_weak
verwenden, keinen Fortschritt machen können.-Zmiri-disable-isolation
deaktiviert die Host-Isolation. Dadurch hat das Programm Zugriff auf Hostressourcen wie Umgebungsvariablen, Dateisysteme und Zufälligkeit.-Zmiri-disable-leak-backtraces
deaktiviert Backtraces-Berichte für Speicherlecks. Standardmäßig wird für jede Zuordnung bei der Erstellung ein Backtrace erfasst, für den Fall, dass etwas verloren geht. Dadurch entsteht ein gewisser Speicheraufwand für die Speicherung von Daten, die fast nie verwendet werden. Dieses Flag wird durch -Zmiri-ignore-leaks
impliziert.-Zmiri-env-forward=
leitet die Umgebungsvariable var
an das interpretierte Programm weiter. Kann mehrfach verwendet werden, um mehrere Variablen weiterzuleiten. Die Ausführung ist weiterhin deterministisch, wenn der Wert der weitergeleiteten Variablen gleich bleibt. Hat keine Auswirkung, wenn -Zmiri-disable-isolation
gesetzt ist.-Zmiri-env-set==
setzt die Umgebungsvariable var
im interpretierten Programm auf value
. Es kann zur Übergabe von Umgebungsvariablen verwendet werden, ohne dass die Hostumgebung geändert werden muss. Es kann mehrfach verwendet werden, um mehrere Variablen festzulegen. Wenn -Zmiri-disable-isolation
oder -Zmiri-env-forward
festgelegt ist, haben mit dieser Option festgelegte Werte Vorrang vor Werten aus der Hostumgebung.-Zmiri-ignore-leaks
deaktiviert die Speicherleckprüfung und lässt auch zu, dass einige verbleibende Threads bestehen bleiben, wenn der Hauptthread beendet wird.-Zmiri-isolation-error=
konfiguriert Miris Reaktion auf Vorgänge, die Hostzugriff erfordern, während die Isolation aktiviert ist. abort
, hide
, warn
und warn-nobacktrace
sind die unterstützten Aktionen. Die Standardeinstellung ist abort
, wodurch die Maschine angehalten wird. Einige (aber nicht alle) Vorgänge unterstützen auch die Fortsetzung der Ausführung mit der Fehlermeldung „Berechtigung verweigert“, die an das Programm zurückgegeben wird. warn
druckt jedes Mal einen vollständigen Backtrace, wenn das passiert; warn-nobacktrace
ist weniger ausführlich und wird höchstens einmal pro Vorgang angezeigt. hide
verbirgt die Warnung vollständig.-Zmiri-num-cpus
gibt die Anzahl der verfügbaren CPUs an, die von miri gemeldet werden sollen. Standardmäßig beträgt die Anzahl der verfügbaren CPUs 1
. Beachten Sie, dass dieses Flag keinerlei Einfluss darauf hat, wie Miri Threads verarbeitet.-Zmiri-permissive-provenance
deaktiviert die Warnung für Ganzzahl-zu-Zeiger-Umwandlungen und ptr::with_exposed_provenance
. Dadurch werden zwangsläufig einige Fehler übersehen, da diese Vorgänge in einem Sanitizer nicht effizient und genau implementiert werden können. Es werden jedoch nur Fehler übersehen, die den Speicher/Zeiger betreffen, der diesen Vorgängen unterliegt.-Zmiri-preemption-rate
konfiguriert die Wahrscheinlichkeit, dass am Ende eines Basisblocks der aktive Thread vorbelegt wird. Der Standardwert ist 0.01
(dh 1 %). Wenn Sie diesen Wert auf 0
setzen, wird die Vorbelegung deaktiviert.-Zmiri-report-progress
lässt Miri hin und wieder den aktuellen Stacktrace drucken, sodass Sie erkennen können, was es tut, wenn ein Programm einfach weiterläuft. Sie können anpassen, wie oft der Bericht gedruckt wird, indem Sie -Zmiri-report-progress=
verwenden, wodurch der Bericht alle N Basisblöcke gedruckt wird.-Zmiri-seed=
konfiguriert den Seed des RNG, den Miri zur Auflösung von Nichtdeterminismus verwendet. Dieser RNG wird verwendet, um Basisadressen für Zuweisungen auszuwählen, um Vorrang und Fehler von compare_exchange_weak
zu bestimmen und um die Speicherpufferung für die schwache Speicheremulation zu steuern. Wenn die Isolation aktiviert ist (Standardeinstellung), wird diese auch zur Emulation der Systementropie verwendet. Der Standard-Seed ist 0. Sie können die Testabdeckung erhöhen, indem Sie Miri mehrmals mit unterschiedlichen Seeds ausführen.-Zmiri-strict-provenance
ermöglicht eine strenge Provenienzprüfung in Miri. Dies bedeutet, dass die Umwandlung einer Ganzzahl in einen Zeiger ein Ergebnis mit „ungültiger“ Herkunft ergibt, dh mit einer Herkunft, die für keinen Speicherzugriff verwendet werden kann.-Zmiri-symbolic-alignment-check
macht die Ausrichtungsprüfung strenger. Standardmäßig wird die Ausrichtung überprüft, indem der Zeiger in eine Ganzzahl umgewandelt wird und sichergestellt wird, dass es sich um ein Vielfaches der Ausrichtung handelt. Dies kann zu Fällen führen, in denen ein Programm die Ausrichtungsprüfung rein zufällig besteht, weil die Dinge „zufällig“ ausreichend ausgerichtet waren – in dieser Ausführung gibt es kein UB, in anderen jedoch UB. Um solche Fälle zu vermeiden, berücksichtigt die symbolische Ausrichtungsprüfung nur die angeforderte Ausrichtung der relevanten Zuordnung und den Offset in dieser Zuordnung. Dadurch wird vermieden, dass solche Fehler übersehen werden, es kommt aber auch zu einigen Fehlalarmen, wenn der Code manuelle Ganzzahlarithmetik durchführt, um die Ausrichtung sicherzustellen. (Die Standardbibliotheksmethode align_to
funktioniert in beiden Modi einwandfrei; bei symbolischer Ausrichtung füllt sie nur das mittlere Segment, wenn die Zuweisung eine ausreichende Ausrichtung gewährleistet.)Die übrigen Flags dienen nur der erweiterten Verwendung und können sich mit größerer Wahrscheinlichkeit ändern oder entfernt werden. Einige davon sind fehlerhaft , was bedeutet, dass sie dazu führen können, dass Miri Fälle von undefiniertem Verhalten in einem Programm nicht erkennt.
-Zmiri-disable-alignment-check
deaktiviert die Überprüfung der Zeigerausrichtung, sodass Sie sich auf andere Fehler konzentrieren können. Dies bedeutet jedoch, dass Miri Fehler in Ihrem Programm übersehen kann. Die Verwendung dieses Flags ist unzulässig .-Zmiri-disable-data-race-detector
deaktiviert die Überprüfung auf Datenrennen. Die Verwendung dieses Flags ist unzulässig . Dies impliziert -Zmiri-disable-weak-memory-emulation
.-Zmiri-disable-stacked-borrows
deaktiviert die Überprüfung der experimentellen Aliasing-Regeln zur Verfolgung von Ausleihen (Stacked Borrows und Tree Borrows). Dies kann dazu führen, dass Miri schneller läuft, es bedeutet aber auch, dass keine Aliasing-Verstöße erkannt werden. Die Verwendung dieses Flags ist unzumutbar (aber die betroffenen Plausibilitätsregeln sind experimenteller Natur). Spätere Flags haben Vorrang: Die Leihverfolgung kann durch -Zmiri-tree-borrows
reaktiviert werden.-Zmiri-disable-validation
deaktiviert die Durchsetzung von Gültigkeitsinvarianten, die standardmäßig erzwungen werden. Dies ist vor allem nützlich, um sich zunächst auf andere Fehler (z. B. Zugriffe außerhalb der Grenzen) zu konzentrieren. Wenn Sie dieses Flag setzen, kann Miri Fehler in Ihrem Programm übersehen. Dies kann jedoch auch dazu beitragen, dass Miri schneller läuft. Die Verwendung dieses Flags ist unzulässig .-Zmiri-disable-weak-memory-emulation
deaktiviert die Emulation einiger C++11-Schwachspeichereffekte.-Zmiri-native-lib=
ist ein experimentelles Flag zur Bereitstellung von Unterstützung für den Aufruf nativer Funktionen aus dem Interpreter heraus über FFI. Funktionen, die von dieser Datei nicht bereitgestellt werden, werden weiterhin über die üblichen Miri-Shims ausgeführt. WARNUNG : Wenn eine ungültige/falsche .so
Datei angegeben wird, kann dies zu undefiniertem Verhalten in Miri selbst führen! Und natürlich kann Miri die vom nativen Code ausgeführten Aktionen nicht überprüfen. Beachten Sie, dass Miri über eine eigene Handhabung von Dateideskriptoren verfügt. Wenn Sie also einige Funktionen ersetzen möchten, die mit Dateideskriptoren arbeiten, müssen Sie alle ersetzen, da sonst die beiden Arten von Dateideskriptoren verwechselt werden. Dies ist in Arbeit ; Derzeit werden nur Ganzzahlargumente und Rückgabewerte unterstützt (und nein, Zeiger-/Ganzzahlumwandlungen zur Umgehung dieser Einschränkung funktionieren nicht; sie werden schrecklich fehlschlagen). Es funktioniert derzeit auch nur auf Unix-Hosts.-Zmiri-measureme=
aktiviert measureme
für das interpretierte Programm. Damit können Sie herausfinden, welche Teile Ihres Programms unter Miri langsam ausgeführt werden. Das Profil wird in eine Datei in einem Verzeichnis namens
geschrieben und kann mit den Tools im Repository https://github.com/rust-lang/measureme verarbeitet werden.-Zmiri-mute-stdout-stderr
ignoriert stillschweigend alle Schreibvorgänge auf stdout und stderr, meldet dem Programm jedoch, dass tatsächlich geschrieben wurde. Dies ist nützlich, wenn Sie nicht an der eigentlichen Programmausgabe interessiert sind, sondern nur Miris Fehler und Warnungen sehen möchten.-Zmiri-recursive-validation
ist ein äußerst experimentelles Flag, das die Gültigkeitsprüfung unter Referenzen rekursiv macht.-Zmiri-retag-fields[=]
steuert, wann das Retagging gestapelter Ausleihen in Felder rekursiv erfolgt. all
bedeutet, dass es immer rekursiv erfolgt (die Standardeinstellung und entspricht -Zmiri-retag-fields
ohne expliziten Wert), none
bedeutet, dass es nie rekursiv erfolgt, scalar
bedeutet, dass es nur für Typen rekursiv ist, bei denen wir auch noalias
-Anmerkungen in der generierten LLVM-IR ausgeben würden ( Typen, die als einzelne Skalare oder Skalarpaare übergeben werden). Dies auf none
zu setzen, ist unzutreffend .-Zmiri-provenance-gc=
konfiguriert, wie oft der Zeiger-Provenance-Garbage Collector ausgeführt wird. Standardmäßig wird alle 10000
Basisblöcke nach unerreichbarer Herkunft gesucht und diese entfernt. Wenn Sie diesen Wert auf 0
setzen, wird der Garbage Collector deaktiviert, was bei einigen Programmen zu einer explosionsartigen Speicherauslastung und/oder einer superlinearen Laufzeit führt.-Zmiri-track-alloc-accesses
zeigt nicht nur Zuweisungs- und freie Ereignisse für verfolgte Zuteilungen, sondern auch Lese- und Schreibvorgänge.-Zmiri-track-alloc-id=,,...
zeigt einen Backtrace an, wenn die angegebenen Zuweisungen zugewiesen oder freigegeben werden. Dies hilft beim Debuggen von Speicherlecks und bei der Verwendung nach kostenlosen Fehlern. Wenn Sie dieses Argument mehrmals angeben, werden die vorherigen Werte nicht überschrieben, sondern die Werte werden stattdessen an die Liste angehängt. Das mehrfache Angeben einer ID hat keine Auswirkung.-Zmiri-track-pointer-tag=,,...
zeigt einen Backtrace an, wenn ein bestimmtes Zeiger-Tag erstellt wird und wenn es (falls überhaupt) von einem Borrow-Stack entfernt wird (dort wird das Tag gespeichert). ungültig und jede zukünftige Verwendung führt zu Fehlern). Dies hilft Ihnen herauszufinden, warum UB auftritt und wo in Ihrem Code ein guter Ort wäre, um danach zu suchen. Wenn Sie dieses Argument mehrmals angeben, werden die vorherigen Werte nicht überschrieben, sondern die Werte werden stattdessen an die Liste angehängt. Das mehrfache Auflisten eines Tags hat keine Auswirkung.-Zmiri-track-weak-memory-loads
zeigt einen Backtrace an, wenn die schwache Speicheremulation einen veralteten Wert von einem Ladevorgang zurückgibt. Dies kann bei der Diagnose von Problemen helfen, die unter -Zmiri-disable-weak-memory-emulation
verschwinden.-Zmiri-tree-borrows
ersetzt Stacked Borrows durch die Tree Borrows-Regeln. Tree Borrows ist noch experimenteller als Stacked Borrows. Während Tree Borrows immer noch solide ist, da es alle Aliasing-Verstöße abfängt, die aktuelle Versionen des Compilers ausnutzen könnten, ist es wahrscheinlich, dass das endgültige Aliasing-Modell von Rust strenger sein wird als Tree Borrows. Mit anderen Worten: Wenn Sie Tree Borrows verwenden, wird Ihr Code möglicherweise in Zukunft als UB deklariert, selbst wenn er heute akzeptiert wird. Dies ist bei gestapelten Krediten viel weniger wahrscheinlich.-Zmiri-force-page-size=
überschreibt die Standardseitengröße für eine Architektur in Vielfachen von 1 KB. 4
ist für die meisten Ziele die Standardeinstellung. Dieser Wert sollte immer eine Potenz von 2 und ungleich Null sein.-Zmiri-unique-is-unique
führt zusätzliche Aliasing-Prüfungen für core::ptr::Unique
durch, um sicherzustellen, dass es theoretisch als noalias
betrachtet werden könnte. Dieses Flag ist experimentell und hat nur eine Wirkung, wenn es mit -Zmiri-tree-borrows
verwendet wird. Einige native rustc -Z
-Flags sind auch für Miri sehr relevant:
-Zmir-opt-level
steuert, wie viele MIR-Optimierungen durchgeführt werden. Miri überschreibt den Standardwert 0
; Beachten Sie, dass die Verwendung einer höheren Ebene dazu führen kann, dass Miri Fehler in Ihrem Programm übersieht, weil diese wegoptimiert wurden.-Zalways-encode-mir
bewirkt, dass rustc MIR auch für vollständig monomorphe Funktionen ausgibt. Dies ist erforderlich, damit Miri solche Funktionen ausführen kann, daher setzt Miri dieses Flag standardmäßig.-Zmir-emit-retag
steuert, ob Retag
Anweisungen ausgegeben werden. Miri aktiviert dies standardmäßig, da es für gestapelte Ausleihen und Baumausleihen benötigt wird.Darüber hinaus erkennt Miri einige Umgebungsvariablen:
MIRIFLAGS
definiert zusätzliche Flags, die an Miri übergeben werden.MIRI_LIB_SRC
definiert das Verzeichnis, in dem Miri die Quellen der Standardbibliothek erwartet, die es erstellt und zur Interpretation verwendet. Dieses Verzeichnis muss auf das library
eines rust-lang/rust
-Repository-Checkouts verweisen.MIRI_SYSROOT
gibt den zu verwendenden Sysroot an. Bei Verwendung von cargo miri test
/ cargo miri run
wird die automatische Einrichtung übersprungen – stellen Sie dies nur ein, wenn Sie nicht das automatisch erstellte Sysroot verwenden möchten. Wenn Sie cargo miri setup
aufrufen, gibt dies an, wo die Sysroot-Datei abgelegt wird.MIRI_NO_STD
stellt sicher, dass die Sysroot des Ziels ohne libstd erstellt wird. Dies ermöglicht das Testen und Ausführen von no_std-Programmen. Dies sollte normalerweise nicht verwendet werden ; Miri verfügt über eine Heuristik zur Erkennung nicht standardmäßiger Ziele anhand des Zielnamens. Wenn Sie dies auf ein Ziel setzen, das libstd unterstützt, kann dies zu verwirrenden Ergebnissen führen. extern
Funktionen Miri bietet einige extern
Funktionen, die Programme importieren können, um auf Miri-spezifische Funktionen zuzugreifen. Sie werden in /tests/utils/miri_extern.rs deklariert.
Von Binärdateien, die nicht die Standardbibliothek verwenden, wird erwartet, dass sie eine Funktion wie diese deklarieren, damit Miri weiß, wo die Ausführung beginnen soll:
# [ 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.
}
Wenn Sie zu Miri beitragen möchten, großartig! Bitte schauen Sie sich unseren Beitragsleitfaden an.
Wenn Sie Hilfe beim Ausführen von Miri benötigen, können Sie hier auf GitHub ein Problem eröffnen oder den Miri-Stream auf Rust Zulip verwenden.
Dieses Projekt begann im Rahmen eines Bachelor-Forschungskurses im Jahr 2015 von @solson an der University of Saskatchewan. Von diesem Projekt sind Folien und ein Bericht verfügbar. Im Jahr 2016 trat @oli-obk bei, um Miri darauf vorzubereiten, schließlich als Const-Evaluator im Rust-Compiler selbst verwendet zu werden (im Wesentlichen für const
und static
Dinge) und den alten Evaluator zu ersetzen, der direkt auf dem AST arbeitete. Im Jahr 2017 absolvierte @RalfJung ein Praktikum bei Mozilla und begann mit der Entwicklung von Miri zu einem Tool zur Erkennung undefinierten Verhaltens und nutzte Miri auch als Möglichkeit, die Konsequenzen verschiedener möglicher Definitionen für undefiniertes Verhalten in Rust zu untersuchen. @oli-obks Umzug der Miri-Engine in den Compiler wurde schließlich Anfang 2018 abgeschlossen. In der Zwischenzeit, später in diesem Jahr, absolvierte @RalfJung ein zweites Praktikum, bei dem er Miri mit Unterstützung für die Überprüfung grundlegender Typinvarianten und die Überprüfung, ob Referenzen entsprechend verwendet werden, weiterentwickelte zu ihren Aliasing-Einschränkungen.
Miri hat bereits eine Reihe von Fehlern in der Rust-Standardbibliothek und darüber hinaus gefunden, von denen wir einige hier sammeln. Wenn Miri Ihnen geholfen hat, einen subtilen UB-Fehler in Ihrem Code zu finden, würden wir uns über eine PR freuen, die ihn zur Liste hinzufügt!
Eindeutige Fehler gefunden:
Debug for vec_deque::Iter
der auf nicht initialisierten Speicher zugreiftVec::into_iter
führt einen nicht ausgerichteten ZST-Lesevorgang durchFrom<&[T]> for Rc
erstellt eine nicht ausreichend ausgerichtete ReferenzBTreeMap
erstellt eine gemeinsame Referenz, die auf eine zu kleine Zuordnung verweistVec::append
erstellt eine baumelnde Referenzstr
verwandelt eine gemeinsame Referenz in eine veränderlicherand
führt nicht ausgerichtete Lesevorgänge durchposix_memalign
auf ungültige Weise aufgetrandom
ruft den getrandom
-Systemaufruf auf ungültige Weise aufVec
und BTreeMap
verlieren unter bestimmten (panischen) Bedingungen Speicherbeef
EbrCell
verwendet nicht initialisierten Speicher falschservo_arc
erstellt eine baumelnde gemeinsame Referenzencoding_rs
führt Out-of-Bounds-Zeigerarithmetik durchVec::from_raw_parts
falschAtomicPtr
und Box::from_raw_in
ThinVec
crossbeam-epoch
ruft assume_init
auf einem teilweise initialisierten MaybeUninit
aufinteger-encoding
die einen falsch ausgerichteten Zeiger dereferenziertrkyv
konstruiert eine Box<[u8]>
aus einer überausgerichteten Zuordnungarc-swap
thread::scope
regex
verarbeitet nicht ausgerichtete Vec
-Puffer falschcompare_exchange_weak
in once_cell
vec::IntoIter
Iterator::collect
portable-atomic-util
std::mpsc
Kanälen (Originalcode im Crossbeam)Es wurden Verstöße gegen Stacked Borrows festgestellt, bei denen es sich wahrscheinlich um Fehler handelt (aber Stacked Borrows ist derzeit nur ein Experiment):
VecDeque::drain
erstellt überlappende veränderbare ReferenzenBTreeMap
ProblemeBTreeMap
Iteratoren erstellen veränderbare Referenzen, die sich mit gemeinsam genutzten Referenzen überschneidenBTreeMap::iter_mut
erstellt überlappende veränderbare ReferenzenBTreeMap
Knoten mithilfe von Rohzeigern außerhalb ihres gültigen SpeicherbereichsLinkedList
Cursors werden überlappende veränderbare Referenzen erstelltVec::push
macht vorhandene Referenzen im Vektor ungültigalign_to_mut
verletzt die Eindeutigkeit veränderlicher Referenzensized-chunks
die veränderbare Aliasing-Referenzen erstellenString::push_str
macht vorhandene Verweise auf die Zeichenfolge ungültigryu
verwendet Rohzeiger außerhalb ihres gültigen SpeicherbereichsEnv
Iterator verwendet einen Rohzeiger außerhalb seines gültigen SpeicherbereichsVecDeque::iter_mut
erstellt überlappende veränderbare Referenzen<[T]>::copy_within
verwendet ein Darlehen, nachdem es ungültig gemacht wurde Lizenziert unter einem von beiden
nach Ihrer Wahl.
Sofern Sie nicht ausdrücklich etwas anderes angeben, unterliegt jeder Beitrag, der von Ihnen absichtlich zur Aufnahme in das Werk eingereicht wird, einer Doppellizenz wie oben, ohne zusätzliche Bedingungen oder Konditionen.