Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   EAccessViolation mit StringListe (https://www.delphipraxis.net/192756-eaccessviolation-mit-stringliste.html)

Edelfix 17. Mai 2017 07:59

EAccessViolation mit StringListe
 
Hallo.

Ich habe eine Situation die ich leider nicht nachvollziehen kann.
Es geht um eine Access Vialotion in eine Quelcode Zeile die nur ab und zu kommt.
Ich konnte den Fehler noch nicht nachstellen. Nur Nachträglich im LogFile auslesen.

Die abgekürzte fassung der Funktion:

Delphi-Quellcode:
Function TDMAng.CheckRV(RD:TStringList;var errlist:TStringList):boolean;
begin
  result:=true;
  if not assigned(errlist) then errlist:=TStringList.Create;
  errlist.Clear;
 
  //viele Prüfungen ...
 
  if bPasstNicht then
    errlist.Add('"215","'+'Hinweis: '+'Passt nicht!')

  //viele Prüfungen...
   
  result:= errlist.count=0;
end;
Die Fehlermeldung:

madExcept version : 4.0.12
callstack crc : $00000000, $48d61ed6, $48d61ed6
exception number : 1
exception class : EAccessViolation
exception message : Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000.

Dei Fehlerzeile ist mal "errlist.Clear;" oder "result:= errlist.count=0;".

Ich vermute das die Prüfung "if not assigned(errlist)" manchmal nicht greift.

Kann man die Funktion irgendwie optimieren?

himitsu 17. Mai 2017 08:10

AW: EAccessViolation mit StringListe
 
Der gezeigte Code-Teil an sich kann keinerlei Exceptions erzeugen, mit Ausnahme einer Einzigen, welche sich EOutOfMemory nennt.


Zitat:

Zitat von Edelfix (Beitrag 1371711)
Ich vermute das die Prüfung "if not assigned(errlist)" manchmal nicht greift.

Kann man die Funktion irgendwie optimieren?

Tja, dann hat wohl jemand außerhalb das errlist nicht orgendlich initialisiert, was man dann natürlich auch außerhalb beheben sollte, da es intern niemals einen sicheren Weg geben kann, um einen "defekten" Zeiger zu erkennen.



Pssst, ich glaub in deinem errlist.Add fehlt ein ", aber für den Fehler hier ist es egal. :stupid:

Und bezüglich
Delphi-Quellcode:
result:=true;
sollte der Compiler auch was sagen, falls sich nicht irgendwo ein Exit; versteckt, aber auch erstmal egal.

jaenicke 17. Mai 2017 08:12

AW: EAccessViolation mit StringListe
 
Wenn errlist manchmal einen ungültigen Zeiger enthält, liegt das vermutlich daran, dass diese übergebene Liste irgendwo mit Free freigegeben, die Variable aber weiter verwendet wird.

Wenn du dort stattdessen FreeAndNil benutzt, funktioniert auch die Prüfung mit Assigned.

Allerdings stimmt architektonisch dort etwas nicht, wenn manchmal, aber nicht immer, Instanzen in einer solchen Routine erzeugt werden. Für Erstellung und Freigabe muss immer jemand konkret zuständig sein, am besten in der gleichen Ebene (sprich z.B. nicht in einer Klasse die Erzeugung und in einer anderen die Freigabe).

Jasocul 17. Mai 2017 08:14

AW: EAccessViolation mit StringListe
 
Delphi-Quellcode:
//Function TDMAng.CheckRV(RD:TStringList;var errlist:TStringList):boolean;
Function TDMAng.CheckRV(RD:TStringList;errlist:TStringList):boolean;
begin
  result:=true;
  if not assigned(errlist) then errlist:=TStringList.Create;
  errlist.Clear;
 
  //viele Prüfungen ...
 
  if bPasstNicht then
    errlist.Add('"215","'+'Hinweis: '+'Passt nicht!')

  //viele Prüfungen...
   
  result:= errlist.count=0;
end;
Erstmal das "var" beim Prozedurkopf für errlist rausnehmen. Das könnte das Problem schon beheben.
Ansonsten den Debugger nutzen und prüfen, wie die Inhalte sind und wo diese sich ändern und damit eine AV auslösen.

EDIT:
Den Unsinn mit dem "var" bitte ignorieren.

himitsu 17. Mai 2017 08:20

AW: EAccessViolation mit StringListe
 
Zitat:

Zitat von Jasocul (Beitrag 1371714)
Erstmal das "var" beim Prozedurkopf für errlist rausnehmen. Das könnte das Problem schon beheben.

Dann hast du aber 100%ig in Zeile 2 ein Speicherleck. :angle2:
Nein, wenn der Zeiger ungültig ist, dann bleibt er das auch, egal ob mit oder ohne Var, da sich innerhalb dieser Funktion rein garnichts ändert.

Und was jaenicke meint:
* entweder jemand in der gleichen Klasse kümmert sich um die Freigabe, oder garnichts erstellen
* oder wenn errlist Assigned ist, dann die Fehler loggen, bzw. ansonsten nur der Boolean-Result

Jasocul 17. Mai 2017 08:37

AW: EAccessViolation mit StringListe
 
Zitat:

Zitat von himitsu (Beitrag 1371715)
Zitat:

Zitat von Jasocul (Beitrag 1371714)
Erstmal das "var" beim Prozedurkopf für errlist rausnehmen. Das könnte das Problem schon beheben.

Dann hast du aber 100%ig in Zeile 2 ein Speicherleck. :angle2:

Asche auf mein Haupt. Du hast natürlich Recht.

SebastianZ 17. Mai 2017 08:49

AW: EAccessViolation mit StringListe
 
Zitat:

Zitat von Edelfix (Beitrag 1371711)
Hallo.

Ich habe eine Situation die ich leider nicht nachvollziehen kann.
Es geht um eine Access Vialotion in eine Quelcode Zeile die nur ab und zu kommt.
Ich konnte den Fehler noch nicht nachstellen. Nur Nachträglich im LogFile auslesen.

Die abgekürzte fassung der Funktion:

Delphi-Quellcode:
Function TDMAng.CheckRV(RD:TStringList;var errlist:TStringList):boolean;
begin
  result:=true;
  if not assigned(errlist) then errlist:=TStringList.Create;
  errlist.Clear;
 
  //viele Prüfungen ...
 
  if bPasstNicht then
    errlist.Add('"215","'+'Hinweis: '+'Passt nicht!')

  //viele Prüfungen...
   
  result:= errlist.count=0;
end;

Wie schon gesagt wurde, wird hier die Liste mit free vorderbei freigegeben.
Ich würde die Liste nicht als Var-Parameter übergeben. Dadurch ist nicht mehr ersichtlich wer die Hoheit über die Liste hat, und wer sie freizugeben hat.

Sauberer wäre aus meiner Sicht, du baust eine lokale Liste auf, gibst nur den String zurück, und fügst den String dann in die eigentliche Liste ein.

Also so in etwa:

Delphi-Quellcode:
function CheckRV(RD:TStringList; out ErrorText: String): Boolean;
var
  ErrorList: TStringList;
begin
  ErrorList := TStringList.Create;
  try
    result:=true;
 
    //viele Prüfungen ...
 
    if bPasstNicht then
      ErrorList.Add('"215","'+'Hinweis: '+'Passt nicht!')

    //viele Prüfungen...
   
    result:= ErrorList.count=0;
    ErrorText := ErrorList.Text;
  finally
    FreeAndNil(ErrorList);
  end
end;


procedure foo;
var
  lstError: TStringList;
  ErrorText: String;
begin
  lstError := TStringList.Create;
  try
    if not CheckRV(dummy, ErrorText) then
      lstError.Text := lstError.Text + ErrorText;

  finally
    FreeAndNil(lstError);
  end

end;

hoika 17. Mai 2017 09:21

AW: EAccessViolation mit StringListe
 
Hallo,
Zitat:

Ich würde die Liste nicht als Var-Parameter übergeben. Dadurch ist nicht mehr ersichtlich wer die Hoheit über die Liste hat, und wer sie freizugeben hat.
100% Zustimmung.
Wer die Liste erzeugt, muss sie auch wieder freigeben.

Falls der Aufwand zu gross ist, dann sollte die Liste mit FreeAndNil freigegeben werden.

Zur Not hilft auch ein Singleton-Pattern,
um sicherzustellen, dass die StringListe wirklich nur einmal erzeugt wird.

Edelfix 17. Mai 2017 10:37

AW: EAccessViolation mit StringListe
 
Danke an alle.


Ich werde den Vorschlag von SebastianZ ümsetzen.

Ich denke auch das ein String als Var-Parameter unproblematischer ist.

Vielen Dank.


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:36 Uhr.

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