Autor Beitrag
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8554
Erhaltene Danke: 481

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Fr 24.04.09 13:16 
Ich bin da gestern auf ein etwas seltsames Problem gestoßen: Ein Programm wird "einfach so" beendet. So, als würde man ein halt; im Code stehen haben. Da das aber nicht der Fall ist, habe ich etwas gesucht und bin zum Ergebnis gekommen, dass es während MyObjectList.Sort(MyCompareFunction) zu einem Stackoverflow kommt, in dessen Folge das Programm einfach "verschwindet". Ganz still und heimlich. Kein "Plöng" mit toller "ErrorError"-Messagebox, kein madExcept-Fehlerbehandlungsdialog, nichts.

Eine Endlos-Rekursion würde ich da erstmal ausschließen. Warum der Stack trotzdem zu voll wird, muss ich noch mal genauer klären. Meine Frage ist aber grundlegender Natur.

Da ich MadExcept in der Anwendung benutze, wundert es mich jetzt erstmal, warum die Anwendung sich still und heimlich verabschiedet, und kein entsprechendes Fenster mit "Bugreport senden" kommt. Ich habe diesmal das "Glück", dass der Fehler leicht reproduzierbar ist und somit per durchsteppen gefunden werden kann, aber wenn der Fehler nur sporadisch auftreten würde, und dann auch zufällig nicht bei mir hätte ich bei dem Ding ganz schlechte Karten.

Vielleicht kann mir ja mal jemand mit Grundlagenwissen da auf die Sprünge helfen. :D

(Bis das geklärt ist: In der Coverflow-Ansicht bei Nemp bei umfangreichen Sammlungen nicht die ID3-Tags derart bearbeiten, dass sich z.B. der Interpret ändert, wenn das Coverflow danach sortiert ist. ;-))

_________________
We are, we were and will not be.
Xentar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2077
Erhaltene Danke: 2

Win XP
Delphi 5 Ent., Delphi 2007 Prof
BeitragVerfasst: Fr 24.04.09 13:29 
Kann es sein, dass du diese Methode in einem eigenen Thread aufrufst?
Wenn in Threads was schief geht, können diese keine Meldung anzeigen (nur der Hauptthread), sondern fliegen u.U. komplett ab.

Wäre jetzt meine einzige Idee.

_________________
PROGRAMMER: A device for converting coffee into software.
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: Fr 24.04.09 13:42 
Stack Overflow ist sowas auch immer ganz beliebt ...

Hängt damit zusammen, dass die Sort-Methode von Delphi IIRC QuickSort benutzt und der im Worstcase Quadratischen Speicherverbrauch auf dem Stack hat. MErgeSort wäre hier besser, hätte aber u.U. genau das gleiche Problem.

Warum er einfach so wegcrasht: Weiß ich auch nicht genau, aber soweit ich das beim Schreiben des ODbgIntf mitbekommen hab, wird unter manchen Umständen vom Betriebssystem eine Reihe bestimmter Funktionen nicht mehr aufgerufen, da entweder:
- Der Error Stack Frame beschädigt ist oder nicht untergebracht werden kann (Während eines Stack Overflows wird ein Sekundär-Stack angelegt)
- Eine Nested Exception aufgetreten ist, bei der der Exception-Handler von Windows "auf Nummer sicher" geht und die Anwendung einfach killt.

Hat man nun noch Threads kommt zusätzlich hinzu, dass für jeden Thread ein eigener Stack reserviert wird. Dieser ist für Sekundärthreads AFAIR um einiges kleiner (kann man aber in der Anwendung setzen), weshalb Threads i.d.R. nicht tief verzweigen sollten.

HTH.

_________________
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.
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8554
Erhaltene Danke: 481

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Fr 24.04.09 22:24 
So. Ich glaube, ich habs. :dance2:

Threads: Wäre mir sehr peinlich, wenn das die Ursache gewesen wäre. Das war es nicht.

Ich habe es geschafft, den Fehler auch mit einer kleinen Library zu reproduzieren. Das wiederrum heißt: Mit Worst-Case-Quicksort hat der Fehler nichts zu tun. Tatsächlich kommen diverse Fehler zusammen, die dafür sorgen, dass eine Liste generiert wird, die mit der "richtigen" Compare-Funktion den Delphi-Quicksort in eine Endlos-Rekursion schickt. :autsch:

Das genauer zu erklären würde etwas länger werden - ich belasse es dabei. Ganz kurz: Die Compare-Funktion definiert ein bestimmtes Element als "am kleinsten". Unabhängig vom anderen Wert. Normalerweise sollten die Elemente in der Liste eindeutig sein, d.h. das stellt kein Problem dar. Leider habe ich "das kleinste" durch eine unübersichtliche Fehlerkette doch zweimal in der Liste drin, was dann zu ein oder zwei unnötigen Vertauschungen führt. :dunce:

_________________
We are, we were and will not be.
dummzeuch
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: Sa 25.04.09 07:58 
user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
Ich bin da gestern auf ein etwas seltsames Problem gestoßen: Ein Programm wird "einfach so" beendet. So, als würde man ein halt; im Code stehen haben. Da das aber nicht der Fall ist, habe ich etwas gesucht und bin zum Ergebnis gekommen, dass es während MyObjectList.Sort(MyCompareFunction) zu einem Stackoverflow kommt, in dessen Folge das Programm einfach "verschwindet". Ganz still und heimlich. Kein "Plöng" mit toller "ErrorError"-Messagebox, kein madExcept-Fehlerbehandlungsdialog, nichts.


Der Grund ist relativ einfach: Die Routinen zur Fehlerbehandlung benoetigen selbst Speicher (zum Ablegen von Objekten und Strings) und Stack (fuer lokale Variablen und Funktionsaufrufe bzw. deren Ruecksprungadressen). Wenn eins von beidem nicht mehr zur Verfuegung steht, kann die Fehlerbehandlung schiefgehen. Delphi versucht durch vorbeugende Speicheranforderung beim Programmstart das Problem mit fehlendem Speicher zu beheben, so dass ein EOutOfMemory meistens behandelt und angezeigt wird. Mit einem Stack Overflow kommt es aber nicht so gut klar, den bekommt man meist nur gemeldet, wenn das Programm im Debugger laeuft.

twm
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 25.04.09 10:21 
user profile icondummzeuch hat folgendes geschrieben Zum zitierten Posting springen:
Mit einem Stack Overflow kommt es aber nicht so gut klar, den bekommt man meist nur gemeldet, wenn das Programm im Debugger laeuft.

Mit einem Hook an der richtigen Stelle bekommt man ihn aber trotzdem oftmals noch zu Gesicht, selbst ohne Debugger. Dafür crasht einem aber oftmals das Programm weg, weil einem dann exakt 16 KB Stack zur Verfügung stehen, was für Delphi-Verhältnisse VIEL zu wenig ist. Besagtes ODbgIntf konnte es, hatte aber auf Grund des Hooks ein paar andere Problemchen (Vista-tauglichkeit hab ich nie getestet, geh aber mal davon aus, dass es nicht lief).

_________________
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.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: So 26.04.09 21:21 
Guter Artikel über Exception Handling aus Win32-Systemsicht: www.microsoft.com/ms...ption/Exception.aspx

Wenn Windows nicht mehr weiter weiss, macht er ExitProcess.

A Crash Course on the Depths of Win32 Structured Exception Handling hat folgendes geschrieben:
If UnhandledExceptionFilter returns EXCEPTION_EXECUTE_HANDLER, the _except block in BaseProcessStart executes. All the _except block code does is terminate the current process by calling ExitProcess. Thinking about it for a second, this makes sense; it's common knowledge that if a program causes a fault and nobody handles the fault, the system terminates the process. What you're seeing in the pseudocode is exactly where and how this happens.
There's one final addition to what I've just described. If the thread that faulted is running as a service and is for a thread-based service, the _except block code doesn't call ExitProcess—it calls ExitThread instead. You wouldn't want to terminate the entire service process just because one service went bad.

Ob wirklich das geschieht sei dahingestellt, aber es ist eine Möglichkeit.
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 26.04.09 21:32 
user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
Ob wirklich das geschieht sei dahingestellt, aber es ist eine Möglichkeit.

Jap, genau das passiert. Selber schon durch mehrfaches Debugging von Endlos-Rekursionen und anderen Exceptions nachgeprüft. Insbesondere das mit den API-Aufrufen ;-)

_________________
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.