3 Punkte von GN⁺ 2024-07-31 | 1 Kommentare | Auf WhatsApp teilen
  • TRACTOR von DARPA ist ein Forschungsprogramm, das Legacy-C-Code automatisch in Rust umwandeln soll, um eine ganze Kategorie von Schwachstellen in der Speichersicherheit von C-Programmen zu beseitigen
  • Die Probleme von C und C++ bei der Speichersicherheit werden seit mehr als 20 Jahren behandelt, doch es hat sich die Erkenntnis durchgesetzt, dass Werkzeuge zur Fehlererkennung allein nicht ausreichen
  • Die Alternative besteht darin, bestehenden Code in eine sichere Programmiersprache zu überführen, die unsichere Programme bereits zur Compile-Zeit zurückweist
  • Das Ergebnis der Umwandlung soll eine Qualität und einen Stil erreichen, wie sie von erfahrenen Rust-Entwicklern geschriebener Code hat; dazu werden statische und dynamische Analyse mit Machine Learning auf Basis großer Sprachmodelle kombiniert
  • MIT Lincoln Laboratory übernimmt die Tests und Evaluierung; Benchmarks, Meilensteinprojekte und Tools werden auf einer öffentlichen Seite veröffentlicht

Ziele von TRACTOR

  • TRACTOR steht für „Translating All C to Rust“ und zielt darauf ab, Legacy-C-Code automatisch in Rust umzuwandeln
  • Aus Sicherheitssicht soll eine ganze Kategorie von Sicherheitslücken durch mangelnde Speichersicherheit in C-Programmen beseitigt werden
  • Der umgewandelte Code soll nicht nur funktionieren, sondern eine Qualität und einen Stil anstreben, wie sie von erfahrenen Rust-Entwicklern stammen

Warum eine Umwandlung nach Rust nötig ist

  • Die Probleme von C und C++ bei der Speichersicherheit beschäftigen die Software-Engineering-Community seit mehr als 20 Jahren
  • Es hat sich ein Konsens gebildet, dass sich das Problem nur schwer ausreichend lösen lässt, wenn man sich allein auf Werkzeuge zur Fehlererkennung verlässt
  • Der bevorzugte Ansatz ist die Nutzung einer sicheren Programmiersprache, die unsichere Programme bereits zur Compile-Zeit zurückweisen kann
  • TRACTOR nutzt dafür Rust als Zielsprache

Technologien für die automatische Umwandlung

  • TRACTOR kombiniert verschiedene Verfahren der Softwareanalyse und des Machine Learning, um Legacy-C-Code nach Rust zu übertragen
  • Analyseverfahren

    • Es nutzt statische Analyse und dynamische Analyse gemeinsam
    • Auch Machine-Learning-Verfahren einschließlich großer Sprachmodelle sind Teil der Kombination
    • Diese Kombination bildet die zentrale technische Grundlage, um Struktur und Verhalten von C-Code zu erfassen und ihn automatisch in Rust-Code umzuwandeln

Tests, Evaluierung und öffentliche Materialien

1 Kommentare

 
GN⁺ 2024-07-31
Meinungen auf Hacker News
  • Zur Referenz ist auch https://sam.gov/opp/1e45d648886b4e9ca91890285af77eb7/view sehenswert

    • Direkter Link zum PDF mit Informationen zur Bieterkonferenz: https://sam.gov/api/prod/opps/v3/opportunities/resources/fil...
      Dort heißt es, Ziel der Veranstaltung sei es, die technischen Ziele und Herausforderungen von TRACTOR zu erläutern, Fragen potenzieller Anbieter zu beantworten und ihnen Gelegenheit zu geben, zu prüfen, wie ihre jeweilige Forschung zu den Zielen des TRACTOR-Programms passen könnte
  • Das wirkt wirklich schwierig. Insbesondere idiomatisches Rust, wie es erfahrene Entwickler schreiben, ähnelt C überhaupt nicht, und der meiste interessante Code ist in C++ geschrieben
    Am Ende scheint das darauf hinauszulaufen, die Lebensdauer jeder Allokation in einem C-Programm statisch zu bestimmen. Einschließlich Allokationen, die über benutzerdefinierte Allocators oder proprietäre Bibliotheken laufen. In diesem Bereich wird schon lange geforscht, aber große Erfolge gab es nicht viele, und C/C++-Programme können die Lebensdauer von Allokationen daran koppeln, welche Schaltfläche ein Nutzer anklickt, ganz ohne Sicherheitsnetze wie Reference Counting. Das ist keine gute Idee, aber möglich
    Ein weiteres offensichtliches Problem ist, dass das zu analysierende Programm per Definition fehlerhafter Code ist. Wenn die Lebensdauern Sinn ergeben würden, gäbe es keine Memory-Safety-Schwachstellen und keinen Bedarf, ihn zu ersetzen. Forschung, die statisch erkennen will, „wie Lebensdauern sein sollten“, geht meist davon aus, dass der analysierte Code von vornherein korrekt ist. Man könnte sich zum Ziel setzen, ein Programm zu bauen, das die Stellen findet, an denen sich Lebensdauern nicht bestimmen lassen, und dort Entwickler um Hilfe bittet

    • Das ist eine sehr schwierige Aufgabe, und DARPA finanziert gern schwierige Aufgaben[1]
      Allerdings ist dies nicht das erste Mal, dass DARPA automatische Programmübersetzung oder automatische Übersetzung nach Rust versucht[2]
      [1]: https://www.urbandictionary.com/define.php?term=DARPA%20hard
      [2]: https://c2rust.com/
    • Wo wir gerade von schwierigen Aufgaben sprechen: Das DOE finanziert seit über 20 Jahren auch ein Projekt namens ROSE. Es behandelt statische Analyse und automatische Übersetzung zwischen C/C++/Cuda ebenso wie Hochsprachen wie Python und C/C++-Varianten für HPC
      Das Projekt ist ziemlich cool, weil es einen einheitlichen abstrakten Syntaxbaum hat, der diese Sprachen im Grunde mit derselben Menge von Knotentypen unterstützt. Ich hatte im Sommer 2014 während eines Praktikums in Livermore Gelegenheit, daran zu arbeiten
      Es ist außerdem Open Source: http://rosecompiler.org/ROSE_HTML_Reference/index.html
    • Im allgemeinen Fall dürfte es wohl in unsafe Rust übersetzt werden, und nur gelegentlich einzelne isolierte Blattknoten in sicheres Rust
      Wenn schon der Kampf mit dem Borrow Checker schwierig wirkt, ist die automatische Übersetzung in Code, den der Borrow Checker akzeptiert, unter Berücksichtigung des gesamten Raums möglicher C-Programme und des berüchtigten undefinierten Verhaltens noch viel schwieriger. Eines der klassischen Probleme im Compilerbau ist, dass der Raum gültiger Programme viel größer ist als der Raum kompilierbarer Programme
      Eine kurze Suche zeigt, dass es auch Versuche wie c2rust gibt[1]. Mich würde interessieren, worin sich TRACTOR unterscheidet
      [1] https://github.com/immunant/c2rust
    • Es hat seinen Grund, dass DARPA-Projekte DARPA-hard genannt werden
    • Der Ansatz dürfte vermutlich so aussehen: „Eine KI fasst die Funktionalität des Programms in einer Art Spezifikationssprache zusammen und synthetisiert anschließend Rust-Code, der dieselbe Funktionsmenge abdeckt“
      Interessanter wäre es, statt des ursprünglichen Programms dessen Handbuch einzuspeisen. Allerdings enthalten Handbücher selten all die subtilen Verhaltensweisen eines Programms, sodass man wahrscheinlich zumindest für tatsächliche Referenzwerte in den Quellcode schauen muss
  • Diese vorgeschlagene Initiative war schon seit einiger Zeit bekannt, und es ist spannend, dass sie nun öffentlich wird. Es ist ein sehr ambitionierter Vorschlag, und ich denke, ein solches Maß an Ambition passt zur Mission von DARPA; ich hoffe, dass es gut läuft.
    Als jemand, der sich in diesem Bereich für Rust einsetzt, habe ich versucht, die Erwartungen derjenigen zu dämpfen, die diesen Vorschlag hinsichtlich der Möglichkeit einer automatischen Übersetzung von C nach Rust vorantreiben. Das grundlegende Hindernis, das ich sehe, ist, dass C-Quellcode weniger Informationen enthält als Rust-Quellcode. Um C-Code in Rust-Code zu übersetzen, muss jemand oder etwas diese fehlenden Informationen erzeugen. Aus demselben Grund, aus dem man beim starken Vergrößern eines Bildes keine Informationsbits, die im Originalbild nicht erfasst wurden, fehlerfrei erzeugen kann, lässt sich leicht beweisen, dass es unmöglich ist, diese fehlenden Informationen perfekt zu generieren. Letztlich muss man Informationen, die im vorhandenen Quellcode fehlen, extrapolieren, also erfinden. Korrekte Extrapolation erfordert Urteilsvermögen und ist ein Prozess, bei dem zwangsläufig Fehler entstehen, insbesondere wenn unbeaufsichtigte Sprachmodelle ihn in großem Umfang durchführen. Ich habe schon einmal eine Lösung vorgeschlagen, von der ich denke, dass sie dieses Problem bis zu einem gewissen Grad abmildern kann, werde aber nicht ins Detail gehen.
    Letztlich glaube ich, dass dieses Projekt bis zu einem gewissen Grad erfolgreich sein kann, aber es sollte mit vorsichtigen und maßvollen Erwartungen angegangen werden. Gleichzeitig besteht auch die Möglichkeit, dass es keinerlei öffentliche Ergebnisse geben wird; daher möchte ich sagen, dass man zum jetzigen Zeitpunkt nicht zu viel hineininterpretieren sollte. Insbesondere ist die Regierung kein einheitlicher Akteur, daher sollte dieses Projekt weder als vollständige Ablehnung von C noch als vollständiger Segen für Rust verstanden werden. Jede Behörde wird ihre Richtung und ihren Zeitplan für die Einführung von Memory-Safety-Technologien selbst festlegen. So empfiehlt etwa NIST nicht nur Rust, sondern auch Ada SPARK sowie mehrere gehärtete C/C++-Dialekte.

    • In welcher Beziehung steht das zu Grammatechs CRAM-Bemühungen?
      https://cpp-rust-assisted-migration.gitlab.io/blog/
    • Wenn man nicht versucht, die formale Semantik des C-Codes zu bewahren, sondern es als ausreichend betrachtet, wenn nach der Übersetzung nur die Testsuite besteht, entsteht beim Übersetzen deutlich mehr Spielraum.
      Reale Rustifizierungsprojekte laufen oft auf diese Weise. Auch Fuzzer können helfen, zusätzliche Testdaten zu erzeugen und die Branch Coverage zu erhöhen.
  • Persönlich mag ich die Denkweise „Schreiben wir die ganze Welt in Rust neu“ nicht. Trotzdem ist mechanische Übersetzung ein schlechter Weg, wenn man ein Projekt auf eine neue Sprache oder Plattform portieren will.
    Man sollte sich die Zeit nehmen, eine bessere Architektur zu planen und ein besseres Softwaresystem zu entwerfen, und dann einen Weg finden, es Stück für Stück zu ersetzen. Wenn man ein Schloss in den Wolken baut, wird es nie den Boden berühren. Wenn man sich entscheidet, Rust für dieses System zu verwenden, ist das in Ordnung, aber man sollte es Rust-gemäß schreiben. Man sollte nicht versuchen, C nach Rust zurückzuportieren.
    Ein deutlich besserer und ausgereifterer Prozess wäre meiner Ansicht nach, C auf modernes C zu aktualisieren und mit einem Model Checker wie CBMC die Sicherheit von Speicher, Ressourcen und Integer-Arithmetik zu verifizieren. Man kann dieselbe Sicherheit wie bei einer schrittweisen Rust-Neuentwicklung erreichen und zugleich Codebasis, Wissensbasis und Entwickler behalten.

    • Keine Chance. CBMC ist erstaunlich, aber hast du schon einmal ein „echtes“ Programm formal verifiziert?
      Ich stimme zu, dass der Ersatz durch eine von Hand architektierte Rust-Version eindeutig die bessere Lösung ist, aber er ist auch teurer. Hier scheint man auf ein Produkt im RLBox-Stil abzuzielen: „mit fast keinem Aufwand die Sicherheit deutlich verbessern“. Das heißt nicht, dass man keine vollständige manuelle Neuentwicklung machen sollte, wenn man die Ressourcen hat, sondern dass es besser ist, als nichts zu tun.
    • Auch modernes C hat bei Arrays und Strings genau dieselben Sicherheitslücken wie klassisches C, und daran hat sich seit 50 Jahren nichts geändert.
    • Das ist definitiv eine wolkenkuckucksheimartige DARPA-Herausforderung, die man sich beim Ausstieg aus Legacy-Systemen wünschen könnte. Aber selbst wenn man eine Funktion oder Methode aus einer Sprache in ChatGPT eingibt und um Übersetzung in eine andere Sprache bittet, funktioniert das meistens nicht gut.
      Wenn man ChatGPT nach dem ursprünglich zu lösenden Problem fragt, liegt es zwar häufiger richtig, aber meist funktioniert es trotzdem nicht gut. Damit selbst die grundlegende Ausgabe funktioniert, sind immer noch viel Nacharbeit und Nachdenken nötig.
    • Für ruhenden Code, der überall läuft, aber den niemand anfasst, hat der Ansatz „vor dem nächsten Anfassen erst einmal in mieses Rust übersetzen“ einen gewissen Reiz.
      Nicht den Reiz einer offensichtlich guten Idee. Das durch die Übersetzung erzeugte „miese Rust“ dürfte deutlich schlechter zu bearbeiten sein als C mit einem Hintergrundrauschen aus Bugs. Dank der getreuen Übersetzung werden diese Bugs auch im „miesen Rust“ weiterhin vorhanden sein. In C wissen die Leute einigermaßen, wie man mit solchen Problemen umgeht, aber „mieses Rust“ ist buchstäblich mies, weil Rust-Leute daran nicht gewöhnt sind.
      Trotzdem ist die Wahrscheinlichkeit nicht null, dass jemand Techniken entwickelt, um es wiederholt aufzuräumen und in einen erträglichen Zustand zu bringen. Außerdem könnte als Nicht-Ziel-Artefakt des Projekts Linter-Feedback der Art entstehen: „Aus Gründen x, y, z lässt sich das nicht in erträgliches Rust übersetzen.“ C-Entwickler könnten sich das ansehen, und wenn der Code in gutes Rust übersetzbar geworden ist, gibt es auch weniger Gründe, ihn überhaupt zu übersetzen.
      Wenn ein solches Ergebnis herauskommt, könnte es für manche einfacher sein, die Lösung in ausführbarem C zu beschreiben und den „Übersetzer/Linter“ sie zu einem Ansatz führen zu lassen, der nicht kaputt ist. Ich halte solche positiven Ergebnisse für ziemlich unwahrscheinlich, aber gelegentliche Dark-Horse-Wetten gehören doch ziemlich genau zur Stellenbeschreibung von DARPA.
    • Die Denkweise „Schreiben wir die ganze Welt in Rust neu“ gibt es nirgends. Es gibt enorm viel Software, die man viel besser in dynamischen Sprachen oder in statisch typisierten Sprachen mit Garbage Collection wie Go belässt. Gute Ingenieure verstehen den Gedanken, das passende Werkzeug für die Aufgabe zu verwenden.
      Der Kernpunkt ist, endlich damit anzufangen, Memory-Safety-CVEs zu reduzieren, die sich tatsächlich mehrfach als Problem erwiesen haben.
      Ich stimme zu, dass eine automatische und verlässliche Übersetzung von C/C++ nach Rust längst passiert wäre, wenn sie möglich wäre. Aber irgendwo in dem Prozess, bessere Architekturen und Systeme zu planen und Stück für Stück zu ersetzen, können Menschen das Selbstvertrauen entwickeln: „Wir schreiben C jetzt so viel besser, dass wir keine Memory-Safety-Bugs mehr machen; können wir hier nicht aufhören?“ Und genau das werden sie tatsächlich tun. Dann kommt sechs Monate später wieder ein traurig-komischer Buffer-Overflow-CVE.
      C auf modernes C zu aktualisieren und mit CBMC zu verifizieren, ist ebenfalls eine enorme Investition. Wenn man so weit geht, ist es besser, gleich zu Rust zu wechseln. Die Aussage, man erreiche dieselbe Sicherheit wie bei einer schrittweisen Rust-Neuentwicklung, mag möglich sein, wirkt aber ziemlich unsicher oder weit von einer klaren Schlussfolgerung entfernt.
  • Viele lesen das als Aufforderung oder Anweisung, sämtlichen C- und C++-Code nach Rust zu übersetzen, aber trotz des auffälligen Projektnamens liest sich das Abstract nicht so. Es gibt zwei miteinander verwandte, aber getrennte Absätze.
    Erstens sind C und C++ im großen Maßstab nicht sicher genug. Selbst mit sorgfältiger Programmierung und guten Tools entstehen wegen des grundsätzlich unsicheren Designs zu viele Schwachstellen. Daher sollte so viel Code wie möglich in „sichere“ Sprachen übersetzt oder neu geschrieben werden, insbesondere in Sprachen, die Memory Safety garantieren.
    Zweitens geht es darum, Software zu finanzieren und auszuschreiben, die bestehenden C-Code nach Rust übersetzt.
    Es ist kein Konsens, die Welt in Rust neu zu schreiben. Es ist ein Konsens, zu sicheren Sprachen zu migrieren; Rust ist eines der Beispiele, und es bedeutet, dass es in dieser Migration ein Programm mit Rust als Ziel gibt.

    • Wenn solche Sprachen ein unsafe-Konstrukt haben, welche Regeln gelten dann für dessen Nutzung? Wenn es dafür keinen definierten Regelsatz gibt, landet man am Ende wieder am Ausgangspunkt.
      Rust hat einen sicheren Modus. Rust ist nicht eine sichere Sprache. Für interessante Dinge braucht man unsafe-Blöcke. Damit gewinnt man nicht viel.
      Andererseits gibt es viele Garbage-Collection-Sprachen, in denen Programmierer nicht einmal Pointer anfassen können. Warum werden solche Sprachen nicht berücksichtigt? Der Grund ist Performance. Weil Rust-Programmierer Performance so sehr „wichtig“ finden, kann diese Sprache das Grundproblem niemals lösen.
      Will man Performance oder will man Sicherheit? Beides kann man nicht haben.
  • Es ist wirklich erstaunlich, dass das auf irgendeine automatisierte Weise funktionieren können soll. Ein normales C-Programm lässt sich nicht Zeile für Zeile nach Rust übertragen.
    In C-Programmen gibt es Pointer und Aliasing überall, und Rust unterbindet solche Konzepte ausdrücklich. Solange man nicht alles in unsafe einwickelt, muss man viele typische Strukturen auf höherer Ebene neu durchdenken, um ein C-Programm in Rust neu zu schreiben.

    • Eine zeilenweise Übersetzung ist unmöglich; deshalb muss man AI einsetzen, um umfassenderes semantisches Schlussfolgern zu leisten.
      Man muss auch nicht alles auf einmal übersetzen. Einer der Werte des Rust-Compilers ist, dass er viele konkrete Informationen liefert, die man wieder in ein LLM einspeisen und iterieren kann.
      Bei meinem Startup grit.io haben wir an ähnlichen Problemen gearbeitet, und ich denke, C -> Rust ist in naher Zukunft gut beherrschbar. Sicher nicht einfach, aber ein lösbares Problem.
    • Abgesehen von Multi-Thread-Programmen: Gibt es langfristiges Aliasing in C-Programmen wirklich überall? Ich würde erwarten, dass es in vielen Programmen größtenteils innerhalb eines einzelnen Funktions-Scopes oder über Funktionsaufrufe darin hinweg auftritt. Lässt sich das in diesem Fall nicht durch Borrowing lösen?
      Dann könnte man das als ein Teilproblem behandeln und als ein weiteres Problem erkennen, wie Daten zwischen Threads geteilt werden. Im letzteren Fall haben viele Programme vermutlich implizite Ownership-Regeln wie „Thread T1 legt etwas in Queue Q, Thread T2 nimmt es heraus“. Das ließe sich als „Beim Einreihen wird Ownership übertragen“ übersetzen.
      Solche Regeln zu erkennen wäre sicher nicht einfach, wirkt aber auch nicht völlig außerhalb der Reichweite und könnte als Forschungsprojekt durchaus sinnvoll sein.
    • Aus der naiven Anfängerperspektive gefragt: Könnte man nicht Zeile für Zeile vorgehen, alles in unsafe einwickeln, es zum gleichen Binary kompilieren und dann, während man die Äquivalenz fortlaufend prüft, unsafe langsam herauslösen?
      So könnte man zumindest so viel wie möglich nach Rust übernehmen und nur die Konzepte separat behandeln, die Ingenieure neu durchdenken müssen.
    • Für eine zeilenweise Übersetzung braucht es gar nicht viel „AI“. Eine grobe, größtenteils unsafe-Rust-Übersetzung ließe sich vermutlich erzeugen.
      Ich nehme an, dass AI Lebenszeiten usw. verstehen muss, um tatsächlich nützliche und gültige Programme zu erzeugen. Wenn sie das wirklich schafft, wäre das beeindruckend.
    • Bei Codebases, die stark auf Makros setzen, frage ich mich besonders, wie das ausgehen würde.
  • Ähnliche Ergebnisse kann man auch mit C/C++ erzielen, wenn man sehr strenge Coding-Praktiken einhält und Third-Party-Tools für statische Verifikation integriert, die den Code mit proprietären Annotationen vollstopfen müssen.
    Oder man verwendet einfach Rust.

    • Es ist ziemlich lustig zu sehen, wie die C/C++-Community auf Rust reagiert. Jahrzehnte an Arbeit und Erfahrung mit diesen Sprachen haben offenbar die Schaltkreise für Schlussfolgerungen überschrieben.
      Wer bei klarem Verstand würde eine Sprache mit so großen und offensichtlichen Designfehlern verteidigen, wenn es eine echte Alternative gibt?
    • Ich meinte, dass ich proprietäre Annotationen schreiben wollte, nicht „proprietäre Situation“. Das lag an der Autovervollständigung des Handys.
  • Ich glaube nicht, dass das gut funktionieren wird. C hat Abstraktionen, die sich in Rust nicht ohne größere Änderungen nachbilden lassen.
    In C ist es üblich, dass zwei verschiedene Datenstrukturen, die denselben Pointer enthalten, über diesen Pointer schreiben. Das lässt sich in Rust nicht trivial nachbilden und erfordert ziemlich clevere Eingriffe.

    • Man wird wohl etwas erzeugen können, das kompiliert und sowohl „Rust“ als auch „AI“ ist. Damit erfüllt es gleich doppelt die Buzzword-Anforderungen, was auch gut ist, um ein Forschungsprojekt zu rechtfertigen.
      Aber man wird dadurch weder Output mit weniger Bugs noch einen Prozess bekommen, der automatisch die Programmstrukturen erzeugt, die Rusts Zuverlässigkeit ausmachen.
  • Muss das automatisch sein? Falls ja, müsste ein Programm, das C automatisch nach Rust portieren kann, nicht zwangsläufig alle Funktionen enthalten, die nötig wären, um den C-Code selbst sicher zu machen?

    • Wenn man diesen Satz vernünftig liest, ist schwer anzunehmen, dass vollständige Automatisierung gemeint ist; dann lautet die Antwort auf die Frage nein.
      Mancher C-Code ist nicht einfach „in seiner Korrektheit nicht verifizierbar“, sondern in Bezug auf Memory Safety tatsächlich falsch. Solcher Code wird sich nicht ohne menschliches Eingreifen automatisch übersetzen lassen. Wie sollte das gehen, wenn es keinen korrekten äquivalenten Code gibt? Das Tool braucht einen Ausweg, mit dem es sagen kann: „Ich weiß nicht, was dieser Code tun soll, und ich weiß auch, dass das, was er tatsächlich tut, die Vereinbarungen mit dem Compiler verletzt und daher nicht beabsichtigt sein kann. Mensch, hilf mir.“
      Theoretisch ist es unmöglich, diesen Ausweg nur dann zu nutzen, wenn tatsächlich undefiniertes Verhalten auftritt. Wegen des Satzes von Rice. Auch praktisch sollte man übermäßig obskuren Code nicht blind übersetzen, daher ist schon der Versuch wahrscheinlich nicht wünschenswert.
      Am Ende stelle ich mir vor, dass das Tool die meiste Arbeit erledigt, aber eher wie ein vom Menschen geführtes interaktives Tool funktioniert. Und als Ergebnis der menschlichen Anleitung wird nicht exakt äquivalenter Code entstehen, sondern Code, der denselben Zweck erfüllt.
  • Wenn 1) Rust keine Speicherfehler hat und 2) C automatisch nach Rust übersetzt werden kann, bedeutet das, dass sich alle Speicherfehler automatisch beheben ließen.
    Das ist mit ziemlicher Sicherheit nicht wahr. Diese Aufgabe ist im allgemeinen Fall sehr wahrscheinlich völlig unmöglich.

    • Da nicht ausdrücklich gesagt wurde, dass man jedes Verhalten des C-Codes erhalten will, gibt es für dieses Problem eine triviale Lösung.
      Zum Beispiel könnte man alle dynamischen Speicherallokationen durch einen zum Übersetzungszeitpunkt festgelegten festen Puffer ersetzen und alle Eingaben ablehnen, die nicht in diesen Puffer passen.