Fixture 136
cpp exception unwinding
C++ · 3 functions · 4 lanes · 0 of 12 function-lanes behave identically
4 of 4 lanes have a function that returns a different result after decompilation: clang-O0 (0/3), clang-O2 (0/3), gcc-O0 (0/3), gcc-O2 (0/3).
Throwing runs the personality routine over .eh_frame / .gcc_except_table, selecting a landing pad by the thrown type and running every destructor between throw and catch. None of that control flow appears in the ordinary CFG: the unwind edges live in metadata, and the cleanup calls are only reachable through them.
/* 136_cpp_exception_unwinding.cpp
*
* Throwing runs the personality routine over .eh_frame / .gcc_except_table,
* selecting a landing pad by the thrown type and running every destructor
* between throw and catch. None of that control flow appears in the ordinary
* CFG: the unwind edges live in metadata, and the cleanup calls are only
* reachable through them.
*/
#include <stdint.h>
namespace {
struct Marker {
int32_t *log;
int32_t slot;
int32_t value;
Marker(int32_t *l, int32_t s, int32_t v) : log(l), slot(s), value(v) {}
~Marker() { log[slot] = value; }
};
struct SmallError {
int32_t code;
};
struct LargeError {
int32_t code;
int32_t detail[4];
};
int32_t may_throw(int32_t selector) {
if (selector == 1) {
SmallError error;
error.code = 7;
throw error;
}
if (selector == 2) {
LargeError error;
error.code = 9;
error.detail[0] = 1;
error.detail[1] = 2;
error.detail[2] = 3;
error.detail[3] = 4;
throw error;
}
if (selector == 3) {
throw 42; /* a plain int */
}
return selector * 100;
}
} // namespace
extern "C" int32_t cpp_catch_by_type(int32_t selector) {
try {
return may_throw(selector & 3);
} catch (const SmallError &error) {
return 1000 + error.code;
} catch (const LargeError &error) {
return 2000 + error.code + error.detail[3];
} catch (int value) {
return 3000 + value;
}
}
extern "C" int32_t cpp_destructors_run_while_unwinding(int32_t *log,
int32_t selector) {
if (log == 0) {
return -1;
}
log[0] = 0;
log[1] = 0;
log[2] = 0;
try {
Marker outer(log, 0, 11);
{
Marker inner(log, 1, 22);
may_throw(selector & 3);
log[2] = 33; /* skipped when may_throw actually throws */
}
} catch (...) {
/* Both markers have already been destroyed, innermost first. */
return log[0] * 100 + log[1] * 10 + log[2];
}
return log[0] * 100 + log[1] * 10 + log[2];
}
extern "C" int32_t cpp_rethrow_and_nest(int32_t selector) {
try {
try {
may_throw(selector & 3);
} catch (const SmallError &) {
throw; /* rethrow the in-flight exception */
} catch (int value) {
throw SmallError{value}; /* replace it with a different type */
}
} catch (const SmallError &error) {
return 500 + error.code;
} catch (...) {
return 600;
}
return 0;
} Recovered C
Generated by glaurung decompile --style decbench at b47f6b43.
baseline.json records the result after recompiling the C and calling it beside the
original with seeded inputs.
clang -O0
0/3cpp_catch_by_type fail 14 lines
// glaurung: cpp_catch_by_type @ 0x1170
int32_t cpp_catch_by_type(int32_t arg0) {
extern int _ZN12_GLOBAL__N_19may_throwEi(int);
int value;
int local_2c;
int local_4;
int var2;
// x86-64 prologue: save rbp, frame 48 bytes
var2 = _ZN12_GLOBAL__N_19may_throwEi((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 3))));
local_2c = var2;
local_4 = local_2c;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} cpp_destructors_run_while_unwinding fail 25 lines
// glaurung: cpp_destructors_run_while_unwinding @ 0x1340
struct Marker;
__attribute__((no_stack_protector)) int32_t cpp_destructors_run_while_unwinding(int32_t * arg0, int32_t arg1) {
extern void _ZN12_GLOBAL__N_16MarkerC2EPiii(char *, int *, int, int);
extern void _ZN12_GLOBAL__N_16MarkerD2Ev(struct Marker *);
extern int _ZN12_GLOBAL__N_19may_throwEi(int);
unsigned char local_28[16];
unsigned char local_48[16];
int var6;
// x86-64 prologue: save rbp, frame 80 bytes
if ((arg0 != 0)) {
*(int *)((long)arg0) = 0;
*(int *)(((long)arg0 + 0x4)) = 0;
*(int *)(((long)arg0 + 0x8)) = 0;
_ZN12_GLOBAL__N_16MarkerC2EPiii((char *)(&local_28[0]), (int *)(arg0), 0, 11);
_ZN12_GLOBAL__N_16MarkerC2EPiii((char *)(&local_48[0]), (int *)(arg0), 1, 22);
var6 = _ZN12_GLOBAL__N_19may_throwEi((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 3))));
*(int *)(((long)arg0 + 0x8)) = 33;
((void (*)(char *))_ZN12_GLOBAL__N_16MarkerD2Ev)((char *)(&local_48[0]));
((void (*)(char *))_ZN12_GLOBAL__N_16MarkerD2Ev)((char *)(&local_28[0]));
return (unsigned int)(((unsigned long)((unsigned int)(((*(int *)((long)arg0) * 100) + (*(int *)(((long)arg0 + 0x4)) * 10)))) + *(int *)(((long)arg0 + 0x8))));
} else {
return (unsigned int)(-1);
}
} cpp_rethrow_and_nest fail 33 lines
// glaurung: cpp_rethrow_and_nest @ 0x14d0
__attribute__((no_stack_protector)) int32_t cpp_rethrow_and_nest(int32_t arg0) {
extern int _ZN12_GLOBAL__N_19may_throwEi(int);
extern long __cxa_begin_catch(long);
extern long __cxa_end_catch(void);
int value;
long local_10;
int local_14;
unsigned char local_28[4];
int local_4;
int var2;
long var41;
long var47;
long var49;
long var51;
// x86-64 prologue: save rbp, frame 48 bytes
var2 = _ZN12_GLOBAL__N_19may_throwEi((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 3))));
local_4 = 0;
L_15f7: ;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
if (((unsigned long)((unsigned int)(local_14)) == 3)) {
var41 = __cxa_begin_catch(local_10);
*(long *)(&local_28[0]) = var41;
local_4 = ((unsigned int)(*(int *)(*(char *)(&local_28[0]))) + 500);
var47 = __cxa_end_catch();
goto L_15f7;
}
var49 = __cxa_begin_catch(local_10);
local_4 = 600;
var51 = __cxa_end_catch();
goto L_15f7;
} clang -O2
0/3cpp_catch_by_type fail 15 lines
// glaurung: cpp_catch_by_type @ 0x1160
int32_t cpp_catch_by_type(int32_t arg0) {
extern int _ZN12_GLOBAL__N_19may_throwEi(int);
extern long __cxa_end_catch(void);
int var1;
long var20;
long var3;
var1 = _ZN12_GLOBAL__N_19may_throwEi((unsigned long)((unsigned int)((arg0 & 3))));
var3 = (unsigned long)((unsigned int)(var1));
L_116b: ;
// x86-64 epilogue: tear down frame
return (unsigned int)(var3);
var20 = __cxa_end_catch();
goto L_116b;
} cpp_destructors_run_while_unwinding fail 18 lines
// glaurung: cpp_destructors_run_while_unwinding @ 0x1230
int32_t cpp_destructors_run_while_unwinding(int32_t * arg0, int32_t arg1) {
extern int _ZN12_GLOBAL__N_19may_throwEi(int);
long var1;
int var4;
// x86-64 prologue: save callee registers, frame 24 bytes
if ((arg0 == 0)) {
return 0xffffffff;
} else {
var1 = (long)arg0;
*(long *)(((long)arg0)) = 0;
*(int *)(((long)arg0 + 0x8)) = 0;
var4 = _ZN12_GLOBAL__N_19may_throwEi((unsigned long)((unsigned int)((arg1 & 3))));
*(int *)((var1 + 0x8)) = 33;
*(long *)((var1)) = 0x160000000b;
return 1353;
}
} cpp_rethrow_and_nest fail 30 lines
// glaurung: cpp_rethrow_and_nest @ 0x12b0
int32_t cpp_rethrow_and_nest(int32_t arg0) {
extern int _ZN12_GLOBAL__N_19may_throwEi(int);
extern long __cxa_begin_catch(long);
extern long __cxa_end_catch(void);
int value;
int var11;
long var12;
long var13;
long var16;
long var2;
int var3;
long var5;
long var7;
// x86-64 prologue: save callee registers, frame 40 bytes
var2 = 0;
var3 = _ZN12_GLOBAL__N_19may_throwEi((unsigned long)((unsigned int)((arg0 & 3))));
L_12c1: ;
// x86-64 epilogue: restore callee registers
return (unsigned int)(var2);
var11 = 3;
var12 = __cxa_begin_catch(var7);
var13 = var12;
var2 = 600;
if (((unsigned int)(var5) == (unsigned int)(var11))) {
var2 = (unsigned long)((unsigned int)((500 + *(int *)((var13)))));
}
var16 = __cxa_end_catch();
goto L_12c1;
} gcc -O0
0/3cpp_catch_by_type fail 10 lines
// glaurung: cpp_catch_by_type @ 0x1337
int32_t cpp_catch_by_type(int32_t arg0) {
extern int _ZN12_GLOBAL__N_19may_throwEi(int);
int value;
int var3;
// x86-64 prologue: save rbp, frame 8 bytes
var3 = _ZN12_GLOBAL__N_19may_throwEi((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 3))));
// x86-64 epilogue: restore rbp
return (unsigned int)(var3);
} cpp_destructors_run_while_unwinding fail 60 lines
// glaurung: cpp_destructors_run_while_unwinding @ 0x13f0
struct Marker;
int32_t cpp_destructors_run_while_unwinding(int32_t * arg0, int32_t arg1) {
extern void _ZN12_GLOBAL__N_16MarkerC2EPiii(char *, int *, int, int);
extern void _ZN12_GLOBAL__N_16MarkerD2Ev(const struct Marker *);
extern int _ZN12_GLOBAL__N_19may_throwEi(int);
extern long __cxa_begin_catch(long);
extern long __cxa_end_catch(void);
extern __attribute__((noreturn)) void __stack_chk_fail(void);
long local_18;
unsigned char local_30[16];
unsigned char local_40[16];
long ret;
int var13;
long var14;
long var24;
int var28;
long var36;
long var40;
long var44;
long var51;
int var55;
long var63;
// x86-64 prologue: save rbp, frame 8 bytes
local_18 = (long)(0x28);
if ((arg0 != 0)) {
*(int *)((long)arg0) = 0;
*(int *)((arg0 + 1)) = 0;
*(int *)((arg0 + 2)) = 0;
_ZN12_GLOBAL__N_16MarkerC2EPiii((char *)(&local_40[0]), (int *)(arg0), 0, 11);
_ZN12_GLOBAL__N_16MarkerC2EPiii((char *)(&local_30[0]), (int *)(arg0), 1, 22);
var13 = _ZN12_GLOBAL__N_19may_throwEi((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) & 3))));
var14 = (unsigned long)((unsigned int)(var13));
*(int *)((arg0 + 2)) = 33;
((void (*)(char *))_ZN12_GLOBAL__N_16MarkerD2Ev)((char *)(&local_30[0]));
((void (*)(char *))_ZN12_GLOBAL__N_16MarkerD2Ev)((char *)(&local_40[0]));
var24 = (unsigned long)((unsigned int)(*(int *)((arg0 + 1))));
var28 = ((unsigned int)(((unsigned long)((unsigned int)(var24)) << 2)) + var24);
var36 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)((((unsigned long)((unsigned int)(*(int *)((long)arg0))) * 100) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var28)) + (unsigned long)((unsigned int)(var28)))))))) + (unsigned long)((unsigned int)(*(int *)((arg0 + 2)))))));
} else {
var36 = 0xffffffff;
}
L_14dd: ;
ret = (unsigned long)((unsigned int)(var36));
if ((local_18 == 0x28)) {
// x86-64 epilogue: restore rbp
return ret;
}
__stack_chk_fail();
// __glaurung_eh_landing_14f0
var40 = var14;
((void (*)(char *))_ZN12_GLOBAL__N_16MarkerD2Ev)((char *)(&local_30[0]));
((void (*)(char *))_ZN12_GLOBAL__N_16MarkerD2Ev)((char *)(&local_40[0]));
var44 = __cxa_begin_catch(var40);
var51 = (unsigned long)((unsigned int)(*(int *)((arg0 + 1))));
var55 = ((unsigned int)(((unsigned long)((unsigned int)(var51)) << 2)) + var51);
var36 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)((((unsigned long)((unsigned int)(*(int *)((long)arg0))) * 100) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var55)) + (unsigned long)((unsigned int)(var55)))))))) + (unsigned long)((unsigned int)(*(int *)((arg0 + 2)))))));
var63 = __cxa_end_catch();
goto L_14dd;
} cpp_rethrow_and_nest fail 34 lines
// glaurung: cpp_rethrow_and_nest @ 0x1558
int32_t cpp_rethrow_and_nest(int32_t arg0) {
extern int _ZN12_GLOBAL__N_19may_throwEi(int);
extern long __cxa_begin_catch(long);
extern long __cxa_end_catch(void);
int value;
long local_18;
int var3;
long var33;
long var37;
long var39;
long var4;
long var41;
long var5;
long var8;
// x86-64 prologue: save rbp, frame 8 bytes
var3 = _ZN12_GLOBAL__N_19may_throwEi((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 3))));
var4 = (unsigned long)((unsigned int)(var3));
var5 = 0;
L_157c: ;
// x86-64 epilogue: restore rbp
return (unsigned int)(var5);
if ((var8 == 1)) {
var33 = __cxa_begin_catch(var4);
local_18 = var33;
var5 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)(local_18))) + 500)));
var37 = __cxa_end_catch();
goto L_157c;
}
var39 = __cxa_begin_catch(var4);
var5 = 600;
var41 = __cxa_end_catch();
goto L_157c;
} gcc -O2
0/3cpp_catch_by_type fail 28 lines
// glaurung: cpp_catch_by_type @ 0x13b0
int32_t cpp_catch_by_type(int32_t arg0) {
extern int _ZN12_GLOBAL__N_19may_throwEi(int);
extern long __cxa_begin_catch(void);
extern long __cxa_end_catch(void);
int value;
long ret;
int stack_0;
int var1;
long var12;
long var17;
long var19;
long var24;
var1 = _ZN12_GLOBAL__N_19may_throwEi((unsigned long)((unsigned int)((arg0 & 3))));
ret = (unsigned long)((unsigned int)(var1));
L_13c0: ;
return ret;
var12 = __cxa_begin_catch();
stack_0 = ((unsigned int)(*(int *)((var12))) + 1000);
var17 = __cxa_end_catch();
ret = (unsigned long)((unsigned int)(stack_0));
goto L_13c0;
var19 = __cxa_begin_catch();
stack_0 = (((unsigned int)(*(int *)((var19))) + (unsigned int)(*(int *)((var19 + 0x10)))) + 2000);
var24 = __cxa_end_catch();
ret = (unsigned long)((unsigned int)(stack_0));
goto L_13c0;
} cpp_destructors_run_while_unwinding fail 17 lines
// glaurung: cpp_destructors_run_while_unwinding @ 0x13e0
int32_t cpp_destructors_run_while_unwinding(int32_t * arg0, int32_t arg1) {
extern int _ZN12_GLOBAL__N_19may_throwEi(int);
long var2;
int var3;
if ((arg0 == 0)) {
return 0xffffffff;
}
var2 = (long)arg0;
*(long *)(((long)arg0)) = 0;
*(int *)(((long)arg0 + 0x8)) = 0;
var3 = _ZN12_GLOBAL__N_19may_throwEi((unsigned long)((unsigned int)((arg1 & 3))));
*(int *)((var2 + 0x8)) = 33;
*(long *)((var2)) = 0x160000000b;
// x86-64 epilogue: tear down frame
return 1353;
} cpp_rethrow_and_nest fail 57 lines
// glaurung: cpp_rethrow_and_nest @ 0x1440
int32_t cpp_rethrow_and_nest(int32_t arg0) {
extern int _ZN12_GLOBAL__N_19may_throwEi(int);
extern long __cxa_allocate_exception(int);
extern long __cxa_begin_catch(void);
extern long __cxa_end_catch(void);
extern __attribute__((noreturn)) long __cxa_rethrow(void);
extern __attribute__((noreturn)) long __cxa_throw(long, long, int);
int value;
long ret;
int stack_0;
int var1;
long var10;
long var15;
long var17;
long var19;
long var21;
long var24;
long var27;
long var29;
long var30;
long var33;
long var35;
long var4;
long var8;
var1 = _ZN12_GLOBAL__N_19may_throwEi((unsigned long)((unsigned int)((arg0 & 3))));
ret = 0;
L_1454: ;
// x86-64 epilogue: tear down frame
return ret;
L_1233: ;
if ((var8 != 1)) {
goto L_12a2;
}
var10 = __cxa_begin_catch();
stack_0 = ((unsigned int)(*(int *)((var10))) + 500);
var15 = __cxa_end_catch();
ret = (unsigned long)((unsigned int)(stack_0));
goto L_1454;
var17 = __cxa_begin_catch();
var19 = __cxa_rethrow();
var21 = __cxa_begin_catch();
value = (unsigned long)((unsigned int)(*(int *)((var21))));
var24 = __cxa_allocate_exception(4);
*(int *)((var24)) = value;
var27 = __cxa_throw(var24, 0x3de8, 0);
// __glaurung_eh_landing_1285
var29 = var4;
var30 = __cxa_end_catch();
var8 = var29;
goto L_1233;
L_12a2: ;
var33 = __cxa_begin_catch();
var35 = __cxa_end_catch();
ret = 600;
goto L_1454;
}