2016-06-22 28 views
2

Ich erhalte eine Zugriffsverletzung, wenn ich ein Formular in meiner Anwendung zu schließen. Es scheint erst dann zu passieren, wenn ich einige Male auf eine Datenbank zugreife, aber das scheint keinen Sinn zu ergeben.Zugriffsverletzung - wie finde ich die Ursache?

Ich habe durch verfolgt und setzen Output Nachrichten in allen verwandten OnDestroy() Methoden, aber die AV erscheint außerhalb meines Codes zu sein.

Dies ist der Text der Nachricht:

Zugriffsverletzung bei Adresse 00405F7C in Modul 'MySoopaApplication.exe'. Adresse lesen 00000008.

Wie finde ich wo in der Anwendung 00405F7C ist?

Welche Werkzeuge in Delphi 10.1 Berlin verfügbar sind mir dabei zu helfen?

Edit: hat ein bisschen mehr Info ... wenn Sie auf "Pause" die IDE nimmt mich immer an diesem Stück Code in GETMEM.INC:

@SmallPoolWasFull: 
    {Insert this as the first partially free pool for the block size} 
    mov ecx, TSmallBlockType[ebx].NextPartiallyFreePool 

Weitere edit: na ja, ich den Schuldigen gefunden , obwohl ich nicht ehrlich sagen kann, dass die Debug-Tools mich dorthin gebracht haben - sie schienen nur anzuzeigen, dass es nicht in meinem Code war.

I-Code aus dem Netz benutzt hatte, die ich verwenden, um den Windows zu finden angemeldete Benutzer - das ist es:

function GetThisComputerName: string; 
var 
    CompName: PChar; 
    maxlen: cardinal; 
begin 
    maxlen := MAX_COMPUTERNAME_LENGTH +1; 
    GetMem(CompName, maxlen); 
    try 
    GetComputerName(CompName, maxlen); 
    Result := CompName; 
    finally 
    FreeMem(CompName); 
    end; 
end; 

, wenn ich den Code mit einem einfachen Ergebnis ersetzt hatte: ‚12345‘ = die AVs gestoppt. Ich habe nicht geändert, es zu diesem Code:

function GetThisComputerName: string; 
var 
    nSize: DWord; 
    CompName: PChar; 
begin 
    nSize := 1024; 
    GetMem(CompName, nSize); 
    try 
    GetComputerName(CompName, nSize); 
    Result := CompName; 
    finally 
    FreeMem(CompName); 
    end; 
end; 

, die als Bonus zu arbeiten und scheint, nicht AVs verursachen.

Danke für Ihre Hilfe, sehr geschätzt.

+2

unter Extras | Optionen in der IDE zu Embarcadero Debuggers gehen | Sprachausnahmen und stellen Sie sicher, dass Bei Sprachausnahmen benachrichtigen aktiviert ist. Lassen Sie die Ausnahme passieren, und wechseln Sie zu Ansicht | Debug Windows | Call-Stack und Sie sollten in der Lage sein, genau zu sehen, wo es aufgetreten ist. Die Tatsache, dass es nach dem Datenbankzugriff auftritt, liegt wahrscheinlich daran, dass dadurch ein Objekt erstellt wird, das den AV erzeugt, wenn er zerstört wird. Möglicherweise weil es zweimal Free() ed ist. – MartynA

+0

@MartynA: Ich denke, das könnte eine Antwort sein. –

+2

Verwenden Sie madExcept oder ähnliche –

Antwort

4

Unter Tools|Options in den IDE gehen zu Embarcadero Debuggers | Language Exceptions und stellen Sie sicher, Notify on Language Exceptions geprüft. Auch unter Project Options | Compiling, stellen Sie sicher, Debugging | Use debug DCUs geprüft.

Lassen Sie die Ausnahme passieren, dann gehen Sie zu View | Debug Windows | Call stack und Sie sollten in der Lage sein, genau zu sehen, wo es aufgetreten ist. Die Tatsache, dass es nach dem Datenbankzugriff auftritt, liegt wahrscheinlich daran, dass dadurch ein Objekt erstellt wird, das den AV erzeugt, wenn er zerstört wird. Möglicherweise weil es Free() ed zweimal ist.

Wenn das es nicht lösen, können Sie eine Ausnahme-Logging-Tool wie MadExcept von DavidH erwähnt benötigen.

Lesen von Adress 00000008.

Die Tatsache, dass diese Adresse eine geringe Zahl ist, andeutend es die Adresse eines Mitglieds eines Objekts ist (weil sie in der Regel bei niedrigen Offsets von der Basis sind Adresse des Objekts).

Wie finde ich wo in der Anwendung 00405F7C ist?

Mit Ihrer App in der IDE gehen Sie zu Search | Go to Address. Dies sollte es finden, wenn die Ausnahme in Ihrer Anwendung ist und nicht in einem verwandten Modul wie einer .DLL, die es verwendet. Der Menüeintrag wird aktiviert, sobald die Anwendung in der IDE ausgeführt und an einem Haltepunkt angehalten wurde. Außerdem gibt es einen Compiler-Befehlszeilenschalter, um einen Fehler nach Adresse zu finden.

+0

Danke dafür, @MartynA - hatte sich den Call Stack angeschaut, was nicht viel Sinn machte. Gehe zu Adresse ist ausgegraut für mich:/Zeit für madExcept, denke ich. Nochmals vielen Dank, –

+1

Ich habe hinzugefügt Verwenden Sie debug DCUs zu meiner Antwort - in der Regel Fehler aus Doppel-Frees usw. leichter zu finden, wenn Sie die Versionen der VCL DCUs, die Debug-Informationen enthalten verwenden. Wenn Gehe zu Adresse ist grau Vergewissern Sie sich, dass alle Optionen für das Debugging aktiviert sind. – MartynA

+0

Es gibt auch Fehler Befehlszeilen-Compiler-Schalter. –

3

Andere haben erklärt, wie man ein AV diagnostiziert.

In Bezug auf den Code selbst, gibt es Probleme mit ihm:

  1. Am wichtigsten ist, können Sie nicht für den Puffer genügend Speicher zuweisen. GetMem() arbeitet mit Bytes, aber GetComputetName() arbeitet mit Zeichen, und in diesem Fall ist SizeOf (Char) 2 Bytes. Sie ordnen also tatsächlich die Hälfte der Anzahl der Bytes zu, die Sie melden, GetComputerName(), also, wenn es mehr als Sie zuweist schreibt es Heapspeicher beschädigt. Die Beschädigung ging verloren, wenn Sie den Puffer überzuordnen. So nehmen SizeOf(Char) berücksichtigt bei der Zuteilung:

    function GetThisComputerName: string; 
    var 
        CompName: PChar; 
        maxlen: cardinal; 
    begin 
        maxlen := MAX_COMPUTERNAME_LENGTH +1; 
        GetMem(CompName, maxlen * SizeOf(Char)); // <-- here 
        try 
        GetComputerName(CompName, maxlen); 
        Result := CompName; 
        finally 
        FreeMem(CompName); 
        end; 
    end; 
    

Zusätzlich zu, dass:

  1. Sie Fehler von GetComputerName() ignorieren, so dass Sie nicht sind, die gewährleisten, dass CompName ist sogar gültig, um an Result in erster Linie zu übergeben.

  2. sollten Sie SetString(Result, CompName, nSize) anstelle von Result := CompName, da GetComputerName() die tatsächliche CompName Länge ausgibt. Sie müssen keine Verarbeitungszeit verschwenden, wenn RTL die zu kopierende Länge berechnet, wenn Sie die Länge bereits kennen. Und da Sie nicht nach Fehlern suchen, können Sie sich nicht darauf verlassen, dass CompName sowieso null ist, wenn GetComputerName() fehlschlägt.

  3. Sie loswerden GetMem() insgesamt bekommen sollten und nur ein statisches Array auf dem Stapel statt:

    function GetThisComputerName: string; 
    var 
        CompName: array[0..MAX_COMPUTERNAME_LENGTH] of Char; 
        nSize: DWORD; 
    begin 
        nSize := Length(CompName); 
        if GetComputerName(CompName, nSize) then 
        SetString(Result, CompName, nSize) 
        else 
        Result := ''; 
    end; 
    
+0

Die Heap-Beschädigung ist aufgrund SizeOf (char) 2 –

+0

Auch wenn die Funktion erfolgreich ist, garantiert es, dass der Puffer null terminiert ist –

+0

@DavidHeffernan ja, aber nicht, wenn die Funktion fehlschlägt, und der ursprüngliche Code wurde nicht überprüft . Ich habe meine Antwort angepasst. –

Verwandte Themen