Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Zugriffsverletzung beim Zerstören der TIniFile-Instanz (https://www.delphipraxis.net/206756-zugriffsverletzung-beim-zerstoeren-der-tinifile-instanz.html)

Codehunter 29. Jan 2021 21:23

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Zitat:

Zitat von himitsu (Beitrag 1481792)
Ob Free oder FreeAndNil macht keinen Unterschied, denn FreeAndNil ruft auch nur Free auf.
Außer dass FreeAndNil eigentlich NilAndFree heißen müsste, da es zuerst die Variable auf NIL setzt und danach Free aufruft.

Womöglich ist genau das der Punkt? Wobei, wenn ich mir die Quelle von FreeAndNil anschaue, dann tut das schon noch ein bissle mehr als das. Jedenfalls war es für mich immer von Vorteil, die Variable definiert auf nil zu setzen. Und ich bin mir nicht so ganz sicher, ob hier nicht noch ein wenig Compiler Magic ins Spiel kommt...

himitsu 29. Jan 2021 22:04

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
FreeAndNil kopiert nur den Objektzeiger
und setzt vor dem Free die originale Variable auf NIL. (erspart sich so ein TryFinally)

Delphi-Quellcode:
Temp := VAR; // mit ARC sind einfach die Zeilen 1 und 3 nutzlos und werden weggelassen
VAR := nil;
Temp.Free;

// statt

try
  VAR.Free;
finally
  VAR := nil;
end;
Ohne ARC, passiert mit der Objekt-Referenz nichts. (das kopieren der Variable macht nichts, außer den Pointer/Integer zu kopieren)

Und mit ARC wird effektiv nur die VARiable auf NIL gesetzt. (original würde die Variable kopiert, dabei AddRef/INC ausgeführt,
dann die alte Variable auf NIL gesetzt und somit ReleaseRef/DEC, und am Schluß Free, was aber im bei ARC garnichts macht)


PS: Das Application.FormCreate ist gegenüber dem TForm.Create das Selbe, wie FreeAndNil gegenüber einem Free.
Dort wird die Variable zuerst gesetzt, bevor Create ausgeführt wird. (eigentlich wird die Variable ja erst gesetzt, nachdem das Create fertig ist, was blöd ist, wenn eine Form-Referenz in der DFM vorkommt, oder jemand im Create oder einem Property-Setter so blöd ist und die globale Form-Variable benutzt, anstatt Self)
Und beim FreeAndNil wird eben die Variable gelöscht, bevor Destroy ausgeführt wird.

jaenicke 30. Jan 2021 18:29

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Codehunter (Beitrag 1481791)
In meinem 10.2.3 knallt das mit einer AV.

Das wäre dann aber ein ziemlich böser Bug. Bei mir läuft es mit 10.2.3 einfach durch wie es auch sein sollte.
Wie sieht denn der Stacktrace aus bzw. was passiert, wenn du in das Free hinein debuggst? Eigentlich sollte dort Self = nil sein und somit kein Code ausgeführt werden:
Anhang 53590

Bist du sicher, dass nicht FastMM oder ähnliches aktiv ist? Denn die prüfen so etwas und lösen dann eine Exception aus.

Uwe Raabe 30. Jan 2021 22:16

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Zitat:

Zitat von jaenicke (Beitrag 1481822)
Bist du sicher, dass nicht FastMM oder ähnliches aktiv ist? Denn die prüfen so etwas und lösen dann eine Exception aus.

Dir Prüfung auf nil erfolgt doch im Free. Ich glaube kaum, dass FastMM das in irgendeiner Weise abfängt, geschweige denn sich überhaupt dafür interessiert.

jaenicke 31. Jan 2021 07:44

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1481824)
Dir Prüfung auf nil erfolgt doch im Free. Ich glaube kaum, dass FastMM das in irgendeiner Weise abfängt, geschweige denn sich überhaupt dafür interessiert.

Das würde ich auch nicht vermuten, aber so etwas wäre die einzige Variante (außer kaputtem Speicher), die ich mir vorstellen kann. Vielleicht gibt es ja ein Tool, das sich da einklinkt (warum auch immer).

Bei FastMM passiert (eben getestet) in der Tat nichts.

Uwe Raabe 31. Jan 2021 08:13

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Ich tippe schlichtweg auf Test-Case-Error. Ich kann mir nicht vorstellen, dass mein Beispiel in irgendeiner Delphi-Version (eventuell nach Anpassung der uses-Anweisung) eine Exception auslöst.

stahli 31. Jan 2021 15:01

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Sind da vielleicht noch Threads am Arbeiten, die irgendein Problem haben (und es nur so aussieht, als läge es am TIniFile)?

TheSledgeHammer 1. Feb 2021 09:41

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Zitat:

Zitat von Codehunter (Beitrag 1481791)
Noch ein Gedanke: Ist PChar hier überhaupt gleich PChar aus der Hostanwendung? Stichwort PAnsiChar und PWideChar...

Also PChar in der Anwendung ist idetnisch zu PChar in der DLL, ja :) Es ist mit ein und derselben Delphi-Version kompiliert und beide Male als Win32.

TheSledgeHammer 1. Feb 2021 09:47

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Zitat:

Zitat von stahli (Beitrag 1481854)
Sind da vielleicht noch Threads am Arbeiten, die irgendein Problem haben (und es nur so aussieht, als läge es am TIniFile)?

Auch wenn ich Threads an sich ganz gern habe, ist das in dem Fall auszuschließen. Ich hatte ja bereits meinen Code gepostet und da war nix von irgendwelchen Threads und die lokale Variable ist auch echt nur lokal.

TheSledgeHammer 1. Feb 2021 09:47

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Zitat:

Zitat von Codehunter (Beitrag 1481795)
Zitat:

Zitat von himitsu (Beitrag 1481792)
Ob Free oder FreeAndNil macht keinen Unterschied, denn FreeAndNil ruft auch nur Free auf.
Außer dass FreeAndNil eigentlich NilAndFree heißen müsste, da es zuerst die Variable auf NIL setzt und danach Free aufruft.

Womöglich ist genau das der Punkt? Wobei, wenn ich mir die Quelle von FreeAndNil anschaue, dann tut das schon noch ein bissle mehr als das. Jedenfalls war es für mich immer von Vorteil, die Variable definiert auf nil zu setzen. Und ich bin mir nicht so ganz sicher, ob hier nicht noch ein wenig Compiler Magic ins Spiel kommt...

D.h. irgendwie sollte ich es mit FreeAndNil probieren, aber irgendwie auch nicht? :wall:

jaenicke 1. Feb 2021 12:12

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Hast du einmal einen Haltepunkt auf das Destroy der TIniFile Klasse gesetzt? Dann siehst du dort vielleicht mehr...

Fritzew 1. Feb 2021 13:29

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Stimmen die Callingconventions in der Dll und dem aufrufenden Programm?
Also cdecl oder stdcall?
Für mich sieht Dein Fehler ja nach einem kaputten Stack aus, das könnte das problem sein.

TheSledgeHammer 1. Feb 2021 14:26

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Zitat:

Zitat von Fritzew (Beitrag 1481931)
Stimmen die Callingconventions in der Dll und dem aufrufenden Programm?
Also cdecl oder stdcall?
Für mich sieht Dein Fehler ja nach einem kaputten Stack aus, das könnte das problem sein.

Ist alles CDECL.

TheSledgeHammer 1. Feb 2021 14:29

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Zitat:

Zitat von jaenicke (Beitrag 1481924)
Hast du einmal einen Haltepunkt auf das Destroy der TIniFile Klasse gesetzt? Dann siehst du dort vielleicht mehr...

Ja, das Problem mit den Haltepunkten :D Dieser Fehler tritt nur zur Laufzeit bei Releases auf. Offenbar nicht spezifisch an einem Rechner oder bei einem bestimmten Programm (aktuell verwenden 2 oder 3 Programme diese DLL) und auch nicht User-bezogen. Ich will es mal so formulieren: von 30 Mal, wo die DLL aufgerufen wird, knallt es 10 Mal. Ich erhalte ja dann von madExcept den Dump, den hatte ich ja auch schon mal gepostet. Und wie so häufig knallt es nie, wenn der Entwickler das probiert. Ihr glaub nicht, wie sehr ich mich angestrengt hab, diesen Fehler zu provozieren, damit der Debugger mir da an die Stelle springt...

jaenicke 1. Feb 2021 15:58

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Das spricht umso mehr für die bereits erwähnte Vermutung, dass der Speicher dort kaputt ist.

Hast du die DLL einmal mit FastMM und aktiviertem FullDebugMode kompiliert? Das könnte auch auf der Entwicklermaschine solche Fehler aufdecken. Oder auch wenn es knallt: Dann bekommst du evtl. Stacktraces von Erstellung und fehlerhafter Änderung des Speichers. (Du musst die FullDebugMode DLL von FastMM dann mitliefern.)

TheSledgeHammer 2. Feb 2021 08:12

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Also ich hab das jetzt eingerichtet. Und bei mir, wenn ich das auf dem Entwicklungsrechner laufen lasse, wird beim Shutdown offenbar nicht ein einziger MemLeak entdeckt. Das kann schon nicht sein :lol: Also irgendwo ist immer einer ;)

Nur weiß ich nicht, was ich noch groß machen soll. FastMM4 ist als erste Unit im DLL-Projekt eingebunden. Muss das zusätzlich auch in die aufrufende Applikation mit rein? Zudem ist im DLL-Projekt
Delphi-Quellcode:
{$IFDEF DEBUG}ReportMemoryLeaksOnShutdown := true;{$ENDIF}
eingestellt. Auch hier gilt wieder: nicht beim Aufrufer.

FastMM wurde so eingerichtet, dass der FullDebug-Mode aktiv ist. Allerdings würde ich hier gerne wissen, wo das gespeichert wird? Ich mein, es gibt da ne .inc-Datei, wo man das alles aktivieren kann. Muss die dann auch noch zur FullDebug-DLL mit dazu gelegt werden?!

Poelser 2. Feb 2021 08:19

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Zitat:

Zitat von TheSledgeHammer (Beitrag 1481990)
Muss die dann auch noch zur FullDebug-DLL mit dazu gelegt werden?!

Nein, muss sie nicht. Die wird nur zum Compilieren gebraucht, um die dort gemachten Einstellungen in die Exe einzucompilieren.

LG aus dem hohen Norden, Edmund

TheSledgeHammer 2. Feb 2021 08:32

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Ok, d.h. ich hab offenbar tatsächlich keine MemLeaks? :shock:

himitsu 2. Feb 2021 09:30

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Kommt drauf an, was du als Memory-Leck ansiehst.

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
  ReportMemoryLeaksOnShutdown := True; // oder in der DPR gemacht
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  for var i := 0 to 1000 do
    TComponent.Create(Self); // MemoryLeak zu Laufzeit, aber bei ProgrammEnde weg (da, wo ReportMemoryLeaksOnShutdown nachsieht)
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  for var i := 0 to 1000 do
    TComponent.Create(nil); // MemoryLeak bis zum Ende
end;

TheSledgeHammer 2. Feb 2021 12:19

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Ja ok, das ist klar, das ist auch kein tatsächlicher Memory Leak, da der Owner sich ja um das Aufräumen kümmert. Ein TInitFile hat keinen Owner, ergo sollte man es nach dem Erzeugen auch wieder freigeben, sonst gibt es einen Memory Leak. Und in meinem Fall gibt's dann sogar noch eine AV oben drauf :roll:

stahli 2. Feb 2021 16:05

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Zitat:

Zitat von TheSledgeHammer (Beitrag 1481994)
Ok, d.h. ich hab offenbar tatsächlich keine MemLeaks? :shock:

Bau doch mal testweise einen ein.
Dann weißt Du zumindest, ob sowas korrekt gefunden wird.

jaenicke 2. Feb 2021 17:53

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Wenn FastMM auch nichts findet, bleibt nur mit Logs zu analysieren... z.B. den Speicher des Objekts nach der Erzeugung als Dump loggen und dann bei der Freigabe, ...
Das ist nicht schön, aber solche Fehler sind leider nicht so einfach zu finden.

himitsu 2. Feb 2021 19:31

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Das volle FastMM kann bei Speicherfreigabe den Speicher überschreiben (mit einem Muster markieren)
so würde z.B. eine Doppelfreigabe oder ein Zugriff nach der Freigabe auffallen.
-> Man müsste nur noch das entgültige Freigeben ein bissl verzögern, damit auch freigegebener und inzwischen wiederverwendeter Speicher in diese Prüfung fallen.

Gegen sowas wie Buffer-Overrun oder komplett falsche/ungültige Zeiger kann man sich aber nicht wirklich wehren.


Und ja, möglich wäre es viele Wichtige oder gleich alle Speicheranforderungen/-freigaben in ein Log schreiben zu lassen.
Wenn es dann später knallt, dann kann man z.B. schauen was vorher alles an der Stelle mal war.

Blup 3. Feb 2021 10:06

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Zitat:

Zitat von TheSledgeHammer (Beitrag 1481614)
Delphi-Quellcode:
procedure TFormDynamicSearchDialog.LoadIni;
var
  iniFile: TIniFile;
  sec: String;
begin

  if FIniFile <> '' then
  begin

    sec := 'Search';

    iniFile := nil;

    try

      iniFile := TIniFile.Create(FIniFile);

      miSqlLinkCmdAnd.Checked := iniFile.ReadBool(sec, miSqlLinkCmdAnd.Name, true);
      miSqlLinkCmdOr.Checked := iniFile.ReadBool(sec, miSqlLinkCmdOr.Name, false);

      if miSqlLinkCmdAnd.Checked then
        FSqlLinkCmd := slcAnd
      else if miSqlLinkCmdOr.Checked then
        FSqlLinkCmd := slcOr;

      case iniFile.ReadInteger(sec, pcMain.Name, 1) of
        0: tbFavourites.Click;
        1: tbExpert.Click;
        2: tbFavourites.Click;
      end;

    finally
      if iniFile <> nil then
        iniFile.Free;
    end;

  end else
  begin
    // if no INI has been defined, set SQL link command as default here
    miSqlLinkCmdAND.Checked := true;
    FSqlLinkCmd := slcAnd;
  end;

end;
Und bei dem "ShowModal" sollte man sich nicht verwirren lassen :) Das muss ich aber glaub genauer erklären. Im Interface zur Dll (Unit-Name "DynamicSearchDialogDllInterface") gibt es eine Methode, die "ShowModal" heißt. Diese wiederum ruft die aus der DLL exportierte Methode "ShowModal" auf (Unit-Name "DynSearchDialog"). Und in dieser Methode wird dann das tatsächliche "ShowModal" des TForm-Objekts aufgerufen (Unit-Name "DynamicSearchDialog"). D.h. ShowModal wird tatsächlich nur einmal aufgerufen, allerdings gibt es davor noch andere Methoden, die halt exakt so heißen. Hat was mit der Integration zu tun, ich wollte halt nicht, dass alle Entwickler ihren Code anpassen müssen, wenn sie auf die DLL umsteigen wollen; oder zumindest nur ganz gering anpassen müssen :P

Das Fehlerprotokoll zeigt eindeutig den rekursiven Aufruf von TDynamicSearchDialog.ShowModal und TFormDynamicSearchDialog.LoadIni.
Ausgelöst in TFormDynamicSearchDialog.LoadIni durch die Zeile "tbExpert.Click;".

TheSledgeHammer 3. Feb 2021 13:26

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Ja, eines dieser Fehlerprotokolle zeigt eine Rekursion, da geb ich dir Recht. Ich hab aber genau so viele Berichte mit Rekursion, wie solche, bei denen der Fehler nicht rekursiv geschieht, sondern wo es direkt beim ShowModal knallt. Ich hab - zugegeben - nicht geschaut, welchen Bericht ich da jetzt genommen hab, weil die Zeile, wo es knallt, exakt identisch ist. Ich kann dir aber beim besten Willen nicht sagen, warum in diesem Dump eine Rekursion enthalten ist... LoadIni() wird nur einmal aufgerufen...

TheSledgeHammer 3. Feb 2021 13:39

AW: Zugriffsverletzung beim Zerstören der TIniFile-Instanz
 
Zitat:

Zitat von jaenicke (Beitrag 1482053)
Wenn FastMM auch nichts findet, bleibt nur mit Logs zu analysieren... z.B. den Speicher des Objekts nach der Erzeugung als Dump loggen und dann bei der Freigabe, ...
Das ist nicht schön, aber solche Fehler sind leider nicht so einfach zu finden.

Ja, das klingt fast so als wäre das nötig. Kannst du mir erklären wie ich das machen kann? Oder hast du ne Anleitung im WWW, die was taugt?


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:59 Uhr.
Seite 2 von 2     12   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz