Autor Beitrag
uall@ogc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Sa 31.12.05 17:00 
Hallo!
Ich erzähl erstmal eine kleine Vorgeschichte, warum ich das überhaupt teste. Es geht um das Projekt Omorphia, bei dem in der Debug Unit Fehler abgefangen werden und mitgeloggt werden sollen. Dabei ist BenBE und mit aufgefallen, dass Delphi in der Lage ist einfache Fehler (Divison durch 0) abzufangen und trotzem das Programm weiterlaufen kann, dies aber nicht bei einem Stackoverflow funktioniert.

Eigentlich ist es logisch (jedenfalls mir), dass man einen Stackoverflow nicht einfach beheben kann, da man ja nicht weiß wo der eigentliche Fehler ist und somit auch nicht weiß wo man das Programm vorlaufen lassen kann. Bei einer "Divison durch 0", kann man einfach mit der nächsten Assembler Instruktion weitermachen, ohne dass irgendetwas gefixt werden muss.

Jedenfalls macht folgendes bei der Ausführung keine Probleme:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
procedure idv;
asm
  xor eax, eax
  idiv eax
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  idv;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  idv;
end;


Weder in der IDE, noch ohne, weder im OnCreate noch bei einem Buttonklick stürzt noch das Programm ab.
Jetzt das selbe mit dem Stackoverflow. Interessant wäre es jetzt zu wissen ob Delphi diesen abfangen kann.


Bei meinen Tests habe ich dann folgendes rausgefunden.
Hier erstmal der Code:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
procedure stack;
asm
  push eax
  call stack
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  stack;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  stack;
end;


Delphi7 Enterprise ist in der Lage, den 1. stackoverflow im OnCreate abzufangen und anzuzeigen, das Programm läuft ohne crash weiter. Sollte im OnCreate Ereignis noch etwas nach dem Stack stehen, wird der code natürlich nicht ausgeführt, d.h. Delphi7 hat wohl um OnCreate ein "Try Except" das den Fehler abfängt. Erstaunlicherweise stürzt das Programm aber bei einem klick auf den Button ab. Dort fängt Delphi den Stackoverflow also nicht ab, was eigentlich nicht gerade schön ist.

Änder man den code so ab (löschen des 'push eax')

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure stack;
asm
  call stack
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  stack;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  stack;
end;


und startet dann das Programm in der IDE, so friert diese ein. Obwohl ein call nichts anderes als ein

Push retnaddress
jmp funktionaddress

ist. D.h. der Stack wird halb so schnell gefüllt bis er überläuft im Vergleich zum oberen Stackoverflow. Erst nach ca. 2 Minuten gibt Delphi die Stackoverflow Nachricht aus. Bei einem Klick auf den Button friert Delphi auch ca. 2 Minuten ein bis das Programm crashed.

Wofür das ganze?
1. Es schein ein Bug von Delphi zu sein, dass es in dem obigen Beispiel einfriert
2. Delphi ist in der lage einen Stackoverflow im OnCreate abzufangen, im Button.click aber nicht (und jeder anderen Methode)
3. In anderen Delphi Versionen ist Delphi aber in der Lage beides abzufangen ohne das Delphi crashed.

Deshalb würde ich gerne wissen bei wem das Programm crashed, Delphi einfriert, oder der Stackoverflow abgefangen wird.
Wäre nett wenn der ein oder andere, das mal testen könnte.

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Sa 31.12.05 17:02 
Ich mach dann mal den Anfang:

Delphi 7 Enterprise ohne Updates

Stackoverflow mit PUSH EAX:
OnCreate: wird abgefangen
OnButtonKlick: Programm crash


Stackoverflow ohne PUSH EAX:
OnCreate: 2 mins freeze dann abgefangen
OnButtonKlick: 2 misn freeze dann crash

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Jailbird
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 127

Windows XP Pro SP2
Delphi 7 Professional
BeitragVerfasst: Sa 31.12.05 17:32 
Ich hab zwar die gleiche Version wie du und kann das Verhalten nachvollziehen, allerdings nur für die OnCreate.

Für die OnClick des Button hab ich das gleiche Verhalten wie für OnCreate. Begründung:

Wenn ich im OnCreate schon einen Stack Overflow produziere, dann hab ich im OnClick sowieso ein unvorhersehbares Verhalten (wie ist der Zustand des Stack? Voll, leer oder etwas zwischendrin?). Wenn ich den Call im OnCreate rausnehme, dann wird der Stack Overflow abgefangen.
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Sa 31.12.05 17:38 
Nein die Begründung ist nicht richtig.

Wird in OnCreate der Stackoverflow abgefangen - so ist der Stack danach wieder richtig. D.h. ich kann im gleichen Prozess auch wieder den Stackoverflow in einer anderen Methode aufrufen.

D.h. selbst wenn ich den Stackoverflow nur im Button1.OnClick aufrufe stürzt bei mir das Programm ab (das habe ich natürlich vorher getestet)

Also kann der Code direkt hintereinadner ausgeführt werden, wenn OnCreate nicht schon crashed. (das sollte bei dir auch gehen, selbst dann sollte bei dir [im gegensatz zu mir] im OnClick der Stackovrflow abgefangen werden)

Komisch ist das jetzt schon, warums bei dir geht, bei mir aber nicht.

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
matze.de
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 576

Win95, Win98 SE, WinXp Prof SP2
D7P, D8P, FPC2.0
BeitragVerfasst: Sa 31.12.05 20:12 
Hi ich habs auch mal probiert. :)

Delphi 7 Prof. Build 4.453

Stackoverflow mit PUSH EAX:
OnCreate: wird abgefangen, aber wenn ich dann das Programm weiterlaufen lasse bekomm ich eine AV(bzw. crash)
OnButtonKlick: wird abgefangen, aber wenn ich dann das Programm weiterlaufen lasse bekomm ich eine AV(bzw. crash)


Stackoverflow ohne PUSH EAX:
OnCreate: 4 mins freeze dann abgefangen, aber wenn ich dann das Programm weiterlaufen lasse bekomm ich eine AV(bzw. crash)
OnButtonKlick: 4 mins freeze dann abgefangen, aber wenn ich dann das Programm weiterlaufen lasse bekomm ich eine AV(bzw. crash)

Wie man sieht überall so gut wie das selbe. Ist Alles in der Delphi IDE getestet.

mfg matze

_________________
si tacuisses, philosophus mansisses.
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Sa 31.12.05 21:23 
Hatte bis jetzt auch jeder die selbe Delphi Version. Wäre vorteilhaft wenn das mal jemand mit der neusten Version testen kann.

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 31.12.05 22:47 
Damit ihr einen genaueren Einblick in das Problem bekommt, gebe ich ersteinmal kurz einen Link auf unseren Bugtracker Bug #23. Er ist wie gesagt länger bereits bekannt, aber bisher nicht high-ratet, da sein Auftreten unter bestimmten Bedingungen vorhersehbar geworden ist - d.h. wenn er Auftritt, ist auch was anderes falsch *g*

Ich hab weiterhin diesen Bug auch bereits an sakura in der DP gemeldet, aber bisher noch keine Rückmeldung. Ich hoffe, diese folgt demnächst noch.

Das Auftreten dieses Bugs scheint wahrscheinlich auf einen Fehler hinzuweisen, der abhängig von den Compiler-Einstellungen zu sein scheint. Von daher bitte diese Angabe auch ergänzen:

Bei mir getestet:
D3 Standard, ungepatcht:
A=1,B=0,C=1,D=1,E=0,F=0,G=1,H=1,I=1,J=1,K=0,L=1,M=0,N=1,O=1,P=1,Q=0,R=0,S=0,T=0,U=0,V=1,W=0,X=1,Y=0,Z=1
PUSH: OnCreate in IDE nach 2m gemeldet, danach aufgehangen???, Button=nicht möglich zu testen
Ohne: OnCreate IDE hängt komplett; keine Rückmeldung, Button=nicht möglich zu testen

D4 Standard, SP2\BDE Update:
$A+,$B-,$C+,$D+,$E-,$F-,$G+,$H+,$I+,$J+,$K-,$L+,$M-,$N+,$O+,$P+,$Q-,$R-,$S-,$T-,$U-,$V+,$W-,$X+,$YD,$Z1
PUSH: OnCreate fängt ab, Button=Hlt
Ohne: OnCreate fängt ab, Button=Hlt

D5 Enterprise, SP1\ADO Fix:
A=1,B=0,C=1,D=1,E=0,F=0,G=1,H=1,I=1,J=1,K=0,L=1,M=0,N=1,O=1,P=1,Q=0,R=0,S=0,T=0,U=0,V=1,W=0,X=1,Y=1,Z=1
PUSH: OnCreate fängt ab, Button=Hlt - in IDE wegen AVs nicht weiter debugbar nach OnCreate
Ohne: OnCreate fängt ab, Button=Hlt - IDE-freeze

D6E und D7E ergänz ich demnächst ... (bzw. in unserem Bugtracker nachlesbar ... Genaue Konfig folgt.

D9 und D10 teste ich auch demnächst.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: So 01.01.06 16:02 
Delphi6 Prof - durch den Stackoverflow wird sowohl im OnCreate, als auch im OnClick das Programm beendet. Ursache:

Sowohl das OnCreate als auch das OnClick wird intern in einem try-except-Block ausgelöst:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
procedure TCustomForm.DoCreate;
begin
  if Assigned(FOnCreate) then
  try
    FOnCreate(Self);
  except
    if not HandleCreateException then
      raise;
  end;
  if fsVisible in FFormState then Visible := True;
end;

procedure TWinControl.MainWndProc(var Message: TMessage);
begin
  try
    try
      WindowProc(Message); // über die WindowProc wird dann auch OnClick ausgelöst
    finally
      FreeDeviceContexts;
      FreeMemoryContexts;
    end;
  except
    Application.HandleException(Self);
  end;
end;


HandleCreateException macht auch wieder nichts anderes als Application.HandleException aufzurufen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
function TCustomForm.HandleCreateException: Boolean;
begin
  Application.HandleException(Self);
  Result := True;
end;


In beiden Fällen landet man also hier:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TApplication.HandleException(Sender: TObject);
begin
  if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
  if ExceptObject is Exception then
  begin
    if not (ExceptObject is EAbort) then
      if Assigned(FOnException) then
        FOnException(Sender, Exception(ExceptObject))
      else
        ShowException(Exception(ExceptObject));
  end else
    SysUtils.ShowException(ExceptObject, ExceptAddr);
end;

Da das OnException-Ereignis nicht gesetzt ist zeigt Delphi die übliche MessageBox mit der Fehlermeldung an (ShowException). Dazu wird die API-Funktion "MessageBox" verwendet, allerdings tritt innerhalb dieser Funktion eine AccessViolation auf weshalb der Prozess beendet wird - ich hab den Fehler nur soweit verfolgt, dass an einer Code-Stelle die sehr oft durchlaufen wird ($7C8024E3) EAX auf einmal einen etwas seltsamen wert hat (>$400), weshalb die ASM-Anweisung sub esp, eax den Stackpointer ins Nirvana zeigen lässt. Das darauffolgende Push löst die besagt AccessViolation aus.

Der Fehler auf der Delphi-Seite ist eigentlich der, dass der Exception-Handler für JEDE Exception ausgelöst wird, nach einem Stackoverflow ist es aber nicht wirklich möglich das Programm wieder in eine stabile Ausgangsposition zurückzusetzen (gracefully recovering). Ich gehe daher aus, dass es sich einfach um einen "Folgefehler" handelt...

Gruß, Motzi

Edit: es ist dabei egal ob die Prozedur den zusätzlichen "push" enthält oder nicht, das Ergebnis ist dasselbe. Warum die IDE ohne das Push allerdings eine beträchtliche Zeit lang hängt kann ich auch nicht erklären.

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
MagicAndre1981
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: So 01.01.06 16:40 
user profile iconSakura hat in der DP was dazu gepostet.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 01.01.06 16:55 
Hi,

ich hab kurz mich mal mit sakura über das Stack-Problem unterhalten. Dabei kamen folgende Dinge raus:

Chatlog mit Sakura:

[15:04:56] BenBE: Der Stack-Overflow-Bug scheint nämlich soweit die bisherigen Forschungen gehen, in nahezu jeder Delphi-Version aufzutreten und nur von den Compiler-Einstellungen abhängig zu sein.
[15:06:59] Sakura: Der Stack-Overflow ist aber eindeutig ein Entwicklerproblem. Ansonsten: Stack-Overflows werden von Windows iA unterschiedlich (Freund Zufall und Freundin Systemstress entscheiden hier mit Kind Willkür) behandelt.
[15:07:32] Sakura: --> Kein Bug von Delphi ;)


Weiterhin bzgl. Reproduzierbarkeit und Nachforschungen:
Chatlog mit Sakura hat folgendes geschrieben:

[15:09:10] BenBE: Trotzdem ist es nicht sonderlich erfreulich, wenn Stack-Overflows je nach Compiler-Einstellungen unterschiedlich behandelt werden und bei einigen Vorkommen sogar die IDE minutenlang hängt.
[15:10:36] Sakura: Lässt sich aber nicht ändern. Die Compilereinstellungen entscheiden über Speichersicherheit, Speichermanagement, Fehlertoleranz. Setzt Du die Schalter so, dass Fehler weitestgehend ignoriert werden, läufst Du halt auch Gefahr, dass es Dir nicht nur das Programm, sondern auch den Debugger zerschiest. Das ist das Leben unter Windows.
[15:14:02] BenBE: Gut, auf's OS kann man vieles schieben ^^ Aber ein Stackoverflow, der ähnlich nem Halt-Befehl wirkt, ist nicht grad vorteilhaft ... Da dieser Bug nämlich durch die Komponenten-Packages auch leicht in der IDE auftritt und dort zu Datenverlust führen kann. Wäre halt bei diesem Problem sicherlich sinnvoll, einmal bei Borland nachzuforschen, ob sie sich der Sache annehmen könnten.
[15:14:48] BenBE: Ich hab nämlich keine Lust für jegliche Delphi-Versionen in meinem Debug Interface nen Work-Around zu schreiben *g* (auch wenn ich inzwischen genug Ideen für ein solchen hab *g*)
[15:16:35] Sakura: Okay, in D9 kann ich den reproduzieren, lade jetzt D10
[15:19:45] Sakura: Keine Probleme mehr in D10 :) Ich werde nächste Woche (sprich 8.1.) mal in Scotts Valley nachfragen, ob sich ein Reporting für D9 noch lohnt - ich glaube nicht ;)


Unter D10 mit folgenden Einstellungen getestet:
ausblenden volle Höhe Sakura's Compiler-Settings für D10
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
{$A8,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N+,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y+,Z1} 
{$MINSTACKSIZE $00004000} 
{$MAXSTACKSIZE $00100000} 
{$IMAGEBASE $00400000} 
{$APPTYPE GUI} 
{$WARN SYMBOL_DEPRECATED ON} 
{$WARN SYMBOL_LIBRARY ON} 
{$WARN SYMBOL_PLATFORM ON} 
{$WARN SYMBOL_EXPERIMENTAL ON}
{$WARN UNIT_LIBRARY ON} 
{$WARN UNIT_PLATFORM ON} 
{$WARN UNIT_DEPRECATED ON} 
{$WARN UNIT_EXPERIMENTAL ON} 
{$WARN HRESULT_COMPAT ON} 
{$WARN HIDING_MEMBER ON} 
{$WARN HIDDEN_VIRTUAL ON} 
{$WARN GARBAGE ON} 
{$WARN BOUNDS_ERROR ON} 
{$WARN ZERO_NIL_COMPAT ON} 
{$WARN STRING_CONST_TRUNCED ON} 
{$WARN FOR_LOOP_VAR_VARPAR ON} 
{$WARN TYPED_CONST_VARPAR ON} 
{$WARN ASG_TO_TYPED_CONST ON} 
{$WARN CASE_LABEL_RANGE ON} 
{$WARN FOR_VARIABLE ON}  
{$WARN CONSTRUCTING_ABSTRACT ON} 
{$WARN COMPARISON_FALSE ON} 
{$WARN COMPARISON_TRUE ON} 
{$WARN COMPARING_SIGNED_UNSIGNED ON} 
{$WARN COMBINING_SIGNED_UNSIGNED ON} 
{$WARN UNSUPPORTED_CONSTRUCT ON} 
{$WARN FILE_OPEN ON} 
{$WARN FILE_OPEN_UNITSRC ON} 
{$WARN BAD_GLOBAL_SYMBOL ON} 
{$WARN DUPLICATE_CTOR_DTOR ON}  
{$WARN INVALID_DIRECTIVE ON} 
{$WARN PACKAGE_NO_LINK ON} 
{$WARN PACKAGED_THREADVAR ON} 
{$WARN IMPLICIT_IMPORT ON} 
{$WARN HPPEMIT_IGNORED ON} 
{$WARN NO_RETVAL ON} 
{$WARN USE_BEFORE_DEF ON} 
{$WARN FOR_LOOP_VAR_UNDEF ON} 
{$WARN UNIT_NAME_MISMATCH ON} 
{$WARN NO_CFG_FILE_FOUND ON}  
{$WARN MESSAGE_DIRECTIVE ON} 
{$WARN IMPLICIT_VARIANTS ON} 
{$WARN UNICODE_TO_LOCALE ON} 
{$WARN LOCALE_TO_UNICODE ON} 
{$WARN IMAGEBASE_MULTIPLE ON} 
{$WARN SUSPICIOUS_TYPECAST ON} 
{$WARN PRIVATE_PROPACCESSOR ON} 
{$WARN UNSAFE_TYPE OFF} 
{$WARN UNSAFE_CODE OFF} 
{$WARN UNSAFE_CAST OFF} 
{$WARN OPTION_TRUNCATED ON} 
{$WARN WIDECHAR_REDUCED ON} 
{$WARN DUPLICATES_IGNORED ON}


Heißt also Bug scheint in D10 behoben zu sein, oder per Defaults nicht aufzutreten.
In D9 kann er den Fehler reproduzieren.

www.delphipraxis.net...i+stackoverflow.html

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: So 01.01.06 18:32 
Hi, ich habe mir den Fehler auch nochmals angeschaut und aml wieder erstaunliches rausgefunden. Es liegt wirklich an dem OS und teilweise an Delphi. (Ich glaub ich könnte einen ganzen Roman darüber schreiben ;) )

Hier mal ein neues Beispiel wo es "normalerweise" nicht crashen darf, da ein simpler Stackoverflow eigentlich keine wichtigen Daten überschreibt undsomit das Programm nur an der richtigen Stelle fortgesetzt werden sollte.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure stack;
asm
  push eax
  call stack
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    stack
  except
    MessageBox(0,'test',nil,0);
  end;
end;


Das 'sollte' eigentlich nicht crashen, tut es aber! Wenn man die MessageBox rausnimmt dann crashed das Programm auch nicht. Jedenfalls wenn der Stackoverflow zum ersten mal auftritt. (Bei mehrmaligem Stackoverflow crashed es Windowsbedingt) Also warum crashed es mit der MSB und ohne nicht? Nach ein bischen nachforschungen und ettlichem Debuggen konnte ich den Bug finden.

Wird Der Stack zu voll (d.h. sinkt das ESP Register unter dem Stacklimit von Delphi üblichen 0x0012C000) dann allokiert Windows neuen Speicher solange bis die Maximale Stackgrößere erreicht ist. (Max übl. $00100000) Sollte dann auch der Maximale Stacjspeicher voll sein so wird eine Exception geworfen und der Stack nochmals vergrößert. Er fängt dann bei 0x00031000 an. Der neue allokierte Speicher kann jetzt genutzt werden um die Fehlerbehandlung zu übernehmen. Denn auch das fixen des Stacks etc. braucht ja wieder den Stack um APIs etc. aufzurufen.

Der Stack ist also jetzt knapp bei 0x00032C00. Delphi kann jetzt in die HandleAnyException Funktion reingehen um den Stack und die Register wieder zu fixen und anschließend den Except Bereich aufzurufen. (unsere MessageBoxA Funktion)

Und hier ist meienr Meinung nach der Fehler. Das ESP Register wird NICHT wieder richtig hergestellt (siehe BildAnhang 1)
Es ist bei der Ausführung vom Except Bereich immer noch dort wo es eigentlich NUR für die Herstellung des alten Zustandes sein sollte. Das ESP Register (und möglicherweise die anderen) werden erst in 'DoneExcept' wieder geändert.

Deshalb kommt es beim Aufruf von MessageBoxA zu dem crash, wenn diese Funktion mehr als die Differnz vom Stack brauch die sie hat (0x1C00). Folgender Delphi Code funktioniert in der Weise wie ich es für richtig halte und auch in Button.OnClick wird die Exception richtig abgefangen und das Progamm läuft weiter.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
var overflow: boolean;
procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    overflow := false;
    stack;
  except
    overflow := true;
  end;
  if overflow then
    MessageBox(0,'Stackoverflow',nil,0);
end;


Jetzt wird DoneExcept vor MessageBoxA aufgerufen, der Stack stimmt also wieder und MessageBoxA kann nicht durch keinen (Folge)Fehler das Programm crashen.

Leider funktioniert der Aufruf nur einmal, da bei einem weiteren Aufruf der Stack wiederum vergrößert werden müsste (der overflow tritt wieder später auf, d.h. der Stackbereich der vorher zum Exception handling allokiert wurde kann wieder benutzt werden, Windows müsste wieder Speicher davor allokieren, was aber nicht geht.)

Ich weiß nicht ob es durch Funktionen wie GetTls etc. möglich wäre das Problem zu beheben, was dann doch wieder in ein DelphiProblem (nicht Windows Problem) übergehen könnte. Wenn Sakura noch das in Delphi 10 (mit mehrmaligen Aufruf) testen könnte wäre ich ihm dankbar.
Einloggen, um Attachments anzusehen!
_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Mo 02.01.06 00:29 
Du hast recht.. ich hab das ganze mal unter VS 2005 Prof ausprobiert, und zwar unter direkter Verwendung der Win32-SEH-Mittel:

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
void stack()
{
  __asm {
    push 0x00
    call stack
  }
}

int _tmain(int argc, _TCHAR* argv[])
{
  __try {
    stack();
  } __except (EXCEPTION_EXECUTE_HANDLER) {
    MessageBoxA(0, "Test", "Fehler", 0);
  }

  return 0;
}


Dabei wird folgender ASM-Code erzeugt:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
00411435 89 65 E8         mov         dword ptr [ebp-18h],esp  // aktuellen Stack-Pointer speichern
    18:   __try {
00411438 C7 45 FC 00 00 00 00 mov         dword ptr [ebp-4],0 
    19:     stack();
0041143F E8 11 FC FF FF   call        stack (411055h) 
    20:   } __except (EXCEPTION_EXECUTE_HANDLER) {
00411444 C7 45 FC FE FF FF FF mov         dword ptr [ebp-4],0FFFFFFFEh 
0041144B EB 2D            jmp         $LN6+27h (41147Ah) 
$LN5:
0041144D B8 01 00 00 00   mov         eax,1 
$LN7:
00411452 C3               ret              
$LN6:
00411453 8B 65 E8         mov         esp,dword ptr [ebp-18h]  // Stack-Pointer wiederherstellen
    21:     MessageBoxA(0, "Test", "Fehler", 0);
00411456 8B F4            mov         esi,esp 
00411458 6A 00            push        0    
0041145A 68 44 56 41 00   push        offset string "Fehler" (415644h) 
0041145F 68 3C 56 41 00   push        offset string "Test" (41563Ch) 
00411464 6A 00            push        0    
00411466 FF 15 38 83 41 00 call        dword ptr [__imp__MessageBoxA@16 (418338h)] 
0041146C 3B F4            cmp         esi,esp 
0041146E E8 CD FC FF FF   call        @ILT+315(__RTC_CheckEsp) (411140h) 
    22:   }
00411473 C7 45 FC FE FF FF FF mov         dword ptr [ebp-4],0FFFFFFFEh 
    23: 
    24:   return 0;

Es wird also VOR der Ausführung des Exception-Handlings der Stack entsprechend aufgeräumt (bzw der Stack-Pointer wiederhergestellt). Daher kann die MessageBox hier korrekt angezeigt und das Programm nachher fortgesetzt werden. Insofern liegt das Problem also doch an Delphi.
BTW: die VS 2005 IDE hat auch kein Problem wenn ich das zusätzliche push entfernte, es dauert zwar eine Spur länger als mit (eh klar), steht aber in keinem Verhältnis zur Delphi-IDE.

Gruß, Motzi

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!