Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Nicht nachzuvollziehende EAccessViolation (https://www.delphipraxis.net/164905-nicht-nachzuvollziehende-eaccessviolation.html)

genesisv 5. Dez 2011 16:13

Nicht nachzuvollziehende EAccessViolation
 
Hallo,

in letzter Zeit häufen sich AccessViolations in unseren Projekten, wo ich leider an meine Grenzen stoße. Die sind für mich nicht nachzuvollziehen, ev. hat hier jemand eine Idee. Folgend der Protokolleintrag (JCL Error Dialog):

Code:
Zugriffsverletzung bei Adresse 00404ED4 in Modul 'lps.exe'. Lesen von Adresse FFFFFFFD.
------------------------------------------------------------------------------
Fehlerklasse: EAccessViolation
Fehlermeldung: Zugriffsverletzung bei Adresse 00404ED4 in Modul 'lps.exe'. Lesen von Adresse FFFFFFFD.
Fehleradresse: 00404ED4
------------------------------------------------------------------------------
Hauptthread ID = 1084
Fehlerthread ID = 1084
------------------------------------------------------------------------------
Fehlerstack
Stackliste, erzeugt 05.12.2011 14:04:27
[00404ED4]{lps.exe    } System.TObject.Free
[0085B3AD]{lps.exe    } HTTPV2.TFormHTTPV2.Post (Line 354, "..\MainSystem\HTTPV2.pas" + 7)
[0088EDFE]{lps.exe    } Main.TForm_Main.UploadPrograms (Line 2636, "Main.pas" + 21)
[00893E1C]{lps.exe    } Main.TForm_Main.ShowProgramEditorDelayed (Line 3856, "Main.pas" + 43)
[0046721B]{lps.exe    } ExtCtrls.TTimer.Timer (Line 2281, "C:\builds\Tp\vcl\i18n\de\ExtCtrls.pas" + 1)
[0043844C]{lps.exe    } Classes.StdWndProc
------------------------------------------------------------------------------
Callstack des Hauptthread
Stackliste, erzeugt 05.12.2011 14:04:27
[77DA64F4]{ntdll.dll  } KiFastSystemCallRet
Meiner Meinung nach dürfte der Fehler so aber gar nicht auftreten können. In der Zeile 354 von HTTPV2.TFormHTTPV2.Post wird eine Funktion der selben Form aufgerufen:

Delphi-Quellcode:
function TFormHTTPV2.Post(Url, Filename, ErrorHint: string): integer;
begin
348: ClearItems;
349: // Anmerkung: Items[x] ist ein array-property, das das interne array - bei bedarf - automatisch erhöht
350: Items[0].RequestType := httpPost;
351: Items[0].URL := Url;
352: Items[0].LocalFile := Filename;
353:
354: Result := Send(ErrorHint);
end;

function TFormHTTPV2.Send(ErrorHint: string): integer;
begin
...
end;
Also meiner Meinung nach müsste er doch zumindest in .Send reinlaufen und dort einen Fehler protokollieren. Laut stack list wäre ja entweder die Form selbst, die Funktion "Send" oder der string Errorhint nicht vorhanden, alles eher unwahrscheinlich :)

Deutet das auf interne Speicherlecks/bugs hin, die sich erst später auswirken? Im Normalfall funktioniert der Aufruf anstandslos, aber sporadisch werden uns AccessViolations ähnlich dieser gemeldet, mit denen man einfach nichts mehr anfangen kann.

p80286 5. Dez 2011 17:07

AW: Nicht nachzuvollziehende EAccessViolation
 
Jo, auch ich habe ein Problem den Fehler nachzuvollziehen, da ich vermute, daß das
Delphi-Quellcode:
clearItems;
den Fehler verursacht.
Aber ohne die entsprechenden Sourcen, fällt es schwer, hierzu etwas Vernünftiges zu sagen.
Ach ja, wie
Delphi-Quellcode:
Items
definiert ist, würde mich auch interessieren.
(array of TMyRecord...?)

Gruß
K-H

Bjoerk 5. Dez 2011 17:09

AW: Nicht nachzuvollziehende EAccessViolation
 
Zeig mal TFormHTTPV2.Send(ErrorHint: string): integer;

genesisv 5. Dez 2011 17:14

AW: Nicht nachzuvollziehende EAccessViolation
 
Nun, da wird's halt etwas ausführlicher :)

Delphi-Quellcode:
 
  TV2Request = record
    RequestType: TV2RequestType;
    Res: integer;
    URL: string;
    LocalFile: string;
    HTTPContent: string;
    RequestVars: TStringList;
  end;
  PV2Request = ^TV2Request;

  TFormHTTPV2 = class(TForm)
  private
    FV2Requests: array of TV2Request;

    function GetItem(x: integer): PV2Request;
    function GetItemCount: integer;
  public
    procedure ClearItems;

    property ItemCount: integer read GetItemCount;
    property Items[x: integer]: PV2Request read GetItem;
  end;

procedure TFormHTTPV2.ClearItems;
begin
  SetLength(FV2Requests, 0);
end;

function TFormHTTPV2.GetItem(x: integer): PV2Request;
begin
  if (x >= 0) and (x <= High(FV2Requests)) then
  begin
    Result := @FV2Requests[x];
    exit;
  end;

  SetLength(FV2Requests, Length(FV2Requests) + 1);
  FillChar(FV2Requests[High(FV2Requests)], SizeOf(TV2Request), 0);

  Result := @FV2Requests[High(FV2Requests)];
  Result.RequestVars := TStringList.create;
end;

function TFormHTTPV2.GetItemCount: integer;
begin
  Result := length(FV2Requests);
end;
Das sollte alles an relevantem Code sein. Eine Sache die mir selber gerade auffällt, bei ClearItems sollte ich nat. auch die StringList freigeben. Möglich, dass sich ein fehlendes Freigeben von Stringlists so auswirkt?

Besten Dank schon mal

DeddyH 5. Dez 2011 17:20

AW: Nicht nachzuvollziehende EAccessViolation
 
IMHO wäre das Ganze um Längen einfacher zu verwalten, wenn man aus TV2Request eine Klasse macht (zumindest solange eine Objektinstanz, hier eine Stringliste, enthalten ist) und aus FV2Requests eine TObjectList.

genesisv 5. Dez 2011 17:26

AW: Nicht nachzuvollziehende EAccessViolation
 
Ok, sorry, das .free für die Stringlists übernimmt das die .Send-Funktion, kA warum aber irgendeinen Sinn wird das schon gehabt haben. Die .Send kann ich nat. posten, aber dadurch wird's halt nicht kürzer ... ;)

Delphi-Quellcode:
function TFormHTTPV2.Send(ErrorHint: string): integer;
var
  E, I, FS: integer;
  FileStream: TFileStream;
  MemoryLst: TStringList;
  ActiveCursor: TCursor;
  ErrorMsg: string;
  HTTPRequest: TclHttpRequest;
  Rec: TRect;
begin
  ModalResult := mrNone;
  LastReasonPhrase := 'OK';

  // Leave on demo mode
  if FIsDemoMode then
  begin
    Result := -10000;
    Hide;
    exit;
  end;

  if Visible then
  begin
    Rec := Rect(left, top, width - left, height - top);
    MouseFencer.ExecuteEnh(Rec);
  end;

  Result := -1;
  ErrorMsg := '';

  ActiveCursor := Screen.Cursor;
  if Length(FV2Requests) > 1 then
    MaxValue := Length(FV2Requests)
  else
    MaxValue := 60;
  UserValue := 0;
  Busy := False;

  // Load error message
  if ErrorHint <> '' then
    LoadErrorHint(ErrorHint);

  // Set minimum timeout (30000) if visible, or not timeout (100 sec) if file exists
  if FileExists(ExtractFilePath(application.exename) + '~notimeout.txt') then
    HTTP.TimeOut := 100000
  else if Visible then
    HTTP.TimeOut := Max(HTTP.Timeout, FMiddleTimeOut);

  // Init
  I := 0;
 
  repeat
    if HTTP.Active then
      try
        HTTP.Close;
      except
      end;

    ModalResult := mrNone;

    // Change cursor if invisible
    if not Visible then
      Screen.Cursor := crHourGlass;

    // Reset controls
    Notebook.PageIndex := 0;
    LabelError1.Hide;
    LabelProxy.Hide;
    LabelProxy2.Hide;
    ButtonOK.Hide;
    ButtonAbort.Caption := '&Abbrechen';

    UserValue := 0;
    if Length(FV2Requests) > 1 then
      MaxValue := Length(FV2Requests)
    else
      MaxValue := HTTP.TimeOut div 25;

    Application.ProcessMessages;
    TimerTime.Enabled := True;

    if not IsConnectedToInternet then
    begin
      Result := INTERNET_STATE_DISCONNECTED;
      ErrorMsg := 'HTTP-Fehler: Keine bestehende Internetverbindung gefunden';
    end
    else
    begin
      SetProxySettings;
      FWebAccess := noSuccess;

      while I <= High(FV2Requests) do
      begin
        if Length(FV2Requests) <= 1 then
        begin
          UserValue := 0;
          if Visible then
            Sleep(250);
        end;

        HTTPRequest := TclHttpRequest.Create(self);
        HTTPRequest.Header.Accept := '*/*';
        //HTTPRequest.Header.CharSet := 'UTF-8';
        HTTPRequest.Header.ContentType := 'multipart/form-data';

        // Replace spaces
        if Pos('?', FV2Requests[i].URL) > 0 then
          FV2Requests[i].URL := ReplaceStr(FV2Requests[i].URL, #32, '%20');
        DebugOut('DL # ' + inttostr(i) + ': ' + FV2Requests[i].URL);

        try
          // Reset controls
          MemoryLst := Nil;
          FileStream := Nil;

          // Prepare request
          if Pos('=', FV2Requests[i].LocalFile) > 0 then
            HTTPRequest.AddSubmitFile(StrBefore('=', FV2Requests[i].LocalFile), StrAfter('=', FV2Requests[i].LocalFile));
          for e := 0 to FV2Requests[i].RequestVars.count - 1 do
            HTTPRequest.AddFormField(StrBefore('=', FV2Requests[i].RequestVars[e]), StrAfter('=', FV2Requests[i].RequestVars[e]));
          for e := 0 to HTTPRequest.Count - 1 do
            HTTPRequest.Items[e].Canonicalized := False;

          // Prepare stringlist/stream
          if (FV2Requests[i].RequestType = httpGet) and (FV2Requests[i].LocalFile <> '') then
            FileStream := TFileStream.create(FV2Requests[i].LocalFile, fmCreate)
          else
            MemoryLst := TStringList.create;

          try
            FV2Requests[i].Res := 0;
            FV2Requests[i].HTTPContent := '';

            Busy := True;
            if FV2Requests[i].LocalFile = '' then
            begin
              if FV2Requests[i].RequestType = httpGet then
                HTTP.Get(FV2Requests[i].URL, MemoryLst)
              else
                HTTP.Post(FV2Requests[i].URL, HTTPRequest, MemoryLst);
            end
            else
            begin
              if FV2Requests[i].RequestType = httpGet then
                HTTP.Get(FV2Requests[i].URL, FileStream)
              else
                HTTP.Post(FV2Requests[i].URL, HTTPRequest, MemoryLst);
            end;
            Busy := False;

            if MemoryLst <> Nil then
              FV2Requests[i].HTTPContent := MemoryLst.Text
            else if FileStream <> Nil then                
              FV2Requests[i].HTTPContent := 'FILE';

            Result := 200;
            FV2Requests[i].Res := Result;
            LastReasonPhrase := 'OK';
            ErrorMsg := '200: OK';

            if HTTP.ProxySettings.Server <> '' then
              FWebAccess := proxySuccess
            else
              FWebAccess := directSuccess;

            if MemoryLst <> Nil then
              LogHTTPMessage(ErrorMsg, Length(MemoryLst.Text))
            else if FileStream <> Nil then
              LogHTTPMessage(ErrorMsg, FileStream.Size);

          finally

            if MemoryLst <> Nil then
              MemoryLst.Free
            else if FileStream <> Nil then
            begin
              FS := FileStream.Size;
              FileStream.free;

              if FS = 0 then
              if FV2Requests[i].RequestType = httpGet then
              if FV2Requests[i].LocalFile <> '' then
              if FileExists(FV2Requests[i].LocalFile) then
              if FS = 0 then
                DeleteFile(FV2Requests[i].LocalFile);
            end;

            if HTTPRequest <> Nil then
              HTTPRequest.Free;
            HTTPRequest := Nil;

          end;
        except
          on E: EclSocketError do
          begin
            Busy := False;
            Result := E.ErrorCode;
            LastReasonPhrase := E.Message;
            ErrorMsg := Format('%s #%d: %s', ['EclSocketError', E.ErrorCode, E.Message]);
            FV2Requests[i].Res := Result;
            LogHTTPMessage(ErrorMsg, 0);

            if E.ErrorCode = 404 then
            begin
              // not found
              Result := 200;
              LastReasonPhrase := 'OK';
              FV2Requests[i].Res := Result;
              ErrorMsg := '200: OK';
            end
            else if HTTP.ProxySettings.Server <> '' then
            begin
              // Try without proxy
              UserValue := 0;
              HTTP.ProxySettings.Server := '';
              Abort;
              Continue;
            end
            else
              break;

          end;

          on E: EclHttpError do
          begin
            Busy := False;
            Result := E.ErrorCode;
            LastReasonPhrase := E.ResponseText;
            FV2Requests[i].Res := Result;
            ErrorMsg := Format('%s #%d: %s', ['EclHttpError', E.ErrorCode, E.ResponseText]);

            LogHTTPMessage(ErrorMsg, 0);
            break;
          end;

          on E: Exception do
          begin
            Busy := False;
            Result := E.HelpContext;
            LastReasonPhrase := E.Message;
            FV2Requests[i].Res := Result;
            ErrorMsg := Format('%s #%d: %s', ['Exception', E.HelpContext, E.Message]);

            LogHTTPMessage(ErrorMsg, 0);
            break;
          end;

        end;

        if Length(FV2Requests) <= 1 then
          UserValue := ProgressBar.MaxValue
        else
          UserValue := UserValue + 1;

        Inc(i);
      end;
    end;

    Busy := False;
   
    // Set progress to max
    TimerTime.Enabled := False;
    UserValue := ProgressBar.MaxValue;

    // Set error messages
    LabelError1.caption := ErrorMsg;
    LabelError1.hint := ErrorMsg;
    LabelError2.caption := ErrorMsg;
    LabelError2.hint := ErrorMsg;

    // Change to error page if necessary
    if Result <> 200 then
    if ErrorHint <> '' then
      Notebook.PageIndex := 1;

    // Reset cursor or hide on success
    if not Visible then
      Screen.Cursor := ActiveCursor
    else if Result = 200 then
      Hide;

    // Wait for retry or cancel button
    if Result <> 200 then
    if Result <> INTERNET_STATE_DISCONNECTED then
    if Visible then
    if ModalResult <> mrAbort then  
    begin
      LabelError1.Show;

      if Assigned(FOnProxyClick) then
      begin
        LabelProxy.Show;
        LabelProxy2.Show;
      end;

      ButtonAbort.Caption := '&Überspringen';
      ButtonOK.Show;

      repeat
        Application.ProcessMessages;
        Sleep(1);

        if not Visible then
          ModalResult := mrAbort;

      until ModalResult <> mrNone;

    end;

    // Leave if: invisible, success, noInternet or Cancel-Button
  until (Visible = False) or (Result = 200) or (Result = INTERNET_STATE_DISCONNECTED) or (ModalResult <> mrOK);

  // Set timeout for next try (faster)
  if Result <> INTERNET_STATE_DISCONNECTED then
  if Result <> 200 then
    HTTP.TimeOut := FMinTimeOut;

  // Free request string lists
  for i := 0 to High(FV2Requests) do
    if FV2Requests[i].RequestVars <> Nil then
      FV2Requests[i].RequestVars.Free;

  // Run finish procedure if assigned
  if Assigned(FOnFinished) then
    FOnFinished(self);

  // Hide and reset
  Visible := False;
  MouseFencer.Stop;
end;

Bjoerk 5. Dez 2011 17:30

AW: Nicht nachzuvollziehende EAccessViolation
 
Bei jedem Zugriff auf GetItem wird eine StringList erzeugt. Das ist gelinde gesagt sehr unschön. Besser die entsprechende (schon erzeugte) Stringlist als Parameter mitschicken.

genesisv 5. Dez 2011 17:37

AW: Nicht nachzuvollziehende EAccessViolation
 
Moment... Die Stringlist wird nur erzeugt wenn die Liste erhöht wird, also nur 1x pro Item. Falls das Item vorhanden ist springt die Funktion ja mit exit raus.

DeddyH 5. Dez 2011 17:45

AW: Nicht nachzuvollziehende EAccessViolation
 
An Deiner Stelle würde ich zunächst einmal schauen, ob man den Code nicht übersichtlicher gestalten kann (z.B. mit ein paar Unterfunktionen). Und dann wie gesagt aus dem Record eine Klasse machen und über TObjectList verwalten, dann ist auch die Klasse für die enthaltene Stringliste verantwortlich, von außen würde ich den direkten Zugriff verweigern, indem man die Stringliste verbirgt und lediglich Schnittstellen in Form von Methoden und/oder Properties bereitstellt.

Bjoerk 5. Dez 2011 17:46

AW: Nicht nachzuvollziehende EAccessViolation
 
Zitat:

Zitat von genesisv (Beitrag 1139530)
Moment... Die Stringlist wird nur erzeugt wenn die Liste erhöht wird, also nur 1x pro Item. Falls das Item vorhanden ist springt die Funktion ja mit exit raus.

Hatte ich gesehen. Trotzdem. Dann kann Create und Fee auf derselben Ebene stattfinden.(Siehe Assigns bei Delphi, sind immer Proceduren).

// Edit: Und CLearItems (sinngemäß):
Delphi-Quellcode:
procedure TFormHTTPV2.DelItem(I: integer);
begin
  FV2Requests[I].RequestVars.Free;
  SetLength(FV2Requests, Length(FV2Requests) - 1);
end;

procedure TFormHTTPV2.ClearItems;
begin
  while Length(FV2Requests) > 0 do DelItem(Length(FV2Requests)-1);
end;
// Edit2: Oder über TList:
Delphi-Quellcode:
unit uTListBeispielUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TV2Request = record
    RequestType: TV2RequestType;
    Res: integer;
    URL: string;
    LocalFile: string;
    HTTPContent: string;
    RequestVars: TStringList;
  end;
  TV2RequestList = class (TList)
    function GetItem (const Index: integer): TV2Request;
    procedure AddItem (const U: TV2Request);
    procedure InsItem (const Index: integer; const U: TV2Request);
    procedure DelItem (const Index: integer);
    procedure SetItem (const Index: integer; const U: TV2Request);
    procedure ClearList;
  public
    destructor Destroy; override;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  end;

var
  Form1: TForm1;
  List: TV2RequestList;

implementation

{$R *.dfm}

destructor TV2RequestList.Destroy;
begin
  ClearList;
  inherited;
end;

procedure TV2RequestList.ClearList;
begin
  while Count > 0 do delItem(Count-1);
end;

function TV2RequestList.GetItem (const Index: integer): TV2Request;
var
  V: ^TV2Request;
begin
  V:= Items[Index];
  Result:= V^;
end;

procedure TV2RequestList.SetItem (const Index: integer; const U: TV2Request);
var
  V: ^TV2Request;
begin
  V:= Items[Index];
  V^:= U;
end;

procedure TV2RequestList.AddItem (const U: TV2Request);
var
  V: ^TV2Request;
begin
  New (V);
  V^:= U;
  V.RequestVars:= TStringList.Create;
  Add(V);
end;

procedure TV2RequestList.InsItem (const Index: integer; const U: TV2Request);
var
  V: ^TV2Request;
begin
  New (V);
  V^:= U;
  V.RequestVars:= TStringList.Create;
  Insert(Index, V);
end;

procedure TV2RequestList.DelItem (const Index: integer);
var
  V: ^TV2Request;
begin
  V:= Items[Index];
  V.RequestVars.Free;
  Dispose(V);
  Delete(Index);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  List:= TV2RequestList.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  List.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  I: integer;
  Request: TV2Request;
begin
  for I:= 1 to 10 do
    List.AddItem(Request);
end;

end.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:20 Uhr.
Seite 1 von 2  1 2      

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