Board index » delphi » Stack overflow

Stack overflow

Hello, what causes stack overflow? I mean, I know it's a hunk of memory
used for variables and that stuff, but when I repeated a procedure 50
times (not recursively) in rapid succession, I got this error. The error
really isn't harming my program, it's just that I thought my program was
free of this kind of stuff. When I repeated the procedure 52 times, I
got stack overflow, I increased the memory by 2000 bytes and was able to
call the procedure 64 times before it crashed. Is there a way to cure
this without adding more and more memory? Thanks in advance.

 

Re:Stack overflow


Quote
In article <31D0185C.7...@netvoyage.net> Ronn <ronca...@netvoyage.net> writes:
>Hello, what causes stack overflow? I mean, I know it's a hunk of memory
>used for variables and that stuff, but when I repeated a procedure 50
>times (not recursively) in rapid succession, I got this error. The error
>really isn't harming my program, it's just that I thought my program was
>free of this kind of stuff. When I repeated the procedure 52 times, I
>got stack overflow, I increased the memory by 2000 bytes and was able to
>call the procedure 64 times before it crashed. Is there a way to cure
>this without adding more and more memory? Thanks in advance.

If you are getting stack-overflow based on the number of times you "repeat" a
procedure, then it is axiomatic that you must be calling it recursively even
though you may think this is not so.  When a procedure is entered and exited
in a true loop, it constantly re-uses the same stack space.  (I'm sure that in
response to this you'll post the actual source-code and I'll be surprised and
forced to eat those words, but it will be educational.)

Re:Stack overflow


Quote
In article <31D0185C.7...@netvoyage.net> Ronn wrote:
>Hello, what causes stack overflow? I mean, I know it's a hunk of memory
>used for variables and that stuff, but when I repeated a procedure 50
>times (not recursively) in rapid succession, I got this error. The error
>really isn't harming my program, it's just that I thought my program was
>free of this kind of stuff. When I repeated the procedure 52 times, I
>got stack overflow, I increased the memory by 2000 bytes and was able to
>call the procedure 64 times before it crashed. Is there a way to cure
>this without adding more and more memory? Thanks in advan

Ronn, there is definitely something wrong.  After a function returns
the stack should be at the same place it was before it was called.  The
only way that this could happen calling a routine repetitively is that
the routine is not terminating properly. If you are using assembler
routines make certain you are properly releasing parameters.  If everything
is in Pascal, ...  Well, the only thing I can think of here is that you are
making an improper transfer like through a poorly implemented long-jump.

You might need to post a piece of the code.

--
RDon...@gnn.com
http://members.gnn.com/rdonais/index.html
-------------------------------------------
Knowledge is one of the few things that you
can give away and still keep for yourself.

Re:Stack overflow


In article <4qpv6g$...@news-e2b.gnn.com>, R. E. Donais <RDon...@gnn.com> writes:

Quote

> Ronn, there is definitely something wrong.  After a function returns
> the stack should be at the same place it was before it was called.  The
> only way that this could happen calling a routine repetitively is that
> the routine is not terminating properly. If you are using assembler
> routines make certain you are properly releasing parameters.  If everything
> is in Pascal, ...  Well, the only thing I can think of here is that you are
> making an improper transfer like through a poorly implemented long-jump.

I doubt that this is the problem.
I rubbish were left on the stack, the program would probably crash for other
reasons...

I think he's calling it recirsively, but he's not aware of it.
Some code would really help here...

BTW, here's an interesting bug in TP7. It has nothing to do with the above, but
is rather interesting.

It turns out that stack checking doesn't work correctly.
Try this piece of code with stack checking turned on {$S+}

type bigarr = array [0..65534] of byte;

procedure (a:bigarr);
begin
  a[0]:=1;
end;

The program will crash without a stack overflow message.
By debbuging it eith TD, I discovered that TP checks for sufficient stack space
only for parameters and local variables. What happens here is that it makes a
copy of the array on the stack and passes a pointer to it.
The problem is that it doesn't check if there's sufficient space for the copy
on the stack....

So, be careful not to forget the VAR when passing big structures as parameters.
This bug can be more difficult to detect if the structures is smaller, and it
could overwrite a piece of code in another unit, so that everything crashes at
a later time....
I had this problem, and it took more than two hours to track down the bug..

--
Vladan Bato
i3100...@univ.trieste.it
http://www.geocities.com/SiliconValley/8682/

Re:Stack overflow


Be aware of the fact that when you try an array of this size it cannot be
larger than the maximum segment size (2^16) minus a few bytes. If i
remebered correctly it was 32 bytes.

Anco ;-)

Re:Stack overflow


Re:Stack overflow


Quote
In article <31D2905A.4...@bsi.de> Tels <elst...@bsi.de> writes:
>The "WITH" statement can't be used recursively.
>Example, that will fail:
>TYPE
>  TMyType1 = RECORD
>    test : BYTE;
>  END;
>  TMyType2 = RECORD
>    test : BYTE;
>  END;
>PROCEUDRE TESTIT;
>VAR
>  t1,t2 : TMyType;
>BEGIN
>  WITH t1 DO BEGIN
>    test:=1;
>    WITH t2 DO BEGIN
>      test:=2;
>    END;
>    test:=3;    
>{here it goes wrong, instead of writing to t1.test it overwrites
>t2.test}
>  END;

You don't mean "recursively," you mean "nested."

The record-element "test" is deliberately ambiguous:  it could refer to
T1.Test or T2.Test.  Delphi has chosen to associate it with the innermost WITH
statement and this is what I would expect it to do.  I think that Delphi is
working as expected.

/mr/

Re:Stack overflow


Re:Stack overflow


Quote
In article <31D2905A.4...@bsi.de> Tels wrote:
>TYPE
>  TMyType1 = RECORD
>    test : BYTE;
>  END;
>  TMyType2 = RECORD
>    test : BYTE;
>  END;

>PROCEUDRE TESTIT;
>VAR
>  t1,t2 : TMyType;
>BEGIN
>  WITH t1 DO BEGIN
>    test:=1;
>    WITH t2 DO BEGIN
>      test:=2;
>    END;
>    test:=3;        {here it goes wrong, instead of writing to t1.test it overwrites
>t2.test}
>  END;

What you describe is nesting _not_ recursion.  Since I frequently nest
with statements I was surprised at your claim that it fails.  I copied
your sample which would not compile due to misspelling procedure",
undefined type "tMyType", and missing END.  Since it wouldn't compile
I must assume that this is not the code exhibiting your alleged error.  
I corrected the errors and added the following to the end of your sample

    Writeln(t1.test,'  ',t2.Test)
END; {testit}

BEGIN
    Testit;
END.

The results were "3  2" as expected.  So, you nearly corrected your
error when you copied the code.  I suggest you take a closer look at the
original which is doing exactly as you told it, which appears not to be
what you wanted.

--
RDon...@gnn.com
http://members.gnn.com/rdonais/index.html
-------------------------------------------
Knowledge is one of the few things that you
can give away and still keep for yourself.

Re:Stack overflow


Quote
R. E. Donais wrote:

> In article <1996Jun26.091...@univ.trieste.it> Vladan Bato wrote:

> >In article <4qpv6g$...@news-e2b.gnn.com>, R. E. Donais <RDon...@gnn.com>writes:

> >> Ronn, there is definitely something wrong.  After a function returns
> >> the stack should be at the same place it was before it was called.  The
> >> only way that this could happen calling a routine repetitively is that
> >> the routine is not terminating properly. If you are using assembler
> >> routines make certain you are properly releasing parameters.  Ifeverything
> >> is in Pascal, ...  Well, the only thing I can think of here is that youare
> >> making an improper transfer like through a poorly implemented long-jump.

> >I doubt that this is the problem.
> >I rubbish were left on the stack, the program would probably crash forother
> >reasons...

> >I think he's calling it recirsively, but he's not aware of it.
> >Some code would really help here...

> Ronn says failure occurs when he repeats the procedure 50 times in rapid
> succession.  I assume this means in some form of loop from within another
> routine.  The fact that it works 49 times leads me to believe that there
> may be something other than recursion involved.  Granted, it may be a
> recursive call, if so it would have to be indirect recursion or otherwise
> hidden since he states that recursion is not involved.  This can be
> verified w/o having to study the code simply by placing a break-point at
> the beginnig of the routine and an other at the end.  If the first doesn't
> trigger more than once w/o the second, then recursion is not a problem.

> If parameters are changed with each call, the problem could be anything.
> But if they remain constant, then the routine would have to behave the
> same each time.  A stack overflow is often reported at odd locations
> within a program if a routine returns "into" junk on the stack.  This could
> be caused by issuing a RET instruction without properly restoring the stack
> frame or by moving too much data into local variables which would overwrite
> the return address. All these problems are caused by using non-standard
> methods and/or defeating Pascal's type checking.  However, these would
> probably fail each time and since it works 49 times, something else must
> be happening.

> If parameters are not properly being removed then the stack will not be
> corrected until the calling routine returns (its proloque would correct the
> bad stack if it had local variables, else it wold cause a crase). If it
> again calls the non-standard routine more junk is added to the junk already
> on the stack.  Eventually the stack will overflow.  This scenario allows
> for some success before inevitable failure.

> Since Ronn recently acquired BP 7.0 I would guess there might be a little
> experimentation involved.  Many beginning programmers dabbling with
> assembler don't realize that BASM places the necessary prologue at the
> end of a routine.  Having heard that assembly language routines must end
> with a RET instruction they add one but fail to add the necessary prologue.
> This would eventually cause the type of problem he is experiencing.

> Granted, a little code sample would make it easier to identify the problem,
> but there is a sort of challenge trying to solve a problem blind-folded and
> when you're not on the clock you can afford to speculate. :)

> --
> RDon...@gnn.com
> http://members.gnn.com/rdonais/index.html
> -------------------------------------------
> Knowledge is one of the few things that you
> can give away and still keep for yourself.

Yes, I am calling it recursively if you count me typing 'W' then enter,
'W' then enter over and over at just under the speed of light.

Re:Stack overflow


Quote
In article <31D0185C.7...@netvoyage.net>, Ronn <ronca...@netvoyage.net> wrote:
>Hello, what causes stack overflow? I mean, I know it's a hunk of memory
>used for variables and that stuff, but when I repeated a procedure 50
>times (not recursively) in rapid succession, I got this error. The error
>really isn't harming my program, it's just that I thought my program was
>free of this kind of stuff. When I repeated the procedure 52 times, I
>got stack overflow, I increased the memory by 2000 bytes and was able to
>call the procedure 64 times before it crashed. Is there a way to cure
>this without adding more and more memory? Thanks in advance.

I would have to see the code for that procedure. It could be that something in
the procedure is stepping on a memory location or something else. The stack
holds the local variables for the procedure. When the procedure exits, the
stack is reset to the value it entered with.

You should step through it with the de{*word*81}, making sure that your stack
register is coming back from the procedure with the same value it went in
with.

-----------------------------------------------
Mike Chapin
Powder River
mcha...@vcn.com
http://www.vcn.com/server/netizens/mchapin/first.html
Gillette, WY

Not the end of the earth but you can see it from
there.
-----------------------------------------------

Re:Stack overflow


On a slightly different subject, does anyone know how to monitor the size of  
the stack (i.e., how much is still available)?  I don't know of any way to  
set the stack size for a given program except trial and error.

Thanks,

Chris Mathews

Re:Stack overflow


Quote
In article <6Bo8fezE...@site33.ping.at> rse...@site33.ping.at (Chris Mathews) writes:
>On a slightly different subject, does anyone know how to monitor the size of  
>the stack (i.e., how much is still available)?  I don't know of any way to  
>set the stack size for a given program except trial and error.

It's whatever the value of SP is.  The stack starts at the size it's set to
by the $M directive, and grows downward to 0.  The SPtr() function returns
the current stack pointer (and adds 4 to account for the far return address
that's been pushed onto the stack by calling the function).

If you're outputting it in code and printing it to the screen, make sure you
don't call it as a parameter to a procedure such as writeln() -- its return
value is slightly off.  Instead:

var
  stkleft : word;

begin
  stkleft := SPtr;
  writeln ('Stack left:  ',stkleft,' bytes.');
end;

Or if you're stepping and/or tracing, you can call up the registers window
and watch what happens to it.

Or, third possibility:  monitor by TSR.  Rough, unpolished, untested, no
guarantees about the correctness/functionality of this:

unit stackmon;

{$F+,R-,Q-,S-}

{
 Unit to find out how much stack your program used while running.

 Written by Scott Earnest (siny...@{*word*104}space.org)

 This code has NOT been tested, but should work.  Use at your own discretion.

Quote
}

interface

var
  stackmin : word; {public in case you want to peek at it}

implementation

var
  OldTimerInt : procedure;
  exitchain : pointer;
  tmpstack : word; {to keep a local variable off the stack}

procedure StackCheck1C (Flags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP : word);
interrupt;

begin
  asm
    cli
    mov  ax,sp {can SP be moved directly to memory?}
    mov  [tmpstack],ax
  end;
  if tmpstack+6<stackmin then {6 bytes -- 4 for address, 2 for Flags}
    stackmin := tmpstack+6;
  asm
    pushf
    sti
  end;
  OldTimerInt;
end;

procedure stackexit;

begin
  setintvec ($1c,@OldTimerInt);
  exitproc := exitchain;
  writeln ('Minimum stack left was:  ',stackmin);
end;

begin
  stackmin := SPtr;
  getintvec ($1c,@OldTimerInt);
  setintvec ($1c,@StackCheck1C);
end.

Quote
>Thanks,

Welcome.

Quote
>Chris Mathews

--
Scott Earnest          | We now return you to our regularly scheduled |
siny...@{*word*104}space.org | chaos and mayhem. . . .                      |

Re:Stack overflow


Re:Stack overflow


Quote
In article <sinykal.474.00098...@{*word*104}space.org> siny...@{*word*104}space.org (Scott Earnest) writes:

Hmmm, okay.  I've taken a little time to pull this down and look at it and
there are a couple problems -- just what I get for working blind.  First,
two omissions keep it from working.  Second . . . well, I'll get to that.

Quote
>[...]
>unit stackmon;
>[...]
>implementation

Add here:

uses
  dos;

Quote
>[...]
>begin
>  stackmin := SPtr;

Add here:

  exitchain := exitproc;
  exitproc := @stackexit;

Quote
>  getintvec ($1c,@OldTimerInt);
>  setintvec ($1c,@StackCheck1C);
>end.

And the second comment was. . . .

Now, even with that done, it doesn't produce useful results.  It always
seems to give a worthless answer, always around 2K.  I tested it with stack
sizes of 16K and 4K (sufficiently different, I think), and one gave 2344,
and the other 2042, respectively.  Also tested with programs that use
recursive procedures (directory tree walker).  Any ideas why this could be
happening?  Some things I thought of and tried:

- Get BP rather than SP.  Same wrong number.
- Make tmpstack local.  Same wrong number, but 2 bytes off.
- Tried without parameters to save registers.  Nope.
- Only check the value of SP if the InDOS flag is clear (something I had to
  do in another ISR I just wrote).

One theory I have is that DS might not be valid when the interrupt is
called, so [tmpstack] might be a meaningless address.  Is it safe to call
DSeg in an ISR, and if so, does can it be relied upon to return the correct
value of DS?

I'd like to figure out both why this doesn't work, and how to make it work.  
This would make a useful testing tool.  Well, at least the ISR structuring
is correct, and it doesn't crash.

Quote
>[...]
>--
>Scott Earnest          | We now return you to our regularly scheduled |
>siny...@{*word*104}space.org | chaos and mayhem. . . .                      |

Hey, Osmo, now do you believe me when I say I'm not capable of writing
totally bug free code?  ;-)

--
Scott Earnest          | We now return you to our regularly scheduled |
siny...@{*word*104}space.org | chaos and mayhem. . . .                      |

Go to page: [1] [2]

Other Threads