Hier ist, wie ich mit dem Thema in den Krakatau decompiler behandelt:
Wir brauchen die Vererbungshierarchie für Ausnahmen wissen, bevor wir entscheiden, was möglich Sprünge.
Krakatau benötigt die Klassendefinitionen aller referenzierten Klassen, um die Vererbungshierarchie zu kennen. Wenn ich es aber trotzdem tun würde, würde ich das nicht tun. Das Anfordern von Klassendefinitionen macht es für Benutzer schwierig, den Decompiler zu betreiben, weil das Finden und Hinzufügen der Abhängigkeiten ein großer Schmerz ist. Sie brauchen das eigentlich nicht, wenn die Analyse etwas ungenau ist. Sie können stattdessen einfach davon ausgehen, dass alle Ausnahmen alle Handler erreichen können. In der Praxis erwarte ich, dass es zu fast den gleichen Ergebnissen führen würde.
Jeder Befehl im try-Block kann möglicherweise Exceptions/ Fehler auslösen, die von einem der verschachtelten try-catch-Blöcke behandelt werden können. Wenn Exception-throws als Kanten betrachtet werden, erhöht sich die Anzahl der zu verarbeitenden Pfade drastisch, und dies gilt auch für die Anzahl der Knoten in CFG.
Krakatau enthält Ausnahmen als Kanten in der CFG, was zu den von Ihnen identifizierten Problemen führt. Um die Anzahl der Kanten zu reduzieren, gab ich vor, dass nur bestimmte Anweisungen auslösen können (Methodenaufrufe, Array-Zugriffe, Division, etc.). Das ist technisch nicht korrekt, aber es ist das Richtige für den echten Code. Ich habe noch nie etwas gesehen, das sich wirklich für die Exceptions interessiert, die von einem Linkfehler, Thread.Stop oder ähnlichem ausgelöst werden. Ich habe später eine Option hinzugefügt, um dieses Verhalten zu deaktivieren.
Wie auch immer, dies funktionierte gut genug für den meisten Code, aber es verursachte manchmal Leistungsprobleme. Besonders große Methoden mit vielen Feldzugängen oder Methodenaufrufen würden zu riesigen CFGs führen, die die Dekompilierung sehr verlangsamen. Ich habe einige Tricks versucht, um dies zu optimieren, aber letztendlich bestand die Lösung darin, von Basisblöcken zu erweiterten Basisblöcken zu wechseln.
Erweiterte Basisblöcke ähneln Basic Blocks, mit der Ausnahme, dass Ausnahmekanten halbimplizit dargestellt werden, was zu einer viel kleineren CFG führt. Ein EBB besteht aus einem geraden Liniencode mit keinen Eintrittspunkten oder Austrittspunkten in der Mitte, abgesehen von Ausnahmekanten, und wobei jeder Befehl in dem Block von demselben Satz von Ausnahmebehandlern abgedeckt ist. Auf diese Weise haben Sie, anstatt eine Ausnahmekante pro Anweisung zu haben, eine pro Block, was die Dinge viel effizienter macht.
Sogar Java-Methoden mit Tausenden von Methodenaufrufen haben normalerweise nur ein paar Versuche/Fänge und daher nur ein paar EBBs.
Ich bin zu faul, um nachzuschlagen - wofür steht CFG? – GhostCat
@GhostCat https://en.wikipedia.org/wiki/Control_flow_graph; "eine Darstellung aller Pfade, die während ihrer Ausführung durch ein Programm durchlaufen werden könnten, unter Verwendung der Graph-Notation." – Aaron