From 673e411c86c6d9903c71f4eba1b54b69a22b2fa6 Mon Sep 17 00:00:00 2001 From: overflowerror <mail@overflowerror.com> Date: Fri, 10 Mar 2017 18:43:56 +0100 Subject: [PATCH] we now have a stackstrace \o/ --- try/Makefile | 13 ++++++--- try/example.c | 54 ++++++++---------------------------- try/exceptions/exceptions.c | 22 +++++++++++++++ try/exceptions/exceptions.h | 32 +++++++++++++++++++++ try/try.c | 55 ++++++++++++++++++++++++++++++++++--- try/try.h | 29 +++++++++++++++---- 6 files changed, 149 insertions(+), 56 deletions(-) create mode 100644 try/exceptions/exceptions.c create mode 100644 try/exceptions/exceptions.h diff --git a/try/Makefile b/try/Makefile index 1ece937..63fc375 100644 --- a/try/Makefile +++ b/try/Makefile @@ -5,9 +5,9 @@ # CC = gcc -DEFS = -D_XOPEN_SOURCE=500 -D_BSD_SOURCE +DEFS = -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -B "../oop/" CFLAGS = -Wall -Wextra -g -std=c99 -DENDEBUG $(DEFS) -fPIC -LDFLAGS = $(DEFS) +LDFLAGS = $(DEFS) -rdynamic LIBFLAGS = -shared $(DEFS) .PHONY: all clean @@ -17,14 +17,19 @@ all: example libtry.so %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< -example: example.o try.o +example: example.o try.o exceptions/exceptions.o ../oop/liboop.so $(CC) $(LDFLAGS) -o $@ $^ -libtry.so: try.o +libtry.so: try.o exceptions/exceptions.o ../oop/liboop.so $(CC) $(LIBFLAGS) -o $@ $^ try.o: try.c try.h example.o: example.c try.h +exceptions/exceptions.o: exceptions/exceptions.c exceptions/exceptions.h + +../oop/liboop.so: + cd ../oop/ && $(MAKE) liboop.so clean: rm -f *.o example libtry.so + cd ../oop/ && $(MAKE) clean diff --git a/try/example.c b/try/example.c index cb7ddc2..39794cc 100644 --- a/try/example.c +++ b/try/example.c @@ -1,54 +1,24 @@ #include "try.h" +#include "../oop/oop.h" +#include "exceptions/exceptions.h" + #include <stdio.h> -void function_with_throw(const char* e) { - subtry(); - - throw(e); +void function(void) { throws(exception_class) + + throw(new exception("This is an uncaught exception.")); } int main(void) { - // simple try-catch try { - throw("Hello World 1"); - } catch(const char* e) { - printf("Catch 1: %s\n", e); - } endtry; - - // try-catch from function - try { - trycall function_with_throw("Hello World 2"); - } catch(const char* e) { - printf("Catch 2: %s\n", e); - } endtry; - - // nested try-catch - try { - const char* string; - - try { - throw("Hello World 3"); - } catch(const char* e) { - string = e; - } endtry; - - throw(string); - } catch(const char* e) { - printf("Catch 3: %s\n", e); - } endtry; - - // nested try-catch with throw in catch-clause - try { - tpush(); - try { - throw("Hello World 4"); - } catch(const char* e) { - cthrow(e); - } endtry; - } catch(const char* e) { - printf("Catch 4: %s\n", e); + throw(new exception("This is a caught exception.")); + } catch(exception_class, exception_t* e) { + printf("Caught: %s\n", e->msg); + e->destruct(e); } endtry; + + function(); return 0; } diff --git a/try/exceptions/exceptions.c b/try/exceptions/exceptions.c new file mode 100644 index 0000000..8c8ad2b --- /dev/null +++ b/try/exceptions/exceptions.c @@ -0,0 +1,22 @@ +#include "exceptions.h" + +#include <stdlib.h> + +void method(exception, destruct)(exception_t* this) { + this->super.destruct((object_t*) this); +} + +void method(exception, populate)(exception_t* obj, class_t c) { + populate(object)((object_t*) obj, c); + + add_method(obj, exception, destruct); +} + +exception_t* method(exception, construct)(const char* msg) { + exception_t* obj = malloc(sizeof(exception_t)); + populate(exception)(obj, exception_class); + + obj->msg = msg; + + return obj; +} diff --git a/try/exceptions/exceptions.h b/try/exceptions/exceptions.h new file mode 100644 index 0000000..eea064d --- /dev/null +++ b/try/exceptions/exceptions.h @@ -0,0 +1,32 @@ +#ifndef EXCEPTIONS_H +#define EXCEPTIONS_H + +#include "../../oop/oop.h" + +#define exception construct(exception) +class_t exception_class; +class(exception, exception_class, object_class, true) { + extends(object_t); + + const char* msg; + + void (*destruct)(defclass exception*); +} exception_t; + +void method(exception, populate)(exception_t*); +exception_t* method(exception, construct)(const char*); + +#define exception construct(exception) +class_t exception_class; +class(exception, exception_class, object_class, true) { + extends(object_t); + + const char* msg; + + void (*destruct)(defclass exception*); +} exception_t; + +void method(exception, populate)(exception_t*); +exception_t* method(exception, construct)(const char*); + +#endif diff --git a/try/try.c b/try/try.c index 0b9238f..ff7a91c 100644 --- a/try/try.c +++ b/try/try.c @@ -1,6 +1,11 @@ #include "try.h" +#include "exceptions/exceptions.h" #include <stdlib.h> +#include <stdio.h> +#include <execinfo.h> +#include <string.h> +#include <errno.h> struct tryc { bool used; @@ -43,11 +48,15 @@ void* try_catch(try_t id) { void try_remove(try_t id) { - trys[id].used = false; - trynr--; + if (trys[id].used) { + trys[id].used = false; + trynr--; + } } try_t try_pop(void) { + if (stack_position < 0) + return NO_TRY_BODY; return stack[stack_position--]; } @@ -55,6 +64,44 @@ void try_push(try_t id) { stack[++stack_position] = id; } -void try_throw(try_t id, void* exception) { - trys[id].exception = exception; +#define BACKTRACE_BUFFER_SIZE 16 +#define EXIT_BACKTRACE_FAILED 3 +#define EXIT_UNCAUGHT 4 +void print_backtrace(FILE* file) { + void* buffer[BACKTRACE_BUFFER_SIZE]; + char** strings; + int entries = backtrace(buffer, BACKTRACE_BUFFER_SIZE); + strings = backtrace_symbols(buffer, entries); + + if (strings == NULL) { + fprintf(file, " Error while backtracing: %s\n", strerror(errno)); + exit(EXIT_BACKTRACE_FAILED); + } + + int tmp = (entries < BACKTRACE_BUFFER_SIZE) ? entries : entries - 1; + + // from 2, because of print_backtrace and try_throw + for (int i = 2; i < tmp; i++) { + fprintf(file, " at %s\n", strings[i]); + } + if (tmp < entries) { + fprintf(file, " ...\n"); + } + exit(EXIT_UNCAUGHT); +} + +void try_throw(try_t id, void* exception) { + if (id == NO_TRY_BODY) { + exception_t* e = exception; + fprintf(stderr, "\nUncaught exception '%s_t' (\"%s\")\n", + oop_get_class_name(oop_get_class_from_obj((void*) e)), + e->msg); + print_backtrace(stderr); + } else { + trys[id].exception = exception; + } +} + +void try_reset(try_t id) { + trys[id].exception = NULL; } diff --git a/try/try.h b/try/try.h index 5d211a2..c818d76 100644 --- a/try/try.h +++ b/try/try.h @@ -3,17 +3,33 @@ #include <stdbool.h> +#include "../oop/oop.h" +#include "../misc/unused.h" + typedef int try_t; -#define try do { try_t _try_id = try_new(); void _try_f(void) -#define catch(e) ; _try_f(); if (try_has_catch(_try_id)) { e = try_catch(_try_id); try_remove(_try_id); do -#define endtry while(false); } } while(false); -#define throw(e) try_throw(_try_id, (void*) e); return; +#define throws(...) subtry(); + +#define try { bool _try_catch = false, _try_body = false; void* _try_data = NULL; try_t _try_id = try_new(); void _try_f(void) +#define pcatch(e) ; _try_f(); if (try_has_catch(_try_id)) { e = try_catch(_try_id); try_remove(_try_id); do + +#define catch(c, ex) ; if (!_try_body) { _try_f(); _try_body = true; _try_data = try_catch(_try_id); _try_catch = try_has_catch(_try_id); try_remove(_try_id); } if (_try_catch && instanceof(_try_data, c)) { _try_catch = false; ex = _try_data; do + +#define endtry while(false); } if (_try_catch) { UNUSED(_try_body); UNUSED(_try_data); }}; +#define throw(e) { try_throw(_try_id, (void*) e); return; } + +#define until(condition) ; do { try_reset(_try_id); _try_f(); } while(try_has_catch(_try_id) == condition); void* _try_result = try_catch(_try_id); try_remove(_try_id); if(true) { do +#define get_thrown() (_try_result) +#define failed false +#define succeeded true + #define subtry() try_t _try_id = try_pop(); -#define tpush() try_push(_try_id) -#define cthrow(e) _try_id = try_pop(); throw(e); #define trycall try_push(_try_id); +#define tpush() try_push(_try_id) +#define cthrow(e) _try_id = try_pop(); throw(e); + +#define NO_TRY_BODY -1 try_t try_new(void); bool try_has_catch(try_t); @@ -22,5 +38,6 @@ void try_remove(try_t); void try_throw(try_t, void*); try_t try_pop(void); void try_push(try_t); +void try_reset(try_t); #endif