Autor Beitrag
der organist
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 467
Erhaltene Danke: 17

WIN 7
NQC, Basic, Delphi 2010
BeitragVerfasst: Mi 16.07.08 20:39 
Tja, dumm gelaufen, wenn man nicht weiss, was mach ein Fehler nun genau bedeuten soll. Deshalb, meine lieben MitProgrammierer, frage ich euch um ein Stückchen schlauer zu werden:

was ist ein:

Project ballspiel.exe raised exeption Class EStackOverflow with message 'Stack overflow'.


Moderiert von user profile iconTino: Topic aus VCL (Visual Component Library) verschoben am Mi 16.07.2008 um 20:47
Tino
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Veteran
Beiträge: 9839
Erhaltene Danke: 45

Windows 8.1
Delphi XE4
BeitragVerfasst: Mi 16.07.08 20:42 
Ein "Stack-Overflow" kommt häufig im Zusammenspiel mit Rekursionen und fehlerhaften Abbruchbedingungen zustande.

An welcher Stell im Code tritt die Exception auf?

Gruß
Tino


Zuletzt bearbeitet von Tino am Do 17.07.08 13:25, insgesamt 1-mal bearbeitet
der organist Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 467
Erhaltene Danke: 17

WIN 7
NQC, Basic, Delphi 2010
BeitragVerfasst: Mi 16.07.08 20:47 
entweder bin ich immer noch blind oder ich weiss es einfach nicht oder es steht da nich. Wo soll ich das genau herausfinden? Wenn ich das weiss, werde ich morgen mehr liefern können.
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: Mi 16.07.08 20:52 
Du musst doch wissen, was passiert, bevor der Fehler auftritt.
Klickt der Anwender auf einen Button, brauchen wir z.B. den Code hinter diesem ButtonClick..

Und wenn nicht: Wenn der Fehler auftritt, zeigt der Compiler dir doch normalerweise die Stelle an, wo das Problem auftritt.
Tilman
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1405
Erhaltene Danke: 51

Win 7, Android
Turbo Delphi, Eclipse
BeitragVerfasst: Mi 16.07.08 21:07 
Stack Overflow ist eigentlich eine typische Erscheinung bei rekursivem Aufruf... also du rufst eine Prozedur in sich selbst auf. (Es gibt natürlich viele weitere Ursachen; dies ist aber die häufigste).

(sry tino, hatte deinen post einfach überlesen)

_________________
Bringe einen Menschen zum grübeln, dann kannst du heimlich seinen Reis essen.
(Koreanisches Sprichwort)


Zuletzt bearbeitet von Tilman am Mi 16.07.08 21:38, insgesamt 1-mal bearbeitet
Timosch
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 1314

Debian Squeeze, Win 7 Prof.
D7 Pers
BeitragVerfasst: Mi 16.07.08 21:36 
Ganz einfach ausgedrückt: Es gibt eine Art Stapel (Stack) auf dem Daten abgelegt werden können. Wenn zu viel drauf liegt, kann er überlaufen (u.U. in andere Bereiche des Programmes, z.B. den Programmcode, was dann eine Sicherheitslücke darstellt). Warum das bei dir vllt. auftaucht, wurde ja schon von anderen beschrieben.

_________________
If liberty means anything at all, it means the right to tell people what they do not want to hear. - George Orwell
der organist Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 467
Erhaltene Danke: 17

WIN 7
NQC, Basic, Delphi 2010
BeitragVerfasst: Mi 16.07.08 22:16 
ok, ich denke, ich habs. Das war wohl eine Rekursion (bei Tino hab ich das überlesen). Des weiteren kann man das hier eher weniger festestellen, das trat immer mitten in meinem Ballspiel (siehe Freeware) auf, da war eig. immer der gleiche Vorgang.

thx für die schnelle Beantwortung
Ralf107
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Di 14.10.08 11:47 
user profile iconTilman hat folgendes geschrieben Zum zitierten Posting springen:
Stack Overflow ist eigentlich eine typische Erscheinung bei rekursivem Aufruf... also du rufst eine Prozedur in sich selbst auf. (Es gibt natürlich viele weitere Ursachen; dies ist aber die häufigste).


Ich habe genau dieses Problem: Stack overflow bei rekursivem Aufruf (QuickSort).

Gibt es eine Möglichkeit, vor dem rekursiven Aufrauf die Größe des freien Stacks abzufragen?
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Di 14.10.08 12:15 
Wegen eines korrekt implementierten Quicksorts gibt es keinen Stackoverflow. Ich vermute, Du übergibst das zu sortierende Array nicht als VAR-Parameter.

Zeig mal deinen Code.

_________________
Na denn, dann. Bis dann, denn.
Ralf107
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Di 14.10.08 12:16 
user profile iconRalf107 hat folgendes geschrieben Zum zitierten Posting springen:
Gibt es eine Möglichkeit, vor dem rekursiven Aufrauf die Größe des freien Stacks abzufragen?


Ich bin bei der Lösung des Problems ein kleines Stück weiter gekommen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.Rekursion;
var 
  nESP : Cardinal;
begin
  asm
    MOV nESP,ESP
  end;
  if nESP > MinStack then Rekursion;
end;


Was mir noch fehlt, ist der richtige Wert für MinStack.

Bei meinem Testprogramm beginnt nESP bei $0012F614 und zählt in $20-Schritten herunter. Die Exception EStackOverflow tritt jedoch nicht erst bei nESP < $20 sondern schon bei nESP = $341F4 auf.
Die Stackgröße ist in den Projektoptionen auf $00004000 - $00100000 eingestellt.

Moderiert von user profile iconmatze: Code- durch Delphi-Tags ersetzt
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Di 14.10.08 12:22 
Willst Du einen Stack-Overflow vermeiden, oder nur damit rumspielen?

_________________
Na denn, dann. Bis dann, denn.
Ralf107
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Di 14.10.08 13:20 
user profile iconalzaimar hat folgendes geschrieben Zum zitierten Posting springen:
Wegen eines korrekt implementierten Quicksorts gibt es keinen Stackoverflow.

Quatsch. Quicksort arbeitet nun mal rekursiv und ist damit anfällig für einen Stack overflow. Besonders kritisch ist dabei der Fall, wenn die Eingangsdaten bereits sortiert sind.

user profile iconalzaimar hat folgendes geschrieben Zum zitierten Posting springen:
Ich vermute, Du übergibst das zu sortierende Array nicht als VAR-Parameter.

Arrays werden immer als Referenz übergeben, daher spielt es für den Stack keine Rolle, ob das Array als var oder const übergeben wird. Das Schlüsselwort const führt nur zu einer Fehlermeldung des Compilers, wenn versucht wird, das Array innerhalb der Subroutine zu verändern.
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Di 14.10.08 13:34 
user profile iconRalf107 hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconalzaimar hat folgendes geschrieben Zum zitierten Posting springen:
Wegen eines korrekt implementierten Quicksorts gibt es keinen Stackoverflow.

Quatsch. Quicksort arbeitet nun mal rekursiv

Quicksort ist auch iterativ implementierbar, das mal am Rande. Aber stimmt, wenn ich den Worst case nehme und den Algorthmus mit einem großen Array starte, könnte es sein, das es knallt. Im Übrigen muss das nicht sein, wenn ich einen Random- oder Fibbionacci-Quicksort implementiere, aber das hast Du sicherlich nicht. Beim Random-QS gibt es keinen determinierbaren Worst-Case, sodaß sich diese Variation für die Realität am Besten eignet.

user profile iconalzaimar hat folgendes geschrieben Zum zitierten Posting springen:
Ich vermute, Du übergibst das zu sortierende Array nicht als VAR-Parameter.

user profile iconRalf107 hat folgendes geschrieben Zum zitierten Posting springen:
Arrays werden immer als Referenz übergeben

Hier etwa auch?Procedure Quicksort (MyArray : TStaticIntegerArray; aLeft, aRight : Integer);
Denn darauf wollte ich hinaus: Array als 'call by value' und der Compiler sollte das Array in Gänze auf den Stack packen. Ein beliebter Tippfehler bei Anfängern ist das Fehlen des 'Var'.

Ach, noch ein beliebte Ursache für einen Stackoverflow:
ausblenden Delphi-Quelltext
1:
2:
3:
Procedure Stoopid;
Var
  BigStuff : Array [0..1234567of TSomething;

Lokale Variablen sind auf dem Stack, ergo ergibt sich bei wenigen rekursiven Aufrufen ein Stackoverflow.

Und wg.
user profile iconRalf107 hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe genau dieses Problem: Stack overflow bei rekursivem Aufruf (QuickSort).
wiederhole ich also meine Frage: Willst Du beim Quicksort den Stackoverflow vermeiden oder nur mit der Stackgröße rumspielen?

_________________
Na denn, dann. Bis dann, denn.
Ralf107
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Di 14.10.08 15:12 
user profile iconalzaimar hat folgendes geschrieben Zum zitierten Posting springen:
Aber stimmt, wenn ich den Worst case nehme und den Algorthmus mit einem großen Array starte, könnte es sein, das es knallt.

Genau das passiert gelegentlich bei Arrays > 16k.

user profile iconalzaimar hat folgendes geschrieben Zum zitierten Posting springen:
Im Übrigen muss das nicht sein, wenn ich einen Random- oder Fibbionacci-Quicksort implementiere, aber das hast Du sicherlich nicht. Beim Random-QS gibt es keinen determinierbaren Worst-Case, sodaß sich diese Variation für die Realität am Besten eignet.

Der worst Case (sortierte Eingangsdaten) ist in dem vorliegenden Fall ausgeschlossen.

user profile iconalzaimar hat folgendes geschrieben Zum zitierten Posting springen:
Ich vermute, Du übergibst das zu sortierende Array nicht als VAR-Parameter.
user profile iconRalf107 hat folgendes geschrieben Zum zitierten Posting springen:
Arrays werden immer als Referenz übergeben

Hier etwa auch?Procedure Quicksort (MyArray : TStaticIntegerArray; aLeft, aRight : Integer);
Denn darauf wollte ich hinaus: Array als 'call by value' und der Compiler sollte das Array in Gänze auf den Stack packen.

Array als 'call by value' gibt es nicht, bei keinem Compiler, egal ob Delphi, C(++/#), ...

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure a ( const x : array of integer );
begin
end;

procedure b;
var 
  y : array of integer;
  z : array [0..123of integer;
begin
  setlength(y,123456);
  a(y);
  a(z);
end;


Die lokale Variable y ist eine Referenz auf ein dynamisches Array. setlength(y,123456) weist dem dynamischen Array 123456 Speicherplätze zu. Die Referenz y liegt auf dem Stack, das Array selbst wird auf dem Heap angelegt.

Die lokale Variable z ist ein Array, das auf dem Stack liegt.

Sowohl der Aufruf a(y) als auch a(z) erfolgt 'call by reference'! In beiden Fällen werden nur die Länge des Arrays und die Adresse des ersten Elementes auf den Stack gelegt.

user profile iconalzaimar hat folgendes geschrieben Zum zitierten Posting springen:
Willst Du beim Quicksort den Stackoverflow vermeiden oder nur mit der Stackgröße rumspielen?

Ich will Quicksort abbrechen, bevor der Stack Overflow auftritt.
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Di 14.10.08 15:44 
user profile iconRalf107 hat folgendes geschrieben Zum zitierten Posting springen:
Array als 'call by value' gibt es nicht, bei keinem Compiler, egal ob Delphi, C(++/#), ...

Doch (Wirth-Pascal, UCDS-Pascal, jeder C-Compiler kennt nur 'call by value' usw.), is aber egal, weil wir über Delphi reden.

Dein Beispiel ist übrigens am Thema vorbei, da Du (1) das 'Const' in der Parameterliste hast und (2) ein dynamisches Array als Parameter deklarierst. Das ist in jedem Fall Call-By-Reference mit Read-Only-Schutz im Compiler.

Dessenungeachtet hast Du aber Recht, denn es wird in der Tat in jedem Fall ein 'Call by Reference' kompiliert, obwohl das falsch ist, also ein Bug von Delphi. Denn wenn ich ein Call by Value will, dann soll das gefälligst so kompilieren, geht bei Strings ja schließlich auch.

Habe deine Behauptung, bei einem sortieren Array würde QS die maximale Rekursionstieve erreichen, geprüft. Stimmt nicht. Dann dauert es nur maximal lang, aber zumindest beim Quicksort von TStringList das auf eine Rekursion verzichtet ist die Rekursionstiefe ca. log n, zumindest im Fall des sortierten Arrays.

Das Array muss schon sehr spezifisch sein, um die maximale Rekursionstiefe zu provozieren (z.B. '1 4 6 8 2 5 3 7' bei einem Array mit 8 Elementen)

Ich würde eine iterative Lösung implementierung. Dann ist Ruhe.

_________________
Na denn, dann. Bis dann, denn.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Di 14.10.08 17:42 
Natürlich werden Arrays "by value" übermittelt, es sei denn, man verwendet einen dynamischen Array-Typ oder arbeitet mit const bzw. var.

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:
26:
27:
28:
29:
uses SysUtils, Dialogs;

type
  TIntegerArray = array of Integer;

procedure Test1(A: array of Integer);
begin
  A[0] := 2;
end;

procedure Test2(A: TIntegerArray);
begin
  A[0] := 2;
end;

var
  X1: array of Integer;
  X2: TIntegerArray;
begin
  SetLength(X1, 1);
  X1[0] := 1;
  Test1(X1);

  SetLength(X2, 1);
  X2[0] := 1;
  Test2(X2);

  ShowMessage(Format('%d %d',[X1[0],X2[0]])); // Shows "1 2"
end.


Zu Stackoverflows: Wenn du einen Stackoverflow hast, hast du ziemlich sicher entweder eine unendliche Rekursion produziert, oder eine Rekursion alloziert zu viel Speicher auf dem Stack. In allen Fällen solltest du die Implementation ändern und nicht die Compilereinstellungen.


Zuletzt bearbeitet von delfiphan am Di 14.10.08 18:00, insgesamt 1-mal bearbeitet
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Di 14.10.08 17:49 
Probier mal das hier:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
Type
  TStaticArray = Array [0..9Of Integer;


Procedure Foo (StaticArray : TStaticArray);
Begin
  StaticArray[0] := 1;
End;


Procedure Bar;
Var
  A : TStaticArray;

Begin
  A[0] := 0;
  Foo(A);
  Showmessage(IntToStr(A[0])); // Kommt '1' heraus und das bei 'Call By Value' ?? Muh?
End;

Mir scheint, das ist ein Fehler von Delphi.
[edit] Ich verwende hier Delphi 6, bei anderen Versionen scheint das nicht (mehr) zu stimmen bzw. korrekt kompiliert zu werden[/edit]

Stack Overflow: Mein Reden.

_________________
Na denn, dann. Bis dann, denn.


Zuletzt bearbeitet von alzaimar am Di 14.10.08 18:03, insgesamt 1-mal bearbeitet
Marc.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1876
Erhaltene Danke: 129

Win 8.1, Xubuntu 15.10

BeitragVerfasst: Di 14.10.08 18:00 
user profile iconalzaimar hat folgendes geschrieben Zum zitierten Posting springen:
Probier mal das hier:
ausblenden Delphi-Quelltext
1:
  Showmessage(IntToStr(A[0])); // Kommt '1' heraus und das bei 'Call By Value' ?? Muh?					

Mir scheint, das ist ein Fehler von Delphi.

Bei mir kommt '0' heraus. :gruebel:
Pardon, es existiert tatsächlich ein Fehler...


Zuletzt bearbeitet von Marc. am Di 14.10.08 18:05, insgesamt 2-mal bearbeitet
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Di 14.10.08 18:02 
Ich verwende Delphi 6 und da kommt 1 heraus.

_________________
Na denn, dann. Bis dann, denn.
Marc.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1876
Erhaltene Danke: 129

Win 8.1, Xubuntu 15.10

BeitragVerfasst: Di 14.10.08 18:14 
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
Type
  TStaticArray = Array [0..9Of Integer;

Procedure FooSt(StaticArray : TStaticArray);
Begin
  StaticArray[0] := 1;
End;

Procedure BarSt;
Var
  A : TStaticArray;
Begin
  A[0] := 0;
  FooSt(A);
  Showmessage(IntToStr(A[0])); //  <--- 0
End;

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
Type
  TDynArray = Array Of Integer;

Procedure FooDy(DynArray : TDynArray);
Begin
  DynArray[0] := 1;
End;

Procedure BarDy;
Var
  A : TDynArray;
Begin
  SetLength(a,1);
  A[0] := 0;
  FooDy(A);
  Showmessage(IntToStr(A[0])); //  <--- 1
end;

Verwendet wurde Delphi7. Mal sehen, was das CPU-Fenster dazu sagt. ;)