Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > The stack and longjmp/setjmp

Reply
Thread Tools

The stack and longjmp/setjmp

 
 
jacob navia
Guest
Posts: n/a
 
      03-04-2008
The stack is one of the central structures in C. Continuing this series
of installments, we come to the interactions of longjmp/setjmp (and also
the lowly "goto" statement) with the stack.

As you know, longjmp/setjmp allow a non-local transfer of control from
a point in the execution of the program to another, completely unrelated
point using a previously established context.

One of the problems with the couple of functions in question (setjmp
establishes this context, longjmp uses a context to return to the
point where the context was established) is a situation like this:

int fn(void)
{
char *m = malloc(BUFSIZ);
fn1(m);
free(m);
}

This looks perfectly correct, no leaks.

Well, the problem arises when fn1 makes a longjmp to somewhere else,
completely bypassing the free() instruction and making for a memory
leak.

One of the advantages of alloca() by the way, is that alloca() will NOT
produce a leak in this case. But obviously too, the call to "malloc"
is just an example of resource allocation. fopen() could have been
called instead of malloc, and we would have the same problem.

There are several solutions for this, one of them would be to indicate
a piece of code that should be executed in the case of a non local
jump across this function.

This is the solution proposed by C's cousin, C++. The run time "walks
upwards" the stack, executing all code marked for execution in this
case. This is not possible in standard C (yet) but there are proposals
that try to introduce the famous try/catch couple into C.

In any case there is absolutely NO solution for this problem within
standard C.

But even without longjmp/setjmp, a simple "goto" can make things quite
messy:

goto lab3; // invalid: going INTO scope of VLA.
{
double a[n];
a[j] = 4.4;
lab3:
a[j] = 3.3;
goto lab4; // valid: going WITHIN scope of VLA.
a[j] = 5.5;
lab4:
a[j] = 6.6;
}
goto lab4; // invalid: going INTO scope of VLA

This rules are specified by the standard to preserve the integrity
of the stack. If there is an implementation that increases/decreases
dynamically the stack, jumping into the middle of such a block
bypassing the stack adjustment can only crash the program!

Note that the problem *remains* even if you do NOT use C99 t all:
{
double a[5];
a[j] = 4.4;
lab3:
a[j] = 3.3;
goto lab4; // valid: going WITHIN scope of VLA.
a[j] = 5.5;
lab4:
a[j] = 6.6;
}

In an implementation that increases/decreases the stack pointer when
such a block is found, the goto into the middle of the block would
bypass the stack adjusting anyway, even if it is a fixed amount and
not a variable one as above.

What are the general rules that can be followed to avoid problems?

As I said above, there is NO standard solution for the longjmp/setjmp
problem within the ISO subset of the language

For the goto, the solution is quite obvious:

"Never do a goto into the middle of a block"


--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
 
Reply With Quote
 
 
 
 
santosh
Guest
Posts: n/a
 
      03-04-2008
jacob navia wrote:

> The stack is one of the central structures in C. Continuing this
> series of installments, we come to the interactions of longjmp/setjmp
> (and also the lowly "goto" statement) with the stack.
>
> As you know, longjmp/setjmp allow a non-local transfer of control from
> a point in the execution of the program to another, completely
> unrelated point using a previously established context.
>
> One of the problems with the couple of functions in question (setjmp
> establishes this context, longjmp uses a context to return to the
> point where the context was established) is a situation like this:
>
> int fn(void)
> {
> char *m = malloc(BUFSIZ);
> fn1(m);
> free(m);
> }
>
> This looks perfectly correct, no leaks.
>
> Well, the problem arises when fn1 makes a longjmp to somewhere else,
> completely bypassing the free() instruction and making for a memory
> leak.
>
> One of the advantages of alloca() by the way, is that alloca() will
> NOT produce a leak in this case.


<snip>

Do you mean to say that memory allocated with alloca will be properly
freed even if the execution jumps to another function via longjmp?

 
Reply With Quote
 
 
 
 
jacob navia
Guest
Posts: n/a
 
      03-04-2008
santosh wrote:
>> int fn(void)
>> {
>> char *m = malloc(BUFSIZ);
>> fn1(m);
>> free(m);
>> }
>>
>> This looks perfectly correct, no leaks.
>>
>> Well, the problem arises when fn1 makes a longjmp to somewhere else,
>> completely bypassing the free() instruction and making for a memory
>> leak.
>>
>> One of the advantages of alloca() by the way, is that alloca() will
>> NOT produce a leak in this case.

>
> <snip>
>
> Do you mean to say that memory allocated with alloca will be properly
> freed even if the execution jumps to another function via longjmp?
>


Of course. Since longjmp unwinds the stack, that memory will be
automatically freed when the stack is unwound.


--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
 
Reply With Quote
 
Harald van Dijk
Guest
Posts: n/a
 
      03-04-2008
On Wed, 05 Mar 2008 01:26:18 +0530, santosh wrote:
> jacob navia wrote:
>> int fn(void)
>> {
>> char *m = malloc(BUFSIZ);
>> fn1(m);
>> free(m);
>> }
>>
>> This looks perfectly correct, no leaks.
>>
>> Well, the problem arises when fn1 makes a longjmp to somewhere else,
>> completely bypassing the free() instruction and making for a memory
>> leak.
>>
>> One of the advantages of alloca() by the way, is that alloca() will NOT
>> produce a leak in this case.

>
> <snip>
>
> Do you mean to say that memory allocated with alloca will be properly
> freed even if the execution jumps to another function via longjmp?


If he is, he's correct for at least the system I'm using, which explains
this its documentation for alloca.

Of course, as alloca is non-standard, other systems are permitted to
implement it differently. I don't know if any do, but I expect it would be
implemented the same way as VLAs, and VLAs can be leaked by longjmp.
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      03-04-2008
jacob navia wrote:
> [...]
> As you know, longjmp/setjmp allow a non-local transfer of control from
> a point in the execution of the program to another, completely unrelated
> point using a previously established context.


"Completely unrelated?" There are some rather strict
requirements on the relation of the longjmp() call to the
corresponding setjmp().

--
http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
jacob navia
Guest
Posts: n/a
 
      03-04-2008
Eric Sosman wrote:
> jacob navia wrote:
>> [...]
>> As you know, longjmp/setjmp allow a non-local transfer of control from
>> a point in the execution of the program to another, completely unrelated
>> point using a previously established context.

>
> "Completely unrelated?" There are some rather strict
> requirements on the relation of the longjmp() call to the
> corresponding setjmp().
>


Interesting

Can you explain what those strict requirements could be?



--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
 
Reply With Quote
 
santosh
Guest
Posts: n/a
 
      03-04-2008
jacob navia wrote:

> Eric Sosman wrote:
>> jacob navia wrote:
>>> [...]
>>> As you know, longjmp/setjmp allow a non-local transfer of control
>>> from a point in the execution of the program to another, completely
>>> unrelated point using a previously established context.

>>
>> "Completely unrelated?" There are some rather strict
>> requirements on the relation of the longjmp() call to the
>> corresponding setjmp().
>>

>
> Interesting
>
> Can you explain what those strict requirements could be?


n1256 7.13.2.1 (2):

The longjmp function restores the environment saved by the most recent
invocation of the setjmp macro in the same invocation of the program
with the corresponding jmp_buf argument. If there has been no such
invocation, or if the function containing the invocation of the setjmp
macro has terminated execution217) in the interim, or if the invocation
of the setjmp macro was within the scope of an identifier with variably
modified type and execution has left that scope in the interim, the
behavior is undefined.

 
Reply With Quote
 
jacob navia
Guest
Posts: n/a
 
      03-04-2008
santosh wrote:
> jacob navia wrote:
>
>> Eric Sosman wrote:
>>> jacob navia wrote:
>>>> [...]
>>>> As you know, longjmp/setjmp allow a non-local transfer of control
>>>> from a point in the execution of the program to another, completely
>>>> unrelated point using a previously established context.
>>> "Completely unrelated?" There are some rather strict
>>> requirements on the relation of the longjmp() call to the
>>> corresponding setjmp().
>>>

>> Interesting
>>
>> Can you explain what those strict requirements could be?

>
> n1256 7.13.2.1 (2):
>
> The longjmp function restores the environment saved by the most recent
> invocation of the setjmp macro in the same invocation of the program
> with the corresponding jmp_buf argument. If there has been no such
> invocation, or if the function containing the invocation of the setjmp
> macro has terminated execution217) in the interim, or if the invocation
> of the setjmp macro was within the scope of an identifier with variably
> modified type and execution has left that scope in the interim, the
> behavior is undefined.
>


That is surely not "strong requirements"!

1: Obviously, you call setjmp THEN longjmp. Doing otherwise is ABI
(A Bad Idea)
2: The setjmp call point should be in the stack... Not very difficult
to understand.
3: To preserve the stack, you can't longjmp into the middle of a
block with variable length arrays. See my discussion of goto
in my post.

Obviously, there are *some* requirements. I wouldn't call them
"strict", but if you want, OK.




--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
 
Reply With Quote
 
CBFalconer
Guest
Posts: n/a
 
      03-04-2008
jacob navia wrote:
>
> The stack is one of the central structures in C. Continuing this
> series of


off-topic posts. C does not have a stack. Your C may have a stack.

> installments, we come to the interactions of longjmp/setjmp (and
> also the lowly "goto" statement) with the stack.


Please post these things to comp.std.c, or to comp.compilers.lcc,
or to some newsgroup where it may be topical. Not here.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.



--
Posted via a free Usenet account from http://www.teranews.com

 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      03-04-2008
jacob navia wrote:
> santosh wrote:
>> jacob navia wrote:
>>
>>> Eric Sosman wrote:
>>>> jacob navia wrote:
>>>>> [...]
>>>>> As you know, longjmp/setjmp allow a non-local transfer of control
>>>>> from a point in the execution of the program to another, completely
>>>>> unrelated point using a previously established context.
>>>> "Completely unrelated?" There are some rather strict
>>>> requirements on the relation of the longjmp() call to the
>>>> corresponding setjmp().
>>>>
>>> Interesting
>>>
>>> Can you explain what those strict requirements could be?

>>
>> n1256 7.13.2.1 (2):
>>
>> The longjmp function restores the environment saved by the most recent
>> invocation of the setjmp macro in the same invocation of the program
>> with the corresponding jmp_buf argument. If there has been no such
>> invocation, or if the function containing the invocation of the setjmp
>> macro has terminated execution217) in the interim, or if the invocation
>> of the setjmp macro was within the scope of an identifier with variably
>> modified type and execution has left that scope in the interim, the
>> behavior is undefined.
>>

>
> That is surely not "strong requirements"!


No, some people seem to treat them as mere advisories.
Others are less eager to encounter undefined behavior.

> 1: Obviously, you call setjmp THEN longjmp. Doing otherwise is ABI
> (A Bad Idea)
> 2: The setjmp call point should be in the stack... Not very difficult
> to understand.
> 3: To preserve the stack, you can't longjmp into the middle of a
> block with variable length arrays. See my discussion of goto
> in my post.
>
> Obviously, there are *some* requirements. I wouldn't call them
> "strict", but if you want, OK.


Well, I certainly wouldn't say they add up to "completely
unrelated ..."

There's also the problem illustrated by this code:

#include <stdio.h>
#include <setjmp.h>
jmp_buf context;

void func(int which) {
if (which == 0)
setjmp (context);
else
longjmp (context, 42);
}

int main(void) {
puts ("Hello, world!");
func (0);
puts ("Goodbye, cruel world!");
func (1);
puts ("Is there life after death?");
return 0;
}

Observe that this code satisfies all three of your
conditions, yet the behavior is undefined. (Suggested fix:
tighten up the wording of your second condition.)

--
(E-Mail Removed)


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Why does std::stack::pop() not throw an exception if the stack is empty? Debajit Adhikary C++ 36 02-10-2011 08:54 PM
C/C++ compilers have one stack for local variables and return addresses and then another stack for array allocations on the stack. Casey Hawthorne C Programming 3 11-01-2009 08:23 PM
stack frame size on linux/solaris of a running application stack Surinder Singh C Programming 1 12-20-2007 01:16 PM
Why stack overflow with such a small stack? Kenneth McDonald Ruby 7 09-01-2007 04:21 AM
"stack level too deep"... because Threads keep their "starting" stack Sam Roberts Ruby 1 02-11-2005 04:25 AM



Advertisments