setjump problem

A

Anders Koeln

Hi

I'm having a problem with setjump()/longjump(). The actual calls
are disguised inside two routines which attempt to implement an
exception handling mechanism.

The first routine, try() calls setjmp(). The throw() routine
calls longjmp(). According to my man page, setjmp() returns 0
when it is really called and 1 when it got there via longjump().
I test for a 1 return and jump to the exception handler.

Except that's not what's happening. Inside the try() routine,
I can see setjmp() being called, and returning 0. Then, my
main code calls throw(), and I see setjump() returning 1. Instead
of returning to the point where try() was called, however, it
returns to the point after which throw() was called, as if
throw() had returned normally without doing a longjmp().

|
try <-.
| |
V |
throw |
|____|

That's what I expect to happen.

|
.- try <-.
| | |
| V |
| throw |
| |____|
|___.
|
V

That's what's actually happening.

Thanks in advance for any help.
 
E

Eric Sosman

You can't call longjmp after the routine that called setjmp has returned,
even if you're using the same jmp_buf object. In other words, try() can't be
a function. setjmp doesn't preserve the entire stack at the time it's
called, just the state of the immediate function invocation.

Well, we really don't know *what* setjmp() preserves; that's up
to the implementation. Still, William is right: Once the caller of
setjmp() returns, undefined behavior ensues if longjmp() tries to use
the jmp_buf contents. The jmp_buf is usable only while the same
function invocation that called setjmp() is still active: Return from
that function and the jmp_buf is junk_buf, even if the function is
called again later on.

setjmp() and longjmp() are fundamentally filthy. They are not
"general," they are not "flexible," they are not "robust," and most
of all they are not to be used in *any* way other than "as advertised."

+--------------+
| BRIDGE OUT |
| SLOW TO 60 |
+--------------+
 
C

Chris M. Thomasson

Anders Koeln said:
Hi

I'm having a problem with setjump()/longjump(). The actual calls
are disguised inside two routines which attempt to implement an
exception handling mechanism.

[...]

Check this crap out:

http://codepad.org/EVljvcze
___________________________________________________________
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <setjmp.h>


#define EXCEPTION_RECURSE_MAX 64
#define EXCEPTION_BUFFER_MAX 128


union exception_buffer
{
double align;
char buffer[EXCEPTION_BUFFER_MAX];
};


struct exception
{
long int code;
jmp_buf* jbuf;
union exception_buffer buf;
};


struct exception_global
{
unsigned int depth;
int results[EXCEPTION_RECURSE_MAX];
jmp_buf jbufs[EXCEPTION_RECURSE_MAX];
struct exception excepts[EXCEPTION_RECURSE_MAX];
};


static struct exception_global g_exception = { 0 };


#define TRY_LOOP_BEGIN \
for (++g_exception.depth;;) \
{ \
int result; \
struct exception* cur_exception = \
g_exception.excepts + (g_exception.depth - 1); \
\
cur_exception->jbuf = g_exception.jbufs + (g_exception.depth - 1); \
\
result = setjmp(g_exception.jbufs[g_exception.depth - 1]); \
if (! result)

#define CATCH(mp_code) \
else if (cur_exception->code == (mp_code)) \

#define CATCH_ALL() \
else if (1)

#define TRY_LOOP_END \
else if(result) \
{ \
assert(0); \
abort(); \
} \
} \
--g_exception.depth;

#define TRY_LOOP_BREAK break

#define THROW(mp_code) \
(g_exception.excepts[g_exception.depth - 1].code = (mp_code), \
longjmp(g_exception.jbufs[g_exception.depth - 1], 1))

#define THROW_GET_BUFFER() (g_exception.excepts[g_exception.depth -
1].buf.buffer)

#define CATCH_GET_BUFFER() (cur_exception->buf.buffer)

#define CATCH_GET_CODE() (cur_exception->code)








#include <string.h>


void throwable_1(int x, int ec)
{
if (! x)
{
strcpy(THROW_GET_BUFFER(), "some message");
THROW(ec);
}
}


void throwable_2(int x)
{
TRY_LOOP_BEGIN
{
throwable_1(5, 0);
throwable_1(0, 666);
}

CATCH(555)
{
puts("throwable_2: caught error 555");
TRY_LOOP_BREAK;
}

CATCH(666)
{
puts("throwable_2: caught error 666");
TRY_LOOP_BREAK;
}
TRY_LOOP_END
}


int
main(void)
{
TRY_LOOP_BEGIN
{
throwable_1(5, 0);
throwable_2(0);
throwable_1(0, 777);
}

CATCH(555)
{
puts("main: caught error 555");
TRY_LOOP_BREAK;
}

CATCH(666)
{
puts("main: caught error 666");
TRY_LOOP_BREAK;
}

CATCH_ALL()
{
printf("main: caught unknown error... code: %lu\n",
CATCH_GET_CODE());
printf("exception message: %s\n", CATCH_GET_BUFFER());
TRY_LOOP_BREAK;
}
TRY_LOOP_END


puts("\n\n\n___________________________________________\n"
"The program has completed; hit <ENTER> to exit...");

getchar();

return 0;
}
___________________________________________________________



What do you think of that hacked up shi%! lol ;^)
 
B

Ben Pfaff

christian.bau said:
With any exception handling mechanism there is always the problem what
happens with all the resources that have been allocated between the
point where the exception context was set up (setjmp) and the point
where the exception was raised (longjmp). C++ and Java have mechanisms
that take care of this in many cases; destructors in C++ and garbage
collection in Java, and it is a pain when these mechanism are not
enough. C doesn't have either of these, so you have to do it by hand
_always_. You have the pain _always_. Frankly, I don't think it is
worth it.

You can make it easier in C, too, by using a resource pool object,
that keeps track of resources that need to be released, and then
using that object to release them instead of doing it manually.
This can sometimes make code simpler and easier to understand.
 

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

Similar Threads


Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top