setjmp and longjmp problem

A

aleksa

static jmp_buf environment;

void testproc (void)
{
longjmp(environment, 1);
}

long do_setjmp (void)
{
return setjmp(environment);
}

long testing (void)
{
long status;

status = setjmp(environment);
// status = do_setjmp();

if (status == 0) {
testproc();
return -1;
}

return status;
}

Prog starts in 'testing', calls setjmp then calls testproc which calls
longjmp.

Now, if I call setjmp from 'testing', it works. First time, returned
status is zero,
so testproc gets called, second time is 1, so I return the status(1).

But, if I call setjmp with do_setjmp, when I call testproc and it
calls longjmp,
longjmp does return where it is supposed to (in do_setjmp) but
do_setjmp
then returns to 'return -1;', i.e. after a call to testproc, and not
to 'if (status == 0)'.

Why?

Cheers,
Aleksandar
 
C

Chine Bleu, Blanc, et Rouge

aleksa said:
static jmp_buf environment;

void testproc (void)
{
longjmp(environment, 1);
}

long do_setjmp (void)
{
return setjmp(environment);

You cannot longjmp to a target after its containing function is exitted. In this
case, as a do_setjmp returns, the target environment is invalid. (Or the call
frame of the setjmp has to still be on the stack when the longjmp is called.)
long testing (void)
{
long status;

status = setjmp(environment);

This setjmp remains valid until testing is exitted.
// status = do_setjmp();

if (status == 0) {
testproc();

The longjmp can be in a function called from setjmp's containing function. The
function testing is still active when testproc is called, so the target
enviroment is still valid and execution should resume above with status==1.
 
F

Francois Grieu

static jmp_buf environment;

void testproc (void)
{
longjmp(environment, 1);
}

long do_setjmp (void)
{
return setjmp(environment);
}

long testing (void)
{
long status;

status = setjmp(environment);
// status = do_setjmp();

if (status == 0) {
testproc();
return -1;
}

return status;
}

Prog starts in 'testing', calls setjmp then calls testproc which calls
longjmp.

Now, if I call setjmp from 'testing', it works. First time, returned
status is zero,
so testproc gets called, second time is 1, so I return the status(1).

But, if I call setjmp with do_setjmp, when I call testproc and it
calls longjmp,
longjmp does return where it is supposed to (in do_setjmp) but
do_setjmp
then returns to 'return -1;', i.e. after a call to testproc, and not
to 'if (status == 0)'.

Why?

Because the function do_setjmp() that did the setjmp has terminated
execution when testproc does longjmp(), and that's prohibited by
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 (..)
the function containing the invocation of the setjmp macro has
terminated execution (for example, by executing a return statement
(..)) in the interim (..) the behavior is undefined.

Francois Grieu
 
K

Keith Thompson

aleksa said:
long do_setjmp (void)
{
return setjmp(environment);
}
[...]

setjmp() returns int. Why are you storing the result in a long?
(Not that that has anything to do with the problems you're seeing.)
 
F

Francois Grieu

Because the function do_setjmp() that did the setjmp has terminated
execution when testproc does longjmp(), and that's prohibited by
7.13.2.1#2:

Ah, but it triggers UB long before that. 7.13.1.1#4 and #5:

[#4] An invocation of the setjmp macro shall appear only in
one of the following contexts:

-- the entire controlling expression of a selection or
iteration statement;

-- one operand of a relational or equality operator with
the other operand an integer constant expression, with
the resulting expression being the entire controlling
expression of a selection or iteration statement;

-- the operand of a unary ! operator with the resulting
expression being the entire controlling expression of a
selection or iteration statement; or

-- the entire expression of an expression statement
(possibly cast to void).

[#5] If the invocation appears in any other context, the
behavior is undefined.

Right. The working variant of OP's code also infringes on that with
status = do_setjmp();

This is UB, although many if not most implementations are happy with it.

Francois Grieu
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,954
Messages
2,570,114
Members
46,702
Latest member
VernitaGow

Latest Threads

Top