Formale Verifikation durch Übersetzung der `core`- und `alloc`-Crates von Rust nach Coq
(formal.land)Übersetzung der core- und alloc-Crates von Rust
Erster Lauf 🐥
- Mit
coq-of-rustwurden diealloc- undcore-Crates von Rust erstmals übersetzt, wobei zwei Coq-Dateien mit jeweils mehreren hunderttausend Zeilen Code erzeugt wurden. - Das zeigt, dass das Tool auch bei großen Codebasen funktioniert, aber der erzeugte Coq-Code kompiliert nicht. Fehler treten nur selten auf, etwa einmal alle paar tausend Zeilen.
Größe des eingegebenen Rust-Codes (gemäß dem Befehl cloc)
-
alloc: 26.299 Zeilen Rust-Code -
core: 54.192 Zeilen Rust-Code -
Da Makros expandiert und dann übersetzt werden müssen, ist die tatsächlich zu übersetzende Größe noch größer.
Aufteilung des erzeugten Codes 🪓
- Die wichtigste Änderung bestand darin, die von
coq-of-rusterzeugte Ausgabe in jeweils eine Datei pro eingegebener Rust-Datei aufzuteilen. - Das ist möglich, weil die Übersetzung unabhängig von der Reihenfolge der Definitionen erfolgen kann. Zyklische Abhängigkeiten zwischen Rust-Dateien sind in Coq zwar verboten, die Aufteilung ist aber trotzdem möglich.
Umfang der Ausgabe
alloc: 54 Coq-Dateien, 171.783 Zeilen Coq-Codecore: 190 Coq-Dateien, 592.065 Zeilen Coq-Code
Vorteile der Code-Aufteilung
- Der erzeugte Code lässt sich leichter lesen und durchsuchen
- Er lässt sich einfacher kompilieren, da parallel kompiliert werden kann
- Debugging ist einfacher, da man sich auf eine Datei konzentrieren kann
- Nicht kompilierbare Dateien lassen sich leichter ignorieren
- Änderungen an einzelnen Dateien lassen sich leichter nachverfolgen, was die Wartung vereinfacht
Einige Bugfixes 🐞
- Es gab einen Bug durch Kollisionen zwischen Modulnamen. Dieser trat bei der Wahl des Modulnamens für
impl-Blöcke auf. - Um die Eindeutigkeit zu erhöhen, wurden mehr Informationen in den Modulnamen aufgenommen, zum Beispiel
where-Klauseln.
Beispiel
-
Implementierung des Typs
Mappingfür das TraitDefault:#[derive(Default)] struct Mapping<K, V> { // ... } -
Vorheriger Coq-Code:
Module Impl_core_default_Default_for_dns_Mapping_K_V. (* ...trait implementation ... *) End Impl_core_default_Default_for_dns_Mapping_K_V. -
Überarbeiteter Coq-Code:
Module Impl_core_default_Default_where_core_default_Default_K_where_core_default_Default_V_for_dns_Mapping_K_V. (* ... *)
Liste der nicht kompilierbaren Dateien
-
alloc/boxed.v -
core/any.v -
core/array/mod.v -
core/cmp/bytewise.v -
core/error.v -
core/escape.v -
core/iter/adapters/flatten.v -
core/net/ip_addr.v -
Das entspricht 4 % aller Dateien. Auch in Dateien, die kompilieren, können noch nicht behandelte Rust-Konstrukte vorkommen.
Beispiele 🔎
Quellcode der Methode unwrap_or_default des Typs Option
pub fn unwrap_or_default(self) -> T
where
T: Default,
{
match self {
Some(x) => x,
None => T::default(),
}
}
Übersetzter Coq-Code
Definition unwrap_or_default (T : Ty.t) (τ : list Ty.t) (α : list Value.t) : M :=
let Self : Ty.t := Self T in
match τ, α with
| [], [ self ] =>
ltac:(M.monadic
(let self := M.alloc (| self |) in
M.read (|
M.match_operator (|
self,
[
fun γ =>
ltac:(M.monadic
(let γ0_0 :=
M.get_struct_tuple_field_or_break_match (|
γ,
"core::option::Option::Some",
0
|) in
let x := M.copy (| γ0_0 |) in
x));
fun γ =>
ltac:(M.monadic
(M.alloc (|
M.call_closure (|
M.get_trait_method (| "core::default::Default", T, [], "default", [] |),
[]
|)
|)))
]
|)
|)))
| _, _ => M.impossible
end.
Vereinfachter Funktionscode
Definition unwrap_or_default {T : Set}
{_ : core.simulations.default.Default.Trait T}
(self : Self T) :
T :=
match self with
| None => core.simulations.default.Default.default (Self := T)
| Some x => x
end.
- Diese vereinfachte Definition wird bei der Codeverifikation verwendet. Der Gleichheitsbeweis befindet sich in
CoqOfRust/core/proofs/option.v.
Fazit
-
Durch die Formalisierung der Standardbibliothek wird die Verifikationsarbeit für Rust-Programme vertrauenswürdig.
-
Das nächste Ziel besteht weiterhin darin, den noch umständlichen Beweisprozess zu vereinfachen. Insbesondere sollen Schritte wie Namensauflösung, Einführung fortgeschrittener Typen und Entfernung von Seiteneffekten bei der Darstellung der Gleichwertigkeit zur ursprünglichen Rust-Implementierung getrennt werden.
-
Wer sich für die formale Verifikation von Rust-Projekten interessiert, kann sich unter contact@formal.land melden. Formale Verifikation bietet das höchste Sicherheitsniveau, indem mathematisch garantiert wird, dass bezogen auf eine gegebene Spezifikation keine Bugs vorhanden sind.
Tags:
- coq-of-rust
- Rust
- Coq
- Übersetzung
- core
- alloc
Meinung von GN⁺
- Integration von Rust und Coq: Die Integration von Rust und Coq kann erheblich dazu beitragen, die Stabilität von Rust-Programmen zu erhöhen. Die Kombination aus der Sicherheit von Rust und der formalen Verifikation von Coq ist besonders für kritische Anwendungen sehr nützlich.
- Bedeutung der Automatisierung: Die automatische Übersetzung mit dem Tool
coq-of-rustist zuverlässiger als manuelle Arbeit. Dennoch ist Vorsicht geboten, da im Verifikationsprozess weiterhin Fehler auftreten können. - Umgang mit komplexen Codebasen: Bei großen Codebasen hilft die Aufteilung des Codes enorm bei Wartung und Debugging. Das ist besonders in Teamumgebungen ein wichtiger Faktor.
- Notwendigkeit formaler Verifikation: Formale Verifikation ist besonders in kritischen Bereichen wie Finanzen, Medizin und Luftfahrt unverzichtbar. Die Kombination aus Rust und Coq kann in solchen Bereichen großen Mehrwert bieten.
- Aspekte bei der Einführung neuer Technologien: Bei der Einführung neuer Technologien sollten die Lernkurve und die Kompatibilität mit bestehenden Systemen berücksichtigt werden. Werkzeuge zur formalen Verifikation wie Coq können eine steile Lernkurve haben und erfordern daher ausreichende Schulung und Vorbereitung.
1 Kommentare
Hacker-News-Kommentar
Zusammenfassung der Hacker-News-Kommentare
Zuverlässigkeit automatischer Übersetzungswerkzeuge
Programmgröße und Verifikation
Fehlermöglichkeiten im Übersetzungsprozess
Beiträge mit Bezug zu Kryptowährungen
Grenzen formaler Verifikation
Formale Verifikation von Rust
unsafeverwendet wird.Schreiben formaler Verifikationsspezifikationen
Vergleich mit anderen Ansätzen
Rust-Einführung im Kernel
Ergänzung eines Rust-Backends für F*