Exception handling crashes or exits

F

Fabiano Sidler

Hi folks!

I'm using gcc 4.2.3 and glibc6 2.7.
I'm doing an exception handling implementation for a library. Although I
assume to have it done properly, with a handler set up, it exits the program
with a random exit value, and without a handler set up, it crashes with a
SIGSEGV, but as I have found out with gdb, at the same line of code:

__libc_siglongjmp (env=0xbfb935f0, val=1) at longjmp.c:29
29 {
31 _longjmp_unwind (env, val);
_longjmp_unwind (env=0xbfb935f0, val=1) at
../nptl/sysdeps/unix/sysv/linux/jmp-unwind.c:32
32 if (__libc_pthread_functions_init)
39 }
__libc_siglongjmp (env=0xbfb935f0, val=1) at longjmp.c:33
33 if (env[0].__mask_was_saved)
39 __longjmp (env[0].__jmpbuf, val ?: 1);


The types i use are:

typedef struct ExcType ExcType;
typedef struct ExcVal ExcVal;
typedef struct Exception Exception;
struct ExcType {
const char *name;
};
union ExcVal {
void* None;
int Int;
char* Char;
};
typedef enum {
NoneType,
IntType,
CharType
} Datatype;
struct Exception {
ExcType *tp;
ExcVal *val;
Datatype dt;
};
struct ExcEntry {
ExcEntry *prev,*next;
jmp_buf buf;
Exception *exc;
};
extern ExcEntry *currexc;


My macros for doing exception handling are as follows:

#define try \
{\
Exception exc;\
ExcEntry excn;\
excn.exc=&exc; excn.prev=currexc;\
currexc = excn.prev->next = &excn;\
if ( setjmp(excn.buf)==0 )
#define catch(e) \
Exception *e = &exc;\
for (;0;currexc=currexc->prev)
#define exctype(et, action) \
if ( e->tp==&et ) { action; }
#define endtry }
#define throw(t,vl) \
{currexc->exc->tp=NULL;\
currexc->exc->tp=&t;\
currexc->exc->val->Char=(char*)vl;\
currexc->exc->dt=CharType;\
jmp_buf buf;\
memcpy((void*)&buf,(void*)currexc->buf, sizeof(jmp_buf));\
longjmp(buf,1);}


A sample program could be:

#include <stdio.h>
ExcType RuntimeError;
int main(int argc, char **argv)
{
try {
throw(RuntimeError,"test error");
} catch(e) {
fprintf(stderr,"foobar!\n");
exit(42);
} endtry;
}


I don't see where the problem is. Any professional here who can help me?

Greetings,
Fabiano
 
A

Andrew Poelstra

Hi folks!

I'm using gcc 4.2.3 and glibc6 2.7.
I'm doing an exception handling implementation for a library. Although I
assume to have it done properly, with a handler set up, it exits the program
with a random exit value, and without a handler set up, it crashes with a
SIGSEGV, but as I have found out with gdb, at the same line of code:

__libc_siglongjmp (env=0xbfb935f0, val=1) at longjmp.c:29
29 {
31 _longjmp_unwind (env, val);
_longjmp_unwind (env=0xbfb935f0, val=1) at
../nptl/sysdeps/unix/sysv/linux/jmp-unwind.c:32
32 if (__libc_pthread_functions_init)
39 }
__libc_siglongjmp (env=0xbfb935f0, val=1) at longjmp.c:33
33 if (env[0].__mask_was_saved)
39 __longjmp (env[0].__jmpbuf, val ?: 1);


The types i use are:

typedef struct ExcType ExcType;
typedef struct ExcVal ExcVal;
typedef struct Exception Exception;
struct ExcType {
const char *name;
};
union ExcVal {
void* None;
int Int;
char* Char;
};
typedef enum {
NoneType,
IntType,
CharType
} Datatype;
struct Exception {
ExcType *tp;
ExcVal *val;
Datatype dt;
};
struct ExcEntry {
ExcEntry *prev,*next;
jmp_buf buf;
Exception *exc;
};
extern ExcEntry *currexc;

Where is this defined? You appear to use it without ever
defining it. Does this program link successfully?
 
A

Andrew Poelstra

Hi folks!

I'm using gcc 4.2.3 and glibc6 2.7.
I'm doing an exception handling implementation for a library. Although I
assume to have it done properly, with a handler set up, it exits the program
with a random exit value, and without a handler set up, it crashes with a
SIGSEGV, but as I have found out with gdb, at the same line of code:

__libc_siglongjmp (env=0xbfb935f0, val=1) at longjmp.c:29
29 {
31 _longjmp_unwind (env, val);
_longjmp_unwind (env=0xbfb935f0, val=1) at
../nptl/sysdeps/unix/sysv/linux/jmp-unwind.c:32
32 if (__libc_pthread_functions_init)
39 }
__libc_siglongjmp (env=0xbfb935f0, val=1) at longjmp.c:33
33 if (env[0].__mask_was_saved)
39 __longjmp (env[0].__jmpbuf, val ?: 1);


The types i use are:

typedef struct ExcType ExcType;
typedef struct ExcVal ExcVal;
typedef struct Exception Exception;
struct ExcType {
const char *name;
};
union ExcVal {
void* None;
int Int;
char* Char;
};
typedef enum {
NoneType,
IntType,
CharType
} Datatype;
struct Exception {
ExcType *tp;
ExcVal *val;
Datatype dt;
};
struct ExcEntry {
ExcEntry *prev,*next;
jmp_buf buf;
Exception *exc;
};
extern ExcEntry *currexc;

Where is this defined? You appear to use it without ever
defining it. Does this program link successfully?
 
F

Fabiano Sidler

Where is this defined?

jmp_buf is defined in setjmp.h which is, in turn, an ANSI C header.
Maybe i should have written this...in my program, it is included.
Does this program link successfully?

<setjmp.h> must be included and the definitions (and the declaration)
must be done before main(), but then it does, otherwise it couldn't SEGSEGV
here...;)

Greetings,
Fabiano
 
F

Fabiano Sidler

Where is this defined?

jmp_buf is defined in setjmp.h which is, in turn, an ANSI C header.
Maybe i should have written this...in my program, it is included.
Does this program link successfully?

<setjmp.h> must be included and the definitions (and the declaration)
must be done before main(), but then it does, otherwise it couldn't SEGSEGV
here...;)

Greetings,
Fabiano
 
A

Andrew Poelstra

jmp_buf is defined in setjmp.h which is, in turn, an ANSI C header.
Maybe i should have written this...in my program, it is included.

Sure, but jmp_buf is just a member of the currexc object, for
which storage is never allocated (since this object is not
defined, as far as I can tell).
 
K

Keith Thompson

Andrew Poelstra said:
Sure, but jmp_buf is just a member of the currexc object, for
which storage is never allocated (since this object is not
defined, as far as I can tell).

Here's the relevant code from the original article:
| struct ExcEntry {
| ExcEntry *prev,*next;
| jmp_buf buf;
| Exception *exc;
| };
| extern ExcEntry *currexc;

jmp_buf is a type, declared in the standard header <setjmp.h>. The
point is simply that you can't refer to the name "jmp_buf" unless you
have a "#include <setjmp.h>".

buf, on the other hand, is a member of the type struct ExcEntry; that
member is of type jmp_buf. And currexc is a pointer to struct
ExcEntry. So buf (not jmp_buf) is a member of *currexc (not currexc).

[...]
 
A

Andrew Poelstra

Andrew Poelstra said:
Sure, but jmp_buf is just a member of the currexc object, for
which storage is never allocated (since this object is not
defined, as far as I can tell).

Here's the relevant code from the original article:
| struct ExcEntry {
| ExcEntry *prev,*next;
| jmp_buf buf;
| Exception *exc;
| };
| extern ExcEntry *currexc;

jmp_buf is a type, declared in the standard header <setjmp.h>. The
point is simply that you can't refer to the name "jmp_buf" unless you
have a "#include <setjmp.h>".

buf, on the other hand, is a member of the type struct ExcEntry; that
member is of type jmp_buf. And currexc is a pointer to struct
ExcEntry. So buf (not jmp_buf) is a member of *currexc (not currexc).

[...]

But currexc is declared as extern and never defined, so when is
storage set aside for the pointer itself?

(But you are right, I missed that currexc was a pointer.)
 
P

Peter Nilsson

Fabiano Sidler said:
I'm doing an exception handling implementation for a
library. ...

The types i use are:

typedef struct ExcType ExcType;
typedef struct ExcVal ExcVal;
typedef struct Exception Exception;
struct ExcType {
        const char *name;};

union ExcVal {
        void* None;
        int Int;
        char* Char;};

typedef enum {
        NoneType,
        IntType,
        CharType} Datatype;

struct Exception {
        ExcType *tp;
        ExcVal *val;
        Datatype dt;};

struct ExcEntry {
        ExcEntry *prev,*next;
        jmp_buf buf;
        Exception *exc;};

extern ExcEntry *currexc;

My macros for doing exception handling are as follows:

#define try \
        {\
                Exception exc;\
                ExcEntry excn;\
                excn.exc=&exc; excn.prev=currexc;\

Are you sure currexc is not a null pointer?
                currexc = excn.prev->next = &excn;\

If it is, this line is problematic.
                if ( setjmp(excn.buf)==0 )
#define catch(e) \
                Exception *e = &exc;\

Seems to be missing an 'else' for the above 'if'. Also,
I prefer to insert the { } blocks directly (split across
the macros,) rather than relying on the user to supply
them.
 
F

Fabiano Sidler

I _do_ include setjmp.h, this is not the problem...i don't get errors
due to that, anyway! ;)

Greetings,
Fabiano
 
F

Fabiano Sidler

Are you sure currexc is not a null pointer?

currexc is initialized as follows:

ExcEntry *currexc = &(ExcEntry) {
NULL,
NULL,
{0},
&(Exception) {
NULL,
&(ExcVal) { 0 },
0
}
};

And yes, this is valid C, C99! ;)
Your other points i'm working on right now...:)

Thanks in advance,
Fabiano
 
F

Fabiano Sidler

Here is the complete demo program:

--- snip ---
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>

typedef struct ExcType ExcType;
typedef union ExcVal ExcVal;
typedef struct Exception Exception;
typedef struct ExcEntry ExcEntry;
struct ExcType {
const char *name;
};
union ExcVal {
void* None;
int Int;
char* Char;
};
typedef enum {
NoneType,
IntType,
CharType
} Datatype;
struct Exception {
ExcType *tp;
ExcVal *val;
Datatype dt;
};
struct ExcEntry {
ExcEntry *prev,*next;
jmp_buf buf;
Exception *exc;
};
ExcEntry *currexc = &(ExcEntry) {
NULL,
NULL,
{0},
&(Exception) {
NULL, &(ExcVal){0}, 0
}
};
#define try \
{\
Exception exc;\
ExcEntry excn;\
excn.exc=&exc; excn.prev=currexc;\
currexc = excn.prev->next = &excn;\
if ( setjmp(excn.buf)==0 )
#define catch(e) \
Exception *e = &exc;\
for (;0;currexc=currexc->prev)
#define exctype(et, action) \
if ( e->tp==&et ) { action; }
#define endtry }
#define throw(t,vl) \
{currexc->exc->tp=NULL;\
currexc->exc->tp=&t;\
currexc->exc->val->Char=(char*)vl;\
currexc->exc->dt=CharType;\
jmp_buf buf;\
memcpy((void*)&buf,(void*)currexc->buf, sizeof(jmp_buf));\
longjmp(buf,1);}

ExcType RuntimeError;

int main(int argc, char **argv)
{
try {
throw(RuntimeError,"test error");
} catch(e) {
fprintf(stderr, "caught\n");
exit(0);
} endtry
fprintf(stderr, "uncaught\n");
return 42;
}
--- snap ---

Greetings,
Fabiano
 
T

Thomas Austad

Fabiano said:
Here is the complete demo program:

--- snip ---
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>

typedef struct ExcType ExcType;
typedef union ExcVal ExcVal;
typedef struct Exception Exception;
typedef struct ExcEntry ExcEntry;
struct ExcType {
const char *name;
};
union ExcVal {
void* None;
int Int;
char* Char;
};
typedef enum {
NoneType,
IntType,
CharType
} Datatype;
struct Exception {
ExcType *tp;
ExcVal *val;
Datatype dt;
};
struct ExcEntry {
ExcEntry *prev,*next;
jmp_buf buf;
Exception *exc;
};
ExcEntry *currexc = &(ExcEntry) {
NULL,
NULL,
{0},
&(Exception) {
NULL, &(ExcVal){0}, 0
}
};
#define try \
{\
Exception exc;\
ExcEntry excn;\
excn.exc=&exc; excn.prev=currexc;\
currexc = excn.prev->next = &excn;\
if ( setjmp(excn.buf)==0 )

I'm not sure what you try to accomplish in the "catch" macro. But do you
really want to execute the for-loop zero times?
#define catch(e) \
Exception *e = &exc;\
for (;0;currexc=currexc->prev)
#define exctype(et, action) \
if ( e->tp==&et ) { action; }
#define endtry }
#define throw(t,vl) \
{currexc->exc->tp=NULL;\
currexc->exc->tp=&t;\

Isn't currexc->exc->val a NULL pointer at this point. Thus giving you
the SIGSEGV?
 
N

Nate Eldredge

Fabiano Sidler said:
Here is the complete demo program:

--- snip ---
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>

typedef struct ExcType ExcType;
typedef union ExcVal ExcVal;
typedef struct Exception Exception;
typedef struct ExcEntry ExcEntry;
struct ExcType {
const char *name;
};
union ExcVal {
void* None;
int Int;
char* Char;
};
typedef enum {
NoneType,
IntType,
CharType
} Datatype;
struct Exception {
ExcType *tp;
ExcVal *val;
Datatype dt;
};
struct ExcEntry {
ExcEntry *prev,*next;
jmp_buf buf;
Exception *exc;
};
ExcEntry *currexc = &(ExcEntry) {
NULL,
NULL,
{0},
&(Exception) {
NULL, &(ExcVal){0}, 0
}
};
#define try \
{\
Exception exc;\
ExcEntry excn;\
excn.exc=&exc; excn.prev=currexc;\

You have not initialized exc.val to point to anything...
currexc = excn.prev->next = &excn;\
if ( setjmp(excn.buf)==0 )
#define catch(e) \
Exception *e = &exc;\
for (;0;currexc=currexc->prev)
#define exctype(et, action) \
if ( e->tp==&et ) { action; }
#define endtry }
#define throw(t,vl) \
{currexc->exc->tp=NULL;\
currexc->exc->tp=&t;\
currexc->exc->val->Char=(char*)vl;\

so it crashes here.

After fixing this it doesn't crash, but it still doesn't catch the
exception. I'm a bit suspicious of your linked list handling, since
the `next' pointers never seem to be used. I don't have the time to
trace through it now, but I'd recommend a careful look.

For debugging I found it helpful to do

gcc -E foo.c |grep -v '# [0-9]' |indent >foo.i
gcc -g foo.i

so that the macros are expanded onto multiple lines, making it easier
to single-step in a debugger.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,071
Latest member
MetabolicSolutionsKeto

Latest Threads

Top