Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

EAccessViolation in getmem.inc

101 views
Skip to first unread message

Matthias Frey

unread,
Apr 10, 2013, 3:01:12 PM4/10/13
to
Hallo,

seit einiger Zeit plagt mich ... eine Exception der Klasse
EAccessViolation mit der Meldung 'Zugriffsverletzung bei Adresse
00403083 in Modul 'MfboTest.exe'. Schreiben von Adresse
FFFFFFFF' ...

Sie tritt auf in der Datei getmem.inc und zwar in der
procedure RemoveMediumFreeBlock(APMediumFreeBlock: PMediumFreeBlock);
an der Stelle
mov TMediumFreeBlock[ecx].PreviousFreeBlock, edx

Er ist im Moment eindeutig reproduzierbar. Im Call-Stack sind
immer die selben etlichen Destroy und Free.
Freigegeben werden soll eine Komponente die ich schon lᅵnger
verwende. Sie wird viermal instanziert und bei einer "knallt" es
dann. Sie dᅵrfte aber nicht verantwortlich sein, denn:

Vor einigen Programmᅵnderungen trat der selbe Fehler auf
allerdings nur sporadisch und bei einer anderen Komponente.

Wie kann ich den Fehler suchen? (madExcept ist drin)

Wenn ich im Versionscontrolsystem zurᅵck gehe, dann tritt der
Fehler wieder nur sporadisch auf und weiter zurᅵck gar nicht mehr.
Hilft das orginale FastMM vielleicht weiter?
Alle Free durch FreeAndNil ersetzen?

Fᅵr Ideen wᅵre ich dankbar.

Matthias

Arno Garrels

unread,
Apr 10, 2013, 3:10:36 PM4/10/13
to
Matthias Frey wrote:
> Wie kann ich den Fehler suchen? (madExcept ist drin)

FullDebugMode?

--
Arno

Heiko Nocon

unread,
Apr 10, 2013, 3:36:59 PM4/10/13
to
Matthias Frey wrote:

>F�r Ideen w�re ich dankbar.


Hat die Anwendung mehr als einen Thread? Wenn ja: Der Fehler steckt mit
an Sicherheit grenzender Wahrscheinlichkeit in unsauberem
Multithreading.

--
Wer Komponenten ohne Quelltext oder richtig miese Komponenten
oder gute Komponenten mit Quelltext, ohne die Source zu verstehen, sich verschafft,
um sie in Form "eigener" Programme in Verkehr zu bringen,
der wird mit Gef�ngnis nicht unter 5 Jahren bestraft.

Matthias Frey

unread,
Apr 11, 2013, 2:28:58 PM4/11/13
to
Dann also mit der offiziellen Version?
Habe ich nun geladen.

Der Fehler tritt immer noch auf, allerdings woanders.

Im Call-Stack das letzte fᅵr mich sinnvolle ist
System._IntfClear
und dort auf der Zeile
CALL DWORD PTR [EAX] + VMTOFFSET IInterface._Release

Vermutlich trifft das zu "FastMM can also be set to
detect the use of an interface of a freed object" ;-)

Allerdings wo ist das Log?
Das mᅵsste ja eine Datei sein mit Namen
"*_MemoryManager_EventLog.txt"

Liege ich richtig in der Vermutung dass es keine gibt,
weil ich mein Programm nicht normal beeenden kann?

Sonst noch Ideen? Andernfalls suche ich nach weiteren
ungᅵltigen Referenzen.


Matthias

Matthias Frey

unread,
Apr 13, 2013, 11:16:35 AM4/13/13
to
Am 11.04.2013 20:28, Matthias Frey schrieb:
> Sonst noch Ideen? Andernfalls suche ich nach weiteren
> ungᅵltigen Referenzen.

Gefunden!


Hauptproblem war eine Klasse die ein Interface implementierte.
Die Referenzzᅵhlung die Delphi dann automatisch macht wurde
ausgehebelt (wie das so hᅵufig gemacht wird). Nun wurde das
Objekt freigeben, es war aber noch eine Interface-Referenz
da, die danach auf nil gesetzt wurde. Delphi ruft dann
_Release auf, aber das Objekt war schon zerstᅵrt.

Frappierend fᅵr mich war, dass der Fehler mit FullDebugMode
schon im Code vor Monaten auftritt, ohne der Fehler erst
neuerdings Symptome verursachte. Ich denke aber es liegt
einfach daran, dass FastMM Speicher der freigegeben wird
mit Nullen ᅵberschreibt.

Was mich noch interessieren wᅵrde, wie man feststellt um
welches Interface es geht.
Der Fehler tritt immer auf in der Datei System.pas,
function _IntfClear(var Dest: IInterface): Pointer;
Zeile: CALL DWORD PTR [EAX] + VMTOFFSET IInterface._Release
auf. Im Debugger ist Dest nicht auswertbar. Der Callstack
ist auch nicht sehr erhellend.
Weiᅵ da jemand weiter?

Matthias


Arno Garrels

unread,
Apr 14, 2013, 10:16:07 AM4/14/13
to
Matthias Frey wrote:
> Gefunden!
>
> Hauptproblem war eine Klasse die ein Interface implementierte.
> Die Referenzzählung die Delphi dann automatisch macht wurde
> ausgehebelt (wie das so häufig gemacht wird). Nun wurde das
> Objekt freigeben, es war aber noch eine Interface-Referenz
> da, die danach auf nil gesetzt wurde. Delphi ruft dann
> _Release auf, aber das Objekt war schon zerstört.

Vieleicht nur die Variable nilen? Aber ist das wirklich nötig?
Pointer(Variable) := nil;

> Frappierend für mich war, dass der Fehler mit FullDebugMode
> schon im Code vor Monaten auftritt, ohne der Fehler erst
> neuerdings Symptome verursachte.

Das kann passieren mit ungültigen Referenzen.

> Ich denke aber es liegt
> einfach daran, dass FastMM Speicher der freigegeben wird
> mit Nullen überschreibt.

Tut er das wirklich?

>
> Was mich noch interessieren würde, wie man feststellt um
> welches Interface es geht.
> Der Fehler tritt immer auf in der Datei System.pas,
> function _IntfClear(var Dest: IInterface): Pointer;
> Zeile: CALL DWORD PTR [EAX] + VMTOFFSET IInterface._Release
> auf. Im Debugger ist Dest nicht auswertbar. Der Callstack
> ist auch nicht sehr erhellend.

Was steht in der MemoryManager_EventLog.txt?
Hier ein kleiner Test:

procedure TForm1.Button1Click(Sender: TObject);
var
IntfVar: IInterFace;
begin
Obj:= TNoARCInterfacedObject.Create;
IntfVar := Obj;
Obj.Free;
IntfVar := nil; // <== hier wird _IntfClear aufgerufen Zeile Nr. 40
end;

FastMM has detected an attempt to use an interface of a freed object. An access violation will now be raised in order to abort the current operation.

The current thread ID is 0x13B8, and the stack trace (return addresses) leading to this error is:
409B8F [System.pas][System][@IntfClear][28061]
4B372E [Unit1.pas][Unit1][TForm1.Button1Click][40]
47280D [Controls.pas][Controls][TControl.Click][7190]
49A66B [StdCtrls.pas][StdCtrls][TCustomButton.Click][4562]
49B159 [StdCtrls.pas][StdCtrls][TCustomButton.CNCommand][5023]
47229F [Controls.pas][Controls][TControl.WndProc][7074]
76577038 [GetWindowLongW]
711AB4C9 [Unknown function at ImageList_GetIcon]
711AB575 [Unknown function at ImageList_GetIcon]
765762FA [Unknown function at gapfnScSendMessage]
76576D91 [Unknown function at GetThreadDesktop]

--
Arno

Hans-Peter Diettrich

unread,
Apr 14, 2013, 3:28:36 PM4/14/13
to
Arno Garrels schrieb:

> procedure TForm1.Button1Click(Sender: TObject);
> var
> IntfVar: IInterFace;
> begin
> Obj:= TNoARCInterfacedObject.Create;
> IntfVar := Obj;
> Obj.Free;
> IntfVar := nil; // <== hier wird _IntfClear aufgerufen Zeile Nr. 40
> end;

Nur zur Erinnerung: das ist nicht der empfohlene Weg zur Benutzung von
Interfaces. Entweder Object *oder* Interface-Variablen benutzen, nicht
beide gleichzeitig fᅵr das selbe Objekt.

DoDi

Matthias Frey

unread,
Apr 16, 2013, 8:27:27 AM4/16/13
to
Arno Garrels schrieb:
> Matthias Frey wrote:
>> Gefunden!
>>
>> Hauptproblem war eine Klasse die ein Interface implementierte.
>> Die Referenzzᅵhlung die Delphi dann automatisch macht wurde
>> ausgehebelt (wie das so hᅵufig gemacht wird). Nun wurde das
>> Objekt freigeben, es war aber noch eine Interface-Referenz
>> da, die danach auf nil gesetzt wurde. Delphi ruft dann
>> _Release auf, aber das Objekt war schon zerstᅵrt.
>
> Vieleicht nur die Variable nilen? Aber ist das wirklich nᅵtig?

Inwiefern nᅵtig?
Spᅵtestens wenn Delphi meint dass Interface nicht mehr zu benᅵtigen
wird _Release aufgerufen.

> Pointer(Variable) := nil;

Das wᅵrde auch helfen ist aber "gar nicht schᅵn"


>> Frappierend fᅵr mich war, dass der Fehler mit FullDebugMode
>> schon im Code vor Monaten auftritt, ohne der Fehler erst
>> neuerdings Symptome verursachte.
>
> Das kann passieren mit ungᅵltigen Referenzen.
>
>> Ich denke aber es liegt
>> einfach daran, dass FastMM Speicher der freigegeben wird
>> mit Nullen ᅵberschreibt.
>
> Tut er das wirklich?

Laut Dokumentation im FullDebugMode ja.


>> Was mich noch interessieren wᅵrde, wie man feststellt um
>> welches Interface es geht.
>> Der Fehler tritt immer auf in der Datei System.pas,
>> function _IntfClear(var Dest: IInterface): Pointer;
>> Zeile: CALL DWORD PTR [EAX] + VMTOFFSET IInterface._Release
>> auf. Im Debugger ist Dest nicht auswertbar. Der Callstack
>> ist auch nicht sehr erhellend.
>
> Was steht in der MemoryManager_EventLog.txt?

Wie schon geschreiben gibt es die nicht.
Ich kann das Programm nicht mehr beenden.

Matthias

Matthias Frey

unread,
Apr 16, 2013, 9:57:54 AM4/16/13
to
Hans-Peter Diettrich schrieb:
Empohelen auf jeden Fall. Geht halt nicht immer.
Wenn man zum Beispiel ein "type TMyForm = class(TForm, IMyForm)" hat,
kannst du die VCL nicht abhalten eine Objectreferenz auf TMyForm zu
halten.

> DoDi

Matthias

MD5

unread,
Apr 16, 2013, 12:26:58 PM4/16/13
to
Am 16.04.2013 14:27, schrieb Matthias Frey:
>> Matthias Frey wrote:
>>> Gefunden!
>>>
>>> Hauptproblem war eine Klasse die ein Interface implementierte.
>>> Die Referenzzählung die Delphi dann automatisch macht wurde

Die Referenzzählung macht Delphi nur automatisch wenn die Klasse
Automatic Reference Counting, ARC implementiert, wie z.B.
TInterfacedObject.

>>> ausgehebelt (wie das so häufig gemacht wird).

Wie?

>>> Nun wurde das
>>> Objekt freigeben, es war aber noch eine Interface-Referenz
>>> da, die danach auf nil gesetzt wurde. Delphi ruft dann
>>> _Release auf, aber das Objekt war schon zerstört.

Das kann IMO nur passieren wenn ARC nicht implementiert ist.
TInterfaceObject implementiert ARC aber z.B. TComponent i.d.R.
nicht.

>>
>> Vieleicht nur die Variable nilen? Aber ist das wirklich nötig?
>
> Inwiefern nötig?
> Spätestens wenn Delphi meint dass Interface nicht mehr zu benötigen
> wird _Release aufgerufen.

Nur falls ARC implementiert ist.

--
MD5



Hans-Peter Diettrich

unread,
Apr 16, 2013, 10:16:30 PM4/16/13
to
Matthias Frey schrieb:
IMO schon:
IntfVar := TMyForm.Create(whatever);

Generell sollten solche Formulare *nicht* beim Programmstart automatisch
erzeugt werden, und das hat der Programmierer im Griff.

DoDi

Matthias Frey

unread,
Apr 17, 2013, 7:47:05 AM4/17/13
to
MD5 schrieb:
> Am 16.04.2013 14:27, schrieb Matthias Frey:
>>> Matthias Frey wrote:
>>>> Gefunden!
>>>>
>>>> Hauptproblem war eine Klasse die ein Interface implementierte.
>>>> Die Referenzzählung die Delphi dann automatisch macht wurde
>
> Die Referenzzählung macht Delphi nur automatisch wenn die Klasse
> Automatic Reference Counting, ARC implementiert, wie z.B.
> TInterfacedObject.
>
>>>> ausgehebelt (wie das so häufig gemacht wird).
>
> Wie?

Menü MMX, Apply Class Template, Apply IUnknown Implementation template ;-)

Das ergibt dann:

type
TDefault = class(TObject)
public
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef(): Integer; stdcall;
function _Release(): Integer; stdcall;
end;

implementation

function TDefault.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if GetInterface(IID, Obj) then Result := S_OK else Result :=
E_NOINTERFACE;
end;

function TDefault._AddRef(): Integer;
begin
Result := -1;
// non-refcounted memorymanagement
end;

function TDefault._Release(): Integer;
begin
Result := -1;
// non-refcounted memorymanagement
end;


Bei DevExpress habe ich sowas auch schon gesehen.


Matthias

MD5

unread,
Apr 17, 2013, 8:22:44 AM4/17/13
to
Am 17.04.2013 13:47, schrieb Matthias Frey:
[..]

> function TDefault._AddRef(): Integer;
> begin
> Result := -1;
> // non-refcounted memorymanagement
> end;
>
> function TDefault._Release(): Integer;
> begin
> Result := -1;
> // non-refcounted memorymanagement
> end;

ARC ist also *nicht* implementiert.
Also ist es ganz simpel, nachdem das implementierende
Object freigegeben wurde ist dann natürlich auch die
Referenz auf das Interface ungültig. Weise der Interface
Variablen nil zu gerade bevor das Object freigegeben wird.

--
MD5

MD5

unread,
Apr 17, 2013, 8:32:34 AM4/17/13
to
Diese Zuweisung ist natürlich nur nötig, falls die Variable
irgendwo auf nicht-nil geprüft wird.

--
MD5

Matthias Frey

unread,
Apr 17, 2013, 8:37:16 AM4/17/13
to
Hans-Peter Diettrich schrieb:
>> Empfohlen auf jeden Fall. Geht halt nicht immer.
>> Wenn man zum Beispiel ein "type TMyForm = class(TForm, IMyForm)" hat,
>> kannst du die VCL nicht abhalten eine Objectreferenz auf TMyForm zu
>> halten.
>
> IMO schon:
> IntfVar := TMyForm.Create(whatever);
>
> Generell sollten solche Formulare *nicht* beim Programmstart automatisch
> erzeugt werden, und das hat der Programmierer im Griff.


Das Beenden weniger ...

Beispiel:

type
TMainform = class(TForm)
IntfVar : IMyForm;
...
procedure TMainform.FormCreate;
begin
IntfVar := TMyForm.Create(whatever);
end;

Wenn du nun bei TMyForm auf den Schließen-Knopf klickst
dann ist IntfVar ungültig. Wenn du dann auch noch TMainform
zu machst, dann wird die Instanz von TMainform zerstört und
vorher IntfVar._Release aufgerufen.

Es muss IntfVar auf nil gesetzt werden, bevor das objekt
zerstört wird.

>
> DoDi


Matthias

Hans-Peter Diettrich

unread,
Apr 17, 2013, 12:02:03 PM4/17/13
to
Matthias Frey schrieb:
> Hans-Peter Diettrich schrieb:

> type
> TMainform = class(TForm)
> IntfVar : IMyForm;
> ....
> procedure TMainform.FormCreate;
> begin
> IntfVar := TMyForm.Create(whatever);
> end;
>
> Wenn du nun bei TMyForm auf den Schlieᅵen-Knopf klickst
> dann ist IntfVar ungᅵltig.

Nur wenn sich die Form beim Schlieᅵen selbst zerstᅵrt.

Preisfrage: zwei Fehler beim Umgang mit Komponenten und Interfaces
werden hier schon vorgefᅵhrt - wer kann den dritten noch einbauen?

DoDi

Matthias Frey

unread,
Apr 18, 2013, 8:14:20 AM4/18/13
to
Hans-Peter Diettrich schrieb:
> Matthias Frey schrieb:
>> Hans-Peter Diettrich schrieb:
>
>> type
>> TMainform = class(TForm)
>> IntfVar : IMyForm;
>> ....
>> procedure TMainform.FormCreate;
>> begin
>> IntfVar := TMyForm.Create(whatever);
>> end;
>>
>> Wenn du nun bei TMyForm auf den Schließen-Knopf klickst
>> dann ist IntfVar ungültig.
>
> Nur wenn sich die Form beim Schließen selbst zerstört.

Da hst du recht. Bei den eher seltenen MDI-Child ist das der
Normalfall. (Und diese verwende ich u.a.)


> Preisfrage: zwei Fehler beim Umgang mit Komponenten und Interfaces
> werden hier schon vorgeführt - wer kann den dritten noch einbauen?

Der wäre? ;-)

Gegenfrage: wie macht man es richtig?
So vielleicht:
- ein Formular darf sich nie selbsst zerstören, also bei OnClose
nur ein caHide statt caFree
- das Formular benachrichtigt den Erzeuger
- der Erzeuger setzt die Interface-Referenzen auf nil
- der Erzeuger zerstört das Formular
Wäre das richtig?

> DoDi

Matthias

Matthias Frey

unread,
Apr 18, 2013, 8:21:19 AM4/18/13
to
MD5 schrieb:
> Am 17.04.2013 14:22, schrieb MD5:
>> Am 17.04.2013 13:47, schrieb Matthias Frey:
>> [..]
>> ARC ist also *nicht* implementiert.
>> Also ist es ganz simpel, nachdem das implementierende
>> Object freigegeben wurde ist dann natᅵrlich auch die
>> Referenz auf das Interface ungᅵltig. Weise der Interface
>> Variablen nil zu gerade bevor das Object freigegeben wird.

Das muss man dann wohl tun. Ganz so simpel ist es aber
nicht immer, das Objekt mit der Referenz auf das Interface
muss die geplante Freigabe des Objektes auch mitbekommen.


> Diese Zuweisung ist natᅵrlich nur nᅵtig, falls die Variable
> irgendwo auf nicht-nil geprᅵft wird.

Nach meiner jetzigen Meinung: Nein, sie ist immer nᅵtig.
Spᅵtestens beim Programmende wird auch die Referenz auf das
Interface freigegeben. Dann ruft Delphi _Release des
Interfaces auf (zu einem Objekt das nicht mehr existiert).

Matthias

MD5

unread,
Apr 18, 2013, 9:27:04 AM4/18/13
to
Am 18.04.2013 14:21, schrieb Matthias Frey:
> MD5 schrieb:

>> Diese Zuweisung ist natürlich nur nötig, falls die Variable
>> irgendwo auf nicht-nil geprüft wird.
>
> Nach meiner jetzigen Meinung: Nein, sie ist immer nötig.

Du hast Recht. Hatte deshalb meine Message gecanceled, mit 39 Fieber
sollte man sich aus solchen Diskussionen heraushalten.

--
MD5

Hans-Peter Diettrich

unread,
Apr 18, 2013, 11:30:39 AM4/18/13
to
Matthias Frey schrieb:
> Hans-Peter Diettrich schrieb:
>> Matthias Frey schrieb:
>>> Hans-Peter Diettrich schrieb:
>>
>>> type
>>> TMainform = class(TForm)
>>> IntfVar : IMyForm;
>>> ....
>>> procedure TMainform.FormCreate;
>>> begin
>>> IntfVar := TMyForm.Create(whatever);
>>> end;
>>>
>>> Wenn du nun bei TMyForm auf den Schlieᅵen-Knopf klickst
>>> dann ist IntfVar ungᅵltig.
>>
>> Nur wenn sich die Form beim Schlieᅵen selbst zerstᅵrt.
>
> Da hst du recht. Bei den eher seltenen MDI-Child ist das der
> Normalfall. (Und diese verwende ich u.a.)
>
>
>> Preisfrage: zwei Fehler beim Umgang mit Komponenten und Interfaces
>> werden hier schon vorgefᅵhrt - wer kann den dritten noch einbauen?
>
> Der wᅵre? ;-)

Blᅵttre mal zurᅵck...


> Gegenfrage: wie macht man es richtig?
> So vielleicht:
> - ein Formular darf sich nie selbsst zerstᅵren, also bei OnClose
> nur ein caHide statt caFree

Kommt drauf an, wie das Formular verwendet wird.

> - das Formular benachrichtigt den Erzeuger

Erzeuger? Owner?

> - der Erzeuger setzt die Interface-Referenzen auf nil

Kommt drauf an, ob er alle kennt.

> - der Erzeuger zerstᅵrt das Formular

Kommt drauf an.

> Wᅵre das richtig?

Erst mal ein tragfᅵhiges Konzept erstellen.

Wozu dienen die Interface-Referenzen? Kᅵnnen die Daten, die mit dem
Formular zerstᅵrt werden, in andere Objekte ausgelagert werden, die dann
ᅵber Interfaces verwaltet werden?

DoDi

Matthias Frey

unread,
Apr 19, 2013, 3:45:40 AM4/19/13
to
MD5 schrieb:
Der Cancel kam bei mir wohl nicht richtig an.

Gute Besserung!

Matthias


0 new messages