Dies ist im Wiki-Eintrag von Symbolic Execution geschrieben , aber ich kann keine Referenz dafür finden. Kann mir jemand einen Zeiger zeigen? Vielen Dank.
Dies ist im Wiki-Eintrag von Symbolic Execution geschrieben , aber ich kann keine Referenz dafür finden. Kann mir jemand einen Zeiger zeigen? Vielen Dank.
Antworten:
Mir ist kein Artikel bekannt, der sich mit dem Vergleich zwischen symbolischer Ausführung und abstrakter Interpretation befasst. Ich denke auch nicht, dass man gebraucht wird. Das Lesen der Originalbeschreibungen dieser beiden Techniken sollte ausreichen.
(Umgekehrt, wenn es eine unerwartete Verbindung geben würde, dann wäre das eine Beschreibung wert. Aber ich bezweifle sehr, dass dies der Fall ist.)
Die Grundidee der symbolischen Ausführung besteht darin, dass Sie zu einem beliebigen Zeitpunkt der Ausführung die Werte aller Variablen als Funktionen der Anfangswerte ausdrücken können. Die Hauptidee der abstrakten Interpretation besteht darin, dass Sie systematisch alle Ausführungen eines Programms durch eine Reihe von Überapproximationen untersuchen können. (Ich kann mehrere KI-Enthusiasten bei der vorherigen Annäherung stöhnen hören.)
Zumindest in der ursprünglichen Formulierung ging es bei der symbolischen Ausführung also nicht darum, alle möglichen Ausführungen zu untersuchen. Sie können dies sogar im Titel sehen: Es enthält das Wort "Testen". Aber hier ist mehr aus Abschnitt 8: "Für Programme mit unendlichen Ausführungsbäumen kann die symbolische Prüfung nicht erschöpfend sein und es kann kein absoluter Beweis für die Richtigkeit erbracht werden."
Im Gegensatz dazu zielt die abstrakte Interpretation darauf ab, alle Ausführungen zu untersuchen. Dazu werden verschiedene Zutaten verwendet, von denen eine der Grundidee der symbolischen Ausführung sehr ähnlich ist. Diese Bestandteile sind (1) abstrakte Zustände, (2) Verbinden und Erweitern (daher "Gitter" im Titel).
Abstrakte Zustände.Der konkrete Zustand eines Programms zu einem bestimmten Zeitpunkt ist im Grunde genommen eine Momentaufnahme des Speicherinhalts (einschließlich des Programmcodes selbst und des Programmzählers). Dies hat viele Details, die schwer zu verfolgen sind. Wenn Sie eine bestimmte Eigenschaft analysieren, möchten Sie möglicherweise große Teile des konkreten Zustands ignorieren. Oder Sie möchten sich nur darum kümmern, ob eine bestimmte Variable negativ, null oder positiv ist, aber nicht um ihren genauen Wert. Im Allgemeinen möchten Sie eine abstrakte Version des konkreten Zustands betrachten. Damit dies funktioniert, müssen Sie über eine Kommutativitätseigenschaft verfügen: Wenn Sie einen konkreten Zustand annehmen, eine Anweisung ausführen und dann den resultierenden Zustand abstrahieren, sollten Sie dasselbe Ergebnis erhalten, als ob Sie den Anfangszustand abstrahieren und dann denselben ausführen Aussage aber über den abstrakten Zustand. Dieses Kommutativitätsdiagramm erscheint in beiden Arbeiten. Das ist die übliche Idee. Auch hier ist die abstrakte Interpretation allgemeiner, da sie nicht vorschreibt, wie ein Staat abstrahiert werden soll - sie sagt lediglich, dass es einen Weg geben sollte, dies zu tun. Im Gegensatz dazu besagt die symbolische Ausführung, dass Sie (symbolische) Ausdrücke verwenden, die die Anfangswerte erwähnen.
Fügen und Erweitern. Wenn die Programmausführung eine bestimmte Anweisung auf zwei verschiedene Arten erreicht, versucht die symbolische Ausführung nicht, die beiden Analysen zusammenzuführen. Deshalb handelt das obige Zitat eher von Hinrichtungsbäumen als von Dags. Denken Sie jedoch daran, dass die abstrakte Interpretation alle Ausführungen abdecken möchte. Daher wird nach einer Möglichkeit gefragt, die Analysen zweier Ausführungen an dem Punkt zusammenzuführen, an dem sie denselben Programmzähler haben. (Der Beitritt könnteSeien Sie sehr dumm ({a} join {b} = {a, b}), sodass es dem entspricht, was die symbolische Ausführung bewirkt.) Im Allgemeinen reicht die Verknüpfung nicht aus, um zu gewährleisten, dass Sie die Analyse aller Ausführungen abschließen. (Insbesondere funktioniert die oben erwähnte dumme Verknüpfung nicht.) Stellen Sie sich ein Programm mit Schleifen vor: "n = input (); für i in range (n): dostuff ()". Wie oft solltest du die Schleife umrunden und dabei bleiben? Keine feste Antwort funktioniert. Daher ist noch etwas anderes erforderlich, und das erweitert sich , was als Heuristik angesehen werden kann. Angenommen, Sie haben die Schleife dreimal durchlaufen und dabei festgestellt, dass "i = 0 oder i = 1 oder i = 2" ist. Dann sagst du: hmmm, ... lass uns größer werden und du bekommst "i> = 0". Auch hier sagt die abstrakte Interpretation nicht, wie eine Verbreiterung erfolgen soll, sondern nur, welche Eigenschaften eine Verbreiterung haben soll.
(Entschuldigung für diese lange Antwort: Ich hatte wirklich keine Zeit, sie zu verkürzen.)
Ich denke, das ist in einem sehr flachen Sinne gemeint. Der erste Schritt der abstrakten Interpretation besteht darin, eine konkrete Sammelsemantik zu identifizieren. Anstatt die Entwicklung eines einzelnen Zustands zu beschreiben, beschreibt das Sammeln von Semantik die Entwicklung von Mengen von Zuständen. Da symbolische Ausführungsgründe über die Repräsentation von Mengen von Zuständen sprechen, kann man argumentieren, dass es die konkrete Semantik des Programms darstellt. Mir ist keine genauere Korrespondenz bekannt.
Siehe Patrick Cousot. Konstruktions- und Annäherungsverfahren für monotone Punkte, Analyse von Programmpunkten (iterative Methoden zur Konstruktion und Annäherung von Fixpunkten von monotonen Operatoren auf Gittern, programmstatische Analyse). Thèse ès Sciences Mathématiques, Universität Joseph Fourier, Grenoble, Frankreich, 21. März 1978. https://cs.nyu.edu/~pcousot/publications.www/CousotTheseEsSciences1978.pdf (leider in französischer Sprache), Seite (3) -27 bis (3) -29