2016-08-01 10 views
1

Wir haben vor kurzem begonnen, madExcept anstelle von ExcMagic als Exception Handler zu verwenden. Wir arbeiten auch an einem 64-Bit-Build unserer App und möchten daher, wenn möglich, die Verwendung von asm-Code eliminieren.Vorteil der Erstellung einer Zugriffsverletzung für Testzwecke mit Asm-Code?

ExcMagic hatte dieses Verfahren, um eine Zugriffsverletzung zu Testzwecken zu erstellen.

procedure CreateAccessViolation 
begin 
    asm 
    mov eax,11111111h 
    mov ebx,22222222h 
    mov ecx,33333333h 
    mov edx,44444444h 
    inc dword ptr [eax] 
    end; 
end; 

Gibt es einen Vorteil, dass Code verwenden, anstatt nur zu schreiben

raise EAccessViolation.Create('Just testing...'); 

Es muss einen Grund geben die ExcMagic Entwickler, dass verwendet.

Danke!

+5

Der ursprüngliche Code erzeugt einen tatsächlichen Zugriffsverletzungsfehler auf der Betriebssystemebene und lässt ihn in die RTL übergehen, um in eine EAccessViolation mit einem echten zugewiesenen EXCEPTION_RECORD konvertiert zu werden. Einfaches Öffnen von EAccessViolation ist nicht dasselbe, aber für Testzwecke spielt es wahrscheinlich keine Rolle. Eine einfachere Möglichkeit, ein echtes AV zu verursachen, besteht darin, in ungültigen Speicher zu schreiben, z. B. durch einen Null-Zeiger, und dazu benötigen Sie keinen Assembly-Code, zB: procedure CreateAccessViolation begin PInteger (nil) ^: = 12345; Ende; ' –

+0

@RudyVelthuis korrigiert. Danke! – santiagoIT

+4

Zunächst einmal - diese Gruppe von Anweisungen ist nicht garantiert, um eine Zugriffsverletzung zu erstellen. Es ist nicht undenkbar, dass sich ein beschreibbarer Speicher unter der Adresse $ 11111111 befindet. Ein NIL-Pointer write erzeugt immer eine Zugriffsverletzung. Davon abgesehen ist diese bestimmte Zugriffsverletzung sehr leicht als die absichtlich erstellte zu erkennen, was möglicherweise der Grund für diese spezielle Gruppe von Anweisungen ist. – HeartWare

Antwort

3

Ausnahmen, auf OS-Ebene, sind keine Objekte. Sie sind numerische Werte, die möglicherweise zusätzliche Kontextdaten enthalten. Wenn Sie versuchen, eine ungültige Adresse zu lesen oder zu schreiben, erhalten Sie den Ausnahmecode Exception_Access_Violation mit Kontext, der den versuchten Vorgang und die Adresse angibt. Wenn Sie jedoch das reservierte Wort raise verwenden, erhalten Sie den Ausnahmecode cDelphiException mit connect, der einen Delphi-Objektverweis gibt. (Wissen Sie, dass Sie jedes Objekt werfen, nicht nur Nachkommen von Exception?)

In Delphi parlance, eine OS-Level-Exception wird bezeichnet als ein Laufzeitfehler.

In der Einheit SysUtils befindet sich ein Code, der einen Laufzeitfehler der Zugriffsverletzung, der von Ihrem Assemblercode erstellt wurde, in eine EAccessViolation Delphi-Ausnahme transformiert. Das macht es einfach, mit Delphi try - except Syntax zu fangen.

Wenn nicht-Delphi-Code in der Aufrufliste (oder vielleicht sogar Delphi-Code, der SysUtils nicht verwendet) ist, wird es wahrscheinlich den cDelphiException Ausnahmecode nicht erkennen, und selbst wenn dies der Fall ist, ist es möglicherweise nicht möglich um einen Delphi-Objekttyp von einem anderen zu unterscheiden. Exception_Access_Violation dagegen ist im gesamten Windows-Code bekannt.

Wenn Sie das Verhalten von einer Zugriffsverletzung testen möchten, ist es wahrscheinlich am besten, wenn eine tatsächliche Zugriffsverletzung vorliegt. Das versucht der Assembly-Code. (Ob dies erfolgreich ist, ist ein separates Problem.) Wenn Sie das Abfangen von Delphi-Objekten testen möchten, werfen Sie alle gewünschten Objekte einschließlich Instanzen von EAccessViolation.

3

Die Zugriffsverletzung listet die Adresse auf, auf die zugegriffen wurde (in diesem Fall $11111111).
Weil es so eine ungewöhnliche Adresse ist, die hervorstechen würde.

Wenn Sie sich einen Stack-Trace anschauen, listet er normalerweise die Werte der Register zum Zeitpunkt des Absturzes auf, wegen ihrer ungewöhnlichen Werte ist dies wieder eine rote Flagge.

Meine Vermutung ist, dass die Codebasis dies verwendet, um zwischen ihren eigenen Ausnahmen und anderen Ausnahmen zu unterscheiden, indem sie die magischen Zahlen überprüft.

Allerdings scheint mir das eine sehr alberne Art, eine benutzerdefinierte Ausnahme zu fälschen.
Ein informativerer Ansatz wäre, Ihre eigene Klasse von Ausnahme zu machen und diese zu erhöhen.

Im Fehlerdialog wird der Name der Ausnahme und alle von Ihnen angegebenen Informationen deutlich angegeben.
Dies macht es auch trivial zwischen Ausnahmen und jeder sonst zu unterscheiden:

try 
    DoSomething 
except 
    on E: EMadException do ShowMessage('it''s mine'); 
    else ShowMessage('not mine'); 
end;