Skip to content

Commit fecb031

Browse files
committed
Windows various bug fixes for SEH
1 parent 6389eef commit fecb031

File tree

4 files changed

+102
-63
lines changed

4 files changed

+102
-63
lines changed

include/exception.h

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,11 @@ enum {
201201
const char *const err_file = ((void)err_file, ex_err.file); \
202202
const int err_line = ((void)err_line, ex_err.line)
203203

204+
#define EX_MAKE_IF() \
205+
const char *const err = ((void)err, !is_empty((void *)ex_err.panic) ? ex_err.panic : ex_err.ex); \
206+
const char *const err_file = ((void)err_file, ex_err.file); \
207+
const int err_line = ((void)err_line, ex_err.line)
208+
204209
/* macros
205210
*/
206211
#define EX_EXCEPTION(E) \
@@ -236,12 +241,13 @@ throws an exception of given message. */
236241

237242
#ifdef _WIN32
238243
#define throw(E) raii_panic(EX_STR(E))
239-
240-
#define rethrow() \
241-
if (ex_err.caught > -1) \
242-
ex_err.state = ex_throw_st; \
243-
else \
244-
ex_throw(ex_err.ex, ex_err.file, ex_err.line, ex_err.function, ex_err.panic)
244+
#define rethrow() \
245+
if (ex_err.caught > -1 || ex_err.is_rethrown) { \
246+
ex_err.is_rethrown = false; \
247+
ex_longjmp(ex_err.buf, ex_err.state | ex_throw_st); \
248+
} else { \
249+
ex_throw(ex_err.ex, ex_err.file, ex_err.line, ex_err.function, ex_err.panic); \
250+
}
245251

246252
#define ex_signal_block(ctrl) \
247253
CRITICAL_SECTION ctrl##__FUNCTION__; \
@@ -264,60 +270,58 @@ throws an exception of given message. */
264270
ex_err.stack = 0; \
265271
ex_err.ex = 0; \
266272
ex_err.unstack = 0; \
273+
ex_err.is_rethrown = false; \
267274
/* global context updated */ \
268275
ex_context = &ex_err; \
269276
/* save jump location */ \
270277
ex_err.state = ex_setjmp(ex_err.buf); \
271-
__try \
272-
{ \
273-
if (ex_err.state == ex_try_st) {
274-
275-
#define ex_catch(E) \
276-
} \
277-
} __except(catch_seh(EX_STR(E), GetExceptionCode(), GetExceptionInformation())) { \
278-
if (ex_err.state == ex_throw_st) { \
279-
EX_MAKE(); \
280-
ex_err.state = ex_catch_st;
281-
282-
#define ex_catch_any \
283-
} \
284-
} __except(catch_filter_seh(GetExceptionCode(), GetExceptionInformation())) { \
285-
if (ex_err.state == ex_throw_st) { \
286-
EX_MAKE(); \
287-
ex_err.state = ex_catch_st;
288-
289-
#define ex_catch_if \
290-
} \
291-
} __except(catch_filter_seh(GetExceptionCode(), GetExceptionInformation())) { \
292-
if (ex_err.state == ex_throw_st) { \
293-
EX_MAKE();
294-
295-
#define ex_finally \
296-
} \
278+
if (ex_err.state == ex_try_st) { \
279+
__try {
280+
281+
#define ex_catch(E) \
282+
} __except(catch_seh(EX_STR(E), GetExceptionCode(), GetExceptionInformation())) { \
283+
if (ex_err.state == ex_throw_st) { \
284+
EX_MAKE_IF(); \
285+
ex_err.state = ex_catch_st;
286+
287+
#define ex_finally \
288+
} \
289+
} \
297290
} \
298291
{ \
299-
EX_MAKE(); \
292+
EX_MAKE_IF(); \
300293
/* global context updated */\
301294
ex_context = ex_err.next;
302295

303-
#define ex_finality \
304-
} \
305-
} __finally { \
306-
EX_MAKE(); \
307-
/* global context updated */ \
308-
ex_context = ex_err.next;
309-
310296
#define ex_end_try \
311-
} \
297+
} \
312298
if (ex_context == &ex_err) \
313299
/* global context updated */ \
314300
ex_context = ex_err.next; \
315301
ex_err.caught = -1; \
302+
ex_err.is_rethrown = false; \
316303
if ((ex_err.state & ex_throw_st) != 0) \
317304
rethrow(); \
318-
}
305+
}
306+
307+
#define ex_catch_any \
308+
} __except(catch_filter_seh(GetExceptionCode(), GetExceptionInformation())) { \
309+
if (ex_err.state == ex_throw_st) { \
310+
EX_MAKE_IF(); \
311+
ex_err.state = ex_catch_st;
312+
313+
#define ex_catch_if \
314+
} __except(catch_filter_seh(GetExceptionCode(), GetExceptionInformation())) { \
315+
if (ex_err.state == ex_throw_st) { \
316+
EX_MAKE_IF();
317+
318+
#define ex_finality \
319+
} __finally { \
320+
EX_MAKE_IF(); \
321+
/* global context updated */ \
322+
ex_context = ex_err.next;
319323

320-
#define ex_end_trying ex_end_try }
324+
#define ex_end_trying ex_finally ex_end_try
321325

322326
#else
323327
#define ex_signal_block(ctrl) \
@@ -410,6 +414,8 @@ struct ex_context_s {
410414
void *data;
411415
void *prev;
412416
bool is_unwind;
417+
bool is_rethrown;
418+
bool is_guarded;
413419
int volatile caught;
414420

415421
/* The handler in the stack (which is a FILO container). */

include/raii.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ C_API void *malloc_arena(size_t size);
235235
C_API void *calloc_arena(int count, size_t size);
236236

237237
C_API values_type *raii_value(void *);
238+
C_API void raii_setup(void);
238239
C_API raii_type type_of(void *);
239240
C_API bool is_type(void *, raii_type);
240241
C_API bool is_instance_of(void *, void *);
@@ -273,9 +274,9 @@ execution begins when current `guard` scope exits or panic/throw. */
273274
#define _recover(err) raii_is_caught(raii_init()->arena, err)
274275

275276
/* Compare `err` to scoped error condition, will mark exception handled, if `true`. */
276-
#define _is_caught(err) raii_is_caught(raii_init()->arena, err)
277+
#define _is_caught(err) raii_is_caught(raii_init()->arena, EX_STR(err))
277278

278-
/* Compare `err` to scoped error condition, will mark exception handled, if `true`. */
279+
/* Get scoped error condition string. */
279280
#define _get_message() raii_message_by(raii_init()->arena)
280281
#define _panic raii_panic
281282

@@ -323,8 +324,6 @@ return given `result` when done, use `NONE` for no return. */
323324
} ex_catch_if { \
324325
if ((is_type(&(_$##__FUNCTION__)->defer, RAII_DEF_ARR))) \
325326
raii_deferred_free(_$##__FUNCTION__); \
326-
if ((_$##__FUNCTION__)->is_recovered) \
327-
ex_err.state = ex_catch_st; \
328327
} ex_finally { \
329328
guard_reset(s##__FUNCTION__, sf##__FUNCTION__, uf##__FUNCTION__); \
330329
guard_delete(_$##__FUNCTION__); \
@@ -342,8 +341,6 @@ On exit will begin executing deferred functions.
342341
} ex_catch_if { \
343342
if ((is_type(&(_$##__FUNCTION__)->defer, RAII_DEF_ARR))) \
344343
raii_deferred_free(_$##__FUNCTION__); \
345-
if ((_$##__FUNCTION__)->is_recovered) \
346-
ex_err.state = ex_catch_st; \
347344
} ex_finally { \
348345
guard_reset(s##__FUNCTION__, sf##__FUNCTION__, uf##__FUNCTION__); \
349346
guard_delete(_$##__FUNCTION__); \
@@ -367,6 +364,7 @@ On exit will begin executing deferred functions.
367364
#define catch(e) ex_catch(e)
368365
#define end_try ex_end_try
369366
#define finally ex_finally
367+
#define caught(err) raii_caught(EX_STR(err))
370368

371369
#ifdef _WIN32
372370
#define finality ex_finality

src/exception.c

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ static void ex_print(ex_context_t *exception, const char *message) {
162162
fprintf(stderr, "\n%s: %s\n", message, (exception->panic != NULL ? exception->panic : exception->ex));
163163
if (exception->file != NULL) {
164164
if (exception->function != NULL) {
165-
fprintf(stderr, " thrown at %s (%s:%d)\n\n", exception->function, exception->file, exception->line);
165+
fprintf(stderr, " thrown in %s at (%s:%d)\n\n", exception->function, exception->file, exception->line);
166166
} else {
167167
fprintf(stderr, " thrown at %s:%d\n\n", exception->file, exception->line);
168168
}
@@ -204,6 +204,8 @@ ex_context_t *ex_init(void) {
204204
ex_signal_block(all);
205205
ex_context = &ex_context_buffer;
206206
ex_context->is_unwind = false;
207+
ex_context->is_rethrown = false;
208+
ex_context->is_guarded = false;
207209
ex_context->caught = -1;
208210
ex_context->type = ex_context_st;
209211
ex_signal_unblock(all);
@@ -260,7 +262,7 @@ void ex_throw(const char *exception, const char *file, int line, const char *fun
260262
ex_terminate();
261263

262264
#ifdef _WIN32
263-
RaiseException(EXCEPTION_PANIC, 0, 0, 0);
265+
RaiseException(EXCEPTION_PANIC, 0, 0, NULL);
264266
#endif
265267
ex_longjmp(ctx->buf, ctx->state | ex_throw_st);
266268
}
@@ -271,19 +273,25 @@ int catch_seh(const char *exception, DWORD code, struct _EXCEPTION_POINTERS *ep)
271273
const char *ex = 0;
272274
int i;
273275

276+
if (!is_str_eq(ctx->panic, exception))
277+
return EXCEPTION_EXECUTE_HANDLER;
278+
274279
for (i = 0; i < max_ex_sig; i++) {
275-
if (is_str_eq(ex_sig[i].ex, exception)
280+
if (ex_sig[i].seh == code
281+
|| ctx->caught == ex_sig[i].seh
276282
|| is_str_eq(ctx->panic, exception)
277-
|| ex_sig[i].seh == code
278-
|| ctx->caught == ex_sig[i].seh) {
283+
) {
279284
ctx->state = ex_throw_st;
280-
ctx->ex = ex_sig[i].ex;
281-
ctx->file = "unknown";
282-
ctx->line = 0;
283-
ctx->function = NULL;
285+
ctx->is_rethrown = true;
286+
if (got_signal) {
287+
ctx->ex = ex_sig[i].ex;
288+
ctx->file = "unknown";
289+
ctx->line = 0;
290+
ctx->function = NULL;
291+
}
284292

285293
if (exception_setup_func)
286-
exception_setup_func(ctx, ctx->ex, NULL);
294+
exception_setup_func(ctx, ctx->ex, ctx->panic);
287295
return EXCEPTION_EXECUTE_HANDLER;
288296
}
289297
}
@@ -304,13 +312,18 @@ int catch_filter_seh(DWORD code, struct _EXCEPTION_POINTERS *ep) {
304312
for (i = 0; i < max_ex_sig; i++) {
305313
if (ex_sig[i].seh == code || ctx->caught == ex_sig[i].seh) {
306314
ctx->state = ex_throw_st;
315+
ctx->is_rethrown = true;
307316
ctx->ex = ex_sig[i].ex;
317+
ctx->panic = NULL;
308318
ctx->file = "unknown";
309319
ctx->line = 0;
310320
ctx->function = NULL;
311321

312322
if (exception_setup_func)
313-
exception_setup_func(ctx, ctx->ex, NULL);
323+
exception_setup_func(ctx, ctx->ex, ctx->panic);
324+
325+
if (!ctx->is_guarded)
326+
ex_unwind_stack(ctx);
314327
return EXCEPTION_EXECUTE_HANDLER;
315328
}
316329
}

src/raii.c

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,12 +417,18 @@ RAII_INLINE void raii_recover_by(memory_t *scope, func_t func, void *data) {
417417
bool raii_caught(const char *err) {
418418
memory_t *scope = raii_init();
419419
const char *exception = (const char *)(!is_empty((void *)scope->panic) ? scope->panic : scope->err);
420-
return scope->is_recovered = is_str_eq(err, exception);
420+
if (scope->is_recovered = is_str_eq(err, exception))
421+
ex_init()->state = ex_catch_st;
422+
423+
return scope->is_recovered;
421424
}
422425

423426
bool raii_is_caught(unique_t *scope, const char *err) {
424427
const char *exception = (const char *)(!is_empty((void *)scope->panic) ? scope->panic : scope->err);
425-
return scope->is_recovered = is_str_eq(err, exception);
428+
if (scope->is_recovered = is_str_eq(err, exception))
429+
ex_init()->state = ex_catch_st;
430+
431+
return scope->is_recovered;
426432
}
427433

428434
const char *raii_message(void) {
@@ -446,13 +452,15 @@ void guard_set(ex_context_t *ctx, const char *ex, const char *message) {
446452
memory_t *scope = raii_init()->arena;
447453
scope->err = (void *)ex;
448454
scope->panic = message;
455+
ctx->is_guarded = true;
449456
ex_swap_set(ctx, (void *)scope);
450457
ex_unwind_set(ctx, scope->is_protected);
451458
}
452459

453460
void guard_reset(void *scope, ex_setup_func set, ex_unwind_func unwind) {
454461
raii_init()->arena = scope;
455462
ex_swap_reset(ex_init());
463+
ex_init()->is_guarded = false;
456464
exception_setup_func = set;
457465
exception_unwind_func = unwind;
458466
}
@@ -470,7 +478,21 @@ values_type *raii_value(void *data) {
470478
return ((raii_values_t *)data)->value;
471479

472480
RAII_LOG("attempt to get value on null");
473-
return ((raii_values_t *)0)->value;
481+
return;
482+
}
483+
484+
static void raii_unwind_set(ex_context_t *ctx, const char *ex, const char *message) {
485+
memory_t *scope = raii_init();
486+
scope->err = (void *)ex;
487+
scope->panic = message;
488+
ex_swap_set(ctx, (void *)scope);
489+
ex_unwind_set(ctx, scope->is_protected);
490+
}
491+
492+
void raii_setup(void) {
493+
exception_unwind_func = (ex_unwind_func)raii_deferred_free;
494+
exception_setup_func = raii_unwind_set;
495+
ex_signal_setup();
474496
}
475497

476498
int strpos(const char *text, char *pattern) {

0 commit comments

Comments
 (0)