Added a CLEANUP mechanism to the exception handling library. Fixed a bug in the way setjmp() return codes were being handled that lead to infinite loops in some cases, exceptions getting missed in others. Made FINALLY {} a required element (unfortunately).

This commit is contained in:
2024-12-22 08:55:51 -05:00
parent d20fbbebe6
commit 53e7e6a094
14 changed files with 195 additions and 82 deletions

View File

@@ -2,18 +2,19 @@ CC=gcc
LD=gcc LD=gcc
EXECOBJ= EXECOBJ=
LIBOBJECTS=src/exclib.o LIBOBJECTS=src/exclib.o
DEMOS=demo/single.exe demo/twolevel.exe demo/trypair.exe demo/catchgroup.exe demo/finally.exe demo/default.exe demo/helpers.exe demo/deepuncaught.exe DEMOS=demo/single.exe demo/twolevel.exe demo/trypair.exe demo/catchgroup.exe demo/finally.exe demo/default.exe demo/helpers.exe demo/deepuncaught.exe demo/cleanup.exe demo/skeleton.exe
LIBTARGET=lib/libexc.a LIBTARGET=lib/libexc.a
LIBS= LIBS=
CFLAGS= #CFLAGS=-Wall -Wextra -std=c89 -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition
CFLAGS=-std=c89
all: lib demo all: lib demo
demo/%.exe: demo/%.o lib demo/%.exe: demo/%.o lib
$(LD) -o $@ $(CFLAGS) -L./lib $< -lexc -ggdb -gstabs $(LD) -o $@ $(CFLAGS) -L./lib $< -lexc -ggdb
%.o: %.c %.o: %.c
$(CC) -c -o $@ $(CFLAGS) -ggdb -gstabs -I./include $< $(CC) -c -o $@ $(CFLAGS) -ggdb -I./include $<
.PHONY: demo .PHONY: demo
demo: $(DEMOS) demo: $(DEMOS)

View File

@@ -4,10 +4,12 @@ int main(void)
{ {
TRY { TRY {
THROW(2, NULL); THROW(2, NULL);
} EXCEPT {
} CATCH_GROUP(1) { } CATCH_GROUP(1) {
} CATCH_GROUP(2) { } CATCH_GROUP(2) {
} CATCH_GROUP(3) { } CATCH_GROUP(3) {
EXCLIB_TRACE("Inside of CATCH_GROUP"); EXCLIB_TRACE("Inside of CATCH_GROUP");
} FINALLY {
} ETRY; } ETRY;
return 0; return 0;
} }

36
demo/cleanup.c Normal file
View File

@@ -0,0 +1,36 @@
#include "exclib.h"
int main(void)
{
int val = 512;
int *ptr = &val;
TRY {
THROW(3, "Checking to ensure cleanup behavior executes before EXCEPT block");
} CLEANUP {
ptr = NULL;
} EXCEPT {
} CATCH(3) {
if ( ptr != NULL ) {
EXCLIB_TRACE("pointer was not reset to NULL in first CLEANUP block");
return 1;
}
} FINALLY {
} ETRY;
ptr = &val;
TRY {
/* No exception thrown here, CLEANUP should still execute */
} CLEANUP {
ptr = NULL;
} EXCEPT {
} FINALLY {
} ETRY;
if ( ptr != NULL ) {
EXCLIB_TRACE("pointer was not reset to NULL in first TRY block");
return 1;
}
return 0;
}

View File

@@ -6,8 +6,17 @@ int main(void)
TRY { TRY {
TRY { TRY {
THROW(3, NULL); THROW(3, NULL);
} CLEANUP {
} EXCEPT {
} FINALLY {
} ETRY; } ETRY;
} CLEANUP {
} EXCEPT {
} FINALLY {
} ETRY; } ETRY;
} CLEANUP {
} EXCEPT {
} FINALLY {
} ETRY; } ETRY;
return 0; return 0;

View File

@@ -5,8 +5,12 @@ int main(void)
{ {
TRY { TRY {
THROW(2, NULL); THROW(2, NULL);
} CLEANUP {
} EXCEPT {
} DEFAULT { } DEFAULT {
EXCLIB_TRACE("Inside of DEFAULT - I catch everything!"); EXCLIB_TRACE("Inside of DEFAULT - I catch everything!");
return 0;
} FINALLY {
} ETRY; } ETRY;
return 0; return 1;
} }

View File

@@ -5,8 +5,9 @@ int main(void)
{ {
TRY { TRY {
THROW(2, NULL); THROW(2, NULL);
} EXCEPT {
} FINALLY { } FINALLY {
printf("I am in the finally clause, and I am about to issue an unhandled exception error.\n"); printf("I am in the finally clause, and I am about to issue an unhandled exception error.\n");
} ETRY; } ETRY;
return 0; return 0;
} }

View File

@@ -4,10 +4,13 @@ int main(void)
{ {
TRY { TRY {
THROW_ZERO(NULL, EXC_NULLPOINTER, "I just threw with THROW_ZERO"); THROW_ZERO(NULL, EXC_NULLPOINTER, "I just threw with THROW_ZERO");
} CLEANUP {
} EXCEPT {
} CATCH ( EXC_NULLPOINTER ) { } CATCH ( EXC_NULLPOINTER ) {
THROW_NONZERO(strcmp("not", "equal"), THROW_NONZERO(strcmp("not", "equal"),
3, 3,
"strcmp was nonzero!"); "strcmp was nonzero!");
} FINALLY {
} ETRY; } ETRY;
return 0; return 0;

View File

@@ -12,8 +12,11 @@ int main(void)
TRY { TRY {
THROW(3, NULL); THROW(3, NULL);
} CLEANUP {
} EXCEPT {
} CATCH(3) { } CATCH(3) {
EXCLIB_TRACE("Caught 3"); EXCLIB_TRACE("Caught 3");
} FINALLY {
} ETRY; } ETRY;
EXCLIB_TRACE("Exiting program"); EXCLIB_TRACE("Exiting program");

10
demo/skeleton.c Normal file
View File

@@ -0,0 +1,10 @@
#include "exclib.h"
int main(void)
{
TRY {
} CLEANUP {
} EXCEPT {
} FINALLY {
} ETRY;
}

View File

@@ -5,11 +5,15 @@ int main(void)
TRY { TRY {
TRY { TRY {
THROW(3, NULL); THROW(3, NULL);
} EXCEPT {
} CATCH(5) { } CATCH(5) {
EXCLIB_TRACE("Caught 5"); EXCLIB_TRACE("Caught 5");
} FINALLY {
} ETRY; } ETRY;
} EXCEPT {
} CATCH(3) { } CATCH(3) {
EXCLIB_TRACE("Caught 3"); EXCLIB_TRACE("Caught 3");
} FINALLY {
} ETRY; } ETRY;
return 0; return 0;

View File

@@ -4,15 +4,24 @@ int main(void)
{ {
TRY { TRY {
THROW(3, NULL); THROW(3, NULL);
} CLEANUP {
} EXCEPT {
} CATCH(3) { } CATCH(3) {
} FINALLY {
} ETRY; } ETRY;
TRY { TRY {
THROW(3, NULL); THROW(3, NULL);
} CLEANUP {
} EXCEPT {
} CATCH(3) { } CATCH(3) {
TRY { TRY {
THROW(3, NULL); THROW(3, NULL);
} ETRY; } CLEANUP {
} EXCEPT {
} FINALLY {
} ETRY;
} FINALLY {
} ETRY; } ETRY;
EXCLIB_TRACE("Should never get here"); EXCLIB_TRACE("Should never get here");

View File

@@ -10,8 +10,11 @@ int main(void)
{ {
TRY { TRY {
THROW(3, NULL); THROW(3, NULL);
} CLEANUP {
} EXCEPT {
} CATCH(3) { } CATCH(3) {
THROW(3, NULL); THROW(3, NULL);
} FINALLY {
} ETRY; } ETRY;
EXCLIB_TRACE("Should never get here"); EXCLIB_TRACE("Should never get here");

View File

@@ -34,12 +34,16 @@
* TRY { * TRY {
* ... do something here ... * ... do something here ...
* THROW(int, "descriptive message") * THROW(int, "descriptive message")
* } CATCH(int) { * } CLEANUP {
* ... do error handling here ... * ... do any cleanup from your TRY {} block here ...
* } DEFAULT { * } EXCEPT {
* ... Do something with an exception here without caring about its value ... * } CATCH(int) {
* } FINALLY { * ... do error handling here ...
* ... Do something here ... * } DEFAULT {
* ... Do something with an exception here without caring about its value ...
* } FINALLY {
* ... Do something here regardless of which exception occurred, but ONLY if an exception occurred ...
* }
* } ETRY; * } ETRY;
* *
* The syntax is fairly obvious. Code inside the TRY block is executed, and any exceptions are propagated out to the CATCH blocks. * The syntax is fairly obvious. Code inside the TRY block is executed, and any exceptions are propagated out to the CATCH blocks.
@@ -47,10 +51,18 @@
* integer exception. If DEFAULT is not present and there is no CATCH block, then the exception is propagated back up the stack to the * integer exception. If DEFAULT is not present and there is no CATCH block, then the exception is propagated back up the stack to the
* first TRY() block encountered in the program. (Unhandled exceptions behave as in #5,6 in the bullet list above.) * first TRY() block encountered in the program. (Unhandled exceptions behave as in #5,6 in the bullet list above.)
* *
* DO NOT PLACE ANY CODE BETWEEN THE EXCEPT { AND THE FIRST CATCH {. IT WILL NEVER BE EXECUTED.
*
* The CLEANUP block is optional and is executed before any exceptions are processed. Use this to clean up any resources which must be
* handled before the EXCEPT{} block potentially sends control out of the currrent scope, orphaning resources like file handles and
* memory.
*
* The FINALLY clause is executed after the try block has executed, and after any applicable CATCH/DEFAULT blocks. If present, it will * The FINALLY clause is executed after the try block has executed, and after any applicable CATCH/DEFAULT blocks. If present, it will
* be executed REGARDLESS of which exception was actually caught. This is useful to examine an exception as it passes through * be executed REGARDLESS of which exception was actually caught. This is useful to examine an exception as it passes through
* without actually handling/modifying it, or to execute some generic action on exception, regardless of what type, but only after * without actually handling/modifying it, or to execute some generic action on exception, regardless of what type, but only after
* specific exceptions have been handled * specific exceptions have been handled. Beware, however, that FINALLY is executed AFTER CATCH blocks, therefore one of the CATCH blocks
* may have transferred control outside of the TRY {} statement, meaning that the FINALLY {} clause never actually gets executed.
* Cleaning up resources should be done in CLEANUP, not FINALLY.
* *
* THROW_ZERO is a convenience function to replace blocks like this: * THROW_ZERO is a convenience function to replace blocks like this:
* *
@@ -79,7 +91,7 @@
* ... * ...
* } CATCH (EXC_NULLPOINTER) { * } CATCH (EXC_NULLPOINTER) {
* ... * ...
* } * } ETRY;
* *
* This example also highlights one of the problems of this library : You can't check for multiple exceptions on the same block, * This example also highlights one of the problems of this library : You can't check for multiple exceptions on the same block,
* because it's all actually a hidden 'switch' statement. But you can use a mechanism like shown above; when you have multiple * because it's all actually a hidden 'switch' statement. But you can use a mechanism like shown above; when you have multiple
@@ -87,6 +99,14 @@
* does not provide a break in the flow between the previous case and the current one, so fallthrough is achieved. Just make * does not provide a break in the flow between the previous case and the current one, so fallthrough is achieved. Just make
* sure to use a CATCH on any proceeding exceptions that don't need to fall through (like the EXC_NULLPOINTER above). * sure to use a CATCH on any proceeding exceptions that don't need to fall through (like the EXC_NULLPOINTER above).
* *
* You MUST use TRY / EXCEPT / FINALLY / ETRY. This is the minimal form:
*
* TRY {
* } EXCEPT {
* } FINALLY {
* } ETRY;
*
* Without this, the generated code will be syntactically incorrect for the preprocessor.
*/ */
#ifndef EXC_STRBUF_SIZE #ifndef EXC_STRBUF_SIZE
@@ -95,62 +115,69 @@
#ifndef EXC_MAX_FRAMES #ifndef EXC_MAX_FRAMES
#define EXC_MAX_FRAMES 50 #define EXC_MAX_FRAMES 50
#endif // EXC_MAX_FRAMES #endif /* EXC_MAX_FRAMES */
#ifndef EXC_MAX_EXCEPTIONS #ifndef EXC_MAX_EXCEPTIONS
#define EXC_MAX_EXCEPTIONS 4096 #define EXC_MAX_EXCEPTIONS 4096
#endif // EXC_MAX_EXCEPTIONS #endif /* EXC_MAX_EXCEPTIONS */
#define TRY \ #define TRY \
if (__exclib_curidx >= EXC_MAX_FRAMES) \ if (__exclib_curidx >= EXC_MAX_FRAMES) \
exclib_print_exception_stack("No available exception stack context", __FILE__, (char *)__func__, __LINE__); \ exclib_print_exception_stack("No available exception stack context", __FILE__, (char *)__func__, __LINE__); \
if ( exclib_new_exc_frame(&__exclib_statuses[__exclib_curidx++], __FILE__, (char *)__func__, __LINE__) != 0) \ if ( exclib_new_exc_frame(&__exclib_statuses[__exclib_curidx++], __FILE__, (char *)__func__, __LINE__) != 0) \
exclib_print_exception_stack("Tried to TRY but couldn't create new exception frame", __FILE__, (char *)__func__, __LINE__); \ exclib_print_exception_stack("Tried to TRY but couldn't create new exception frame", __FILE__, (char *)__func__, __LINE__); \
EXCLIB_EXCEPTION->value = setjmp(EXCLIB_EXCEPTION->buf); \ EXCLIB_EXCEPTION->setjmpstatus = setjmp(EXCLIB_EXCEPTION->buf); \
EXCLIB_EXCEPTION->tried = 1;\ EXCLIB_EXCEPTION->tried = 1; \
switch( EXCLIB_EXCEPTION->value ) { \
case 0: #define CLEANUP
#define EXCEPT \
if ( EXCLIB_EXCEPTION && EXCLIB_EXCEPTION->setjmpstatus != 0 ) { \
switch( EXCLIB_EXCEPTION->value ) { \
case 0:
#define CATCH(x) \ #define CATCH(x) \
break; \ break; \
case x: \ case x: \
EXCLIB_EXCEPTION->caught = 1; \ EXCLIB_EXCEPTION->caught = 1; \
EXCLIB_EXCEPTION->catching = 1; EXCLIB_EXCEPTION->catching = 1;
#define CATCH_GROUP(x) \ #define CATCH_GROUP(x) \
case x: \ case x: \
EXCLIB_EXCEPTION->caught = 1; \ EXCLIB_EXCEPTION->caught = 1; \
EXCLIB_EXCEPTION->catching = 1; EXCLIB_EXCEPTION->catching = 1;
#define DEFAULT \ #define DEFAULT \
break; \ break; \
default: \ default: \
EXCLIB_EXCEPTION->caught = 1; \ EXCLIB_EXCEPTION->caught = 1; \
EXCLIB_EXCEPTION->catching = 1; EXCLIB_EXCEPTION->catching = 1;
#define FINALLY \
}; \
#define ETRY \ #define ETRY \
}; \ }; \
exclib_clear_exc_frame(); \ exclib_clear_exc_frame(); \
__exclib_curidx--; __exclib_curidx--;
#define FINALLY \
}; \
if ( EXCLIB_EXCEPTION && EXCLIB_EXCEPTION->value ) {
#define THROW_NONZERO(x, y, z) __exclib_rc = (x); if ( __exclib_rc != 0 ) { __exclib_rc += y; THROW(__exclib_rc, z); } #define THROW_NONZERO(x, y, z) if ( (x) != 0 ) { THROW(y, z); }
#define THROW_ZERO(x, y, z) if ( (x) == 0 ) THROW(y, z); #define THROW_ZERO(x, y, z) if ( (x) == 0 ) { THROW(y, z); }
#define THROW(x, y) \ #define THROW(x, y) \
THROW_EXPLICIT(x, y, __FILE__, (char *)__func__, __LINE__, 1); THROW_EXPLICIT(x, y, __FILE__, (char *)__func__, __LINE__, 1)
#define THROW_EXPLICIT(x, y, file, func, line, setflag) \ #define THROW_EXPLICIT(x, y, file, func, line, setflag) \
exclib_prep_throw(x, y, file, func, line, setflag); \ if ( EXCLIB_EXCEPTION && EXCLIB_EXCEPTION->setjmpstatus == 0 ) { \
if ( EXCLIB_EXCEPTION->thrown > 0 ) { \ exclib_prep_throw(x, y, file, func, line, setflag); \
longjmp(EXCLIB_EXCEPTION->buf, x); \ if ( EXCLIB_EXCEPTION->thrown > 0 ) { \
} else { \ longjmp(EXCLIB_EXCEPTION->buf, x); \
sprintf((char *)&__exclib_strbuf, "Uncaught exception %d", x); \ } else { \
exclib_print_exception_stack((char *)&__exclib_strbuf, file, func, line); \ sprintf((char *)&__exclib_strbuf, "Uncaught exception %d", x); \
exit(x); \ exclib_print_exception_stack((char *)&__exclib_strbuf, file, func, line); \
exit(x); \
} \
} }
#define EXCLIB_TRACE(x) exclib_print_exception_stack(x, __FILE__, (char *)__func__, __LINE__) #define EXCLIB_TRACE(x) exclib_print_exception_stack(x, __FILE__, (char *)__func__, __LINE__)
@@ -170,6 +197,7 @@ struct exclib_status {
struct exclib_status *next; struct exclib_status *next;
struct exclib_status *prev; struct exclib_status *prev;
jmp_buf buf; jmp_buf buf;
int setjmpstatus;
int value; int value;
int caught; int caught;
int tried; int tried;
@@ -198,4 +226,4 @@ extern void exclib_print_exception_stack(char *mbuf, char *file, char *func, int
extern int exclib_new_exc_frame(struct exclib_status *es, char *file, char *function, int line); extern int exclib_new_exc_frame(struct exclib_status *es, char *file, char *function, int line);
extern int exclib_clear_exc_frame(); extern int exclib_clear_exc_frame();
#endif // __EXCLIB_H__ #endif /* __EXCLIB_H__ */

View File

@@ -21,7 +21,7 @@ struct exclib_name_data __exclib_exc_names[EXC_PREDEFINED_EXCEPTIONS] = {
void exclib_print_exception_stack(char *mbuf, char *file, char *func, int line) void exclib_print_exception_stack(char *mbuf, char *file, char *func, int line)
{ {
char buf[256]; char buf[512];
char flagbuf[256]; char flagbuf[256];
char *excname = NULL; char *excname = NULL;
struct exclib_status *cur = EXCLIB_EXCEPTION; struct exclib_status *cur = EXCLIB_EXCEPTION;
@@ -72,9 +72,9 @@ void exclib_print_exception_stack(char *mbuf, char *file, char *func, int line)
else else
excname = "NULL"; excname = "NULL";
sprintf((char *)&buf, sprintf((char *)&buf,
"EXCLIB: #%d[0x%x] %s:%d:%s:%s:%d:%s: %s\n", "EXCLIB: #%d[0x%lx] %s:%d:%s:%s:%d:%s: %s\n",
idx, idx,
cur, (unsigned long int)cur,
cur->file, cur->file,
cur->line, cur->line,
cur->function, cur->function,
@@ -93,7 +93,7 @@ void exclib_bulk_name_exceptions(struct exclib_name_data *exclib_exc_names, int
{ {
struct exclib_name_data *ptr; struct exclib_name_data *ptr;
int i = 0; int i = 0;
//THROW_ZERO(exclib_exc_names, EXC_NULLPOINTER, "Null Pointer"); /*THROW_ZERO(exclib_exc_names, EXC_NULLPOINTER, "Null Pointer");*/
ptr = exclib_exc_names; ptr = exclib_exc_names;
for ( i = 0; i < size ; i++) { for ( i = 0; i < size ; i++) {
exclib_name_exception(ptr->exc, ptr->name); exclib_name_exception(ptr->exc, ptr->name);
@@ -113,7 +113,7 @@ void exclib_init()
return; return;
__exclib_inited = 1; __exclib_inited = 1;
memset(&__exclib_statuses, 0x00, sizeof(struct exclib_status) * EXC_MAX_FRAMES); memset(&__exclib_statuses, 0x00, sizeof(struct exclib_status) * EXC_MAX_FRAMES);
// for whatever reason memset isn't safe here, so ... /* for whatever reason memset isn't safe here, so ... */
for ( i = 0 ; i < EXC_MAX_EXCEPTIONS; i++ ) { for ( i = 0 ; i < EXC_MAX_EXCEPTIONS; i++ ) {
__exclib_names[i] = NULL; __exclib_names[i] = NULL;
} }
@@ -123,29 +123,29 @@ void exclib_init()
void exclib_prep_throw(int value, char *msg, char *file, char *func, int line, int setflag) void exclib_prep_throw(int value, char *msg, char *file, char *func, int line, int setflag)
{ {
if ( EXCLIB_EXCEPTION && EXCLIB_EXCEPTION->tried == 1) { if ( EXCLIB_EXCEPTION && EXCLIB_EXCEPTION->tried == 1) {
sprintf((char *)&__exclib_strbuf, "Tried to THROW %d but couldn't create new exception frame", value); sprintf((char *)&__exclib_strbuf, "Tried to THROW %d but couldn't create new exception frame", value);
if ( EXCLIB_EXCEPTION->catching == 1 && EXCLIB_EXCEPTION->prev ) { if ( EXCLIB_EXCEPTION->catching == 1 && EXCLIB_EXCEPTION->prev ) {
if ( exclib_new_exc_frame(EXCLIB_EXCEPTION, file, func, line) ) { if ( exclib_new_exc_frame(EXCLIB_EXCEPTION, file, func, line) ) {
exclib_print_exception_stack((char *)&__exclib_strbuf, file, func, line); exclib_print_exception_stack((char *)&__exclib_strbuf, file, func, line);
exit(value); exit(value);
} }
memcpy(EXCLIB_EXCEPTION->buf, EXCLIB_EXCEPTION->prev->buf, sizeof(jmp_buf)); memcpy(EXCLIB_EXCEPTION->buf, EXCLIB_EXCEPTION->prev->buf, sizeof(jmp_buf));
if ( setflag ) if ( setflag )
EXCLIB_EXCEPTION->thrown = 1; EXCLIB_EXCEPTION->thrown = 1;
} else if ( EXCLIB_EXCEPTION->catching == 1 && (EXCLIB_EXCEPTION->prev == NULL) ) { } else if ( EXCLIB_EXCEPTION->catching == 1 && (EXCLIB_EXCEPTION->prev == NULL) ) {
exclib_clear_exc_frame(); exclib_clear_exc_frame();
} else { } else {
if ( exclib_new_exc_frame(EXCLIB_EXCEPTION, file, func, line) ) if ( exclib_new_exc_frame(EXCLIB_EXCEPTION, file, func, line) )
exclib_print_exception_stack((char *)&__exclib_strbuf, file, func, line); exclib_print_exception_stack((char *)&__exclib_strbuf, file, func, line);
if ( setflag ) if ( setflag )
EXCLIB_EXCEPTION->thrown = 1; EXCLIB_EXCEPTION->thrown = 1;
} }
if ( setflag ) { if ( setflag ) {
EXCLIB_EXCEPTION->value = value; EXCLIB_EXCEPTION->value = value;
EXCLIB_EXCEPTION->name = __exclib_names[value]; EXCLIB_EXCEPTION->name = __exclib_names[value];
EXCLIB_EXCEPTION->description = msg; EXCLIB_EXCEPTION->description = msg;
} }
return; return;
} }
sprintf((char *)&__exclib_strbuf, "Tried to THROW Exception %d but had no exception context. (Called outside of TRY block, or thrown while TRY was setting up?)", value); sprintf((char *)&__exclib_strbuf, "Tried to THROW Exception %d but had no exception context. (Called outside of TRY block, or thrown while TRY was setting up?)", value);
exclib_print_exception_stack((char *)&__exclib_strbuf, file, func, line); exclib_print_exception_stack((char *)&__exclib_strbuf, file, func, line);
@@ -190,14 +190,13 @@ int exclib_clear_exc_frame()
if ( es->prev ) if ( es->prev )
es->prev->next = NULL; es->prev->next = NULL;
if ( es->thrown && !es->caught ) { if ( es->thrown && !es->caught ) {
// thrown exception was unhandled - do we have anywhere else to go? /* thrown exception was unhandled - do we have anywhere else to go? */
if ( !es->prev ) { if ( !es->prev ) {
// No frame above us to propagate this into, stacktrace and kill ourselves /* No frame above us to propagate this into, stacktrace and kill ourselves */
exclib_print_exception_stack("Uncaught exception", es->file, es->function, es->line); exclib_print_exception_stack("Uncaught exception", es->file, es->function, es->line);
exit(es->value); exit(es->value);
//kill(getpid(), SIGKILL);
} else if ( es->tried && es->prev && (es->catching == 0)) { } else if ( es->tried && es->prev && (es->catching == 0)) {
// copy this exception up into the upper frame and siglongjmp back to that /* copy this exception up into the upper frame and siglongjmp back to that */
EXCLIB_EXCEPTION = es->prev; EXCLIB_EXCEPTION = es->prev;
EXCLIB_EXCEPTION->caught = 0; EXCLIB_EXCEPTION->caught = 0;
EXCLIB_EXCEPTION->name = es->name; EXCLIB_EXCEPTION->name = es->name;
@@ -216,5 +215,6 @@ int exclib_clear_exc_frame()
} }
memset((void *)es, 0x00, sizeof(struct exclib_status)); memset((void *)es, 0x00, sizeof(struct exclib_status));
} }
return 0;
} }