Fixture 135

cpp rtti

C++ · 4 functions · 4 lanes · 0 of 14 function-lanes behave identically

4 of 4 lanes have a function that returns a different result after decompilation: clang-O0 (0/4), clang-O2 (0/3), gcc-O0 (0/4), gcc-O2 (0/3).

RTTI: dynamic_cast consults a type_info record reachable from the vtable and walks the inheritance graph at runtime, returning null on failure. typeid compares those records. Neither is expressible as a static offset, so both are real calls into the runtime (__dynamic_cast) that a decompiler must not fold into a constant.

tests/decompiler_fixtures/src/135_cpp_rtti.cpp source
/* 135_cpp_rtti.cpp
 *
 * RTTI: `dynamic_cast` consults a type_info record reachable from the vtable and
 * walks the inheritance graph at runtime, returning null on failure. `typeid`
 * compares those records. Neither is expressible as a static offset, so both are
 * real calls into the runtime (__dynamic_cast) that a decompiler must not fold
 * into a constant.
 */
#include <stdint.h>
#include <typeinfo>

namespace {

class Animal {
public:
    virtual ~Animal() {}
    virtual int32_t sound() const { return 0; }
};

class Dog : public Animal {
public:
    int32_t sound() const override { return 1; }
    virtual int32_t fetch() const { return 10; }
};

class Cat : public Animal {
public:
    int32_t sound() const override { return 2; }
};

class Puppy : public Dog {
public:
    int32_t sound() const override { return 3; }
    int32_t fetch() const override { return 11; }
};

}  // namespace

extern "C" int32_t cpp_dynamic_cast_succeeds(int32_t which) {
    Puppy puppy;
    Cat cat;
    Animal *animal = (which & 1) ? static_cast<Animal *>(&puppy)
                                 : static_cast<Animal *>(&cat);
    /* Succeeds only for the Dog lineage; null otherwise. */
    Dog *dog = dynamic_cast<Dog *>(animal);
    return (dog != 0) ? dog->fetch() : -1;
}

extern "C" int32_t cpp_dynamic_cast_fails(int32_t which) {
    Dog dog;
    Cat cat;
    Animal *animal = (which & 1) ? static_cast<Animal *>(&dog)
                                 : static_cast<Animal *>(&cat);
    Puppy *puppy = dynamic_cast<Puppy *>(animal);
    return (puppy != 0) ? 1 : 0;
}

extern "C" int32_t cpp_typeid_compare(int32_t which) {
    Dog dog;
    Puppy puppy;
    Cat cat;
    const Animal *left;
    const Animal *right;
    switch (which & 3) {
    case 0: left = &dog; right = &dog; break;
    case 1: left = &dog; right = &puppy; break;
    case 2: left = &puppy; right = &puppy; break;
    default: left = &dog; right = &cat; break;
    }
    return (typeid(*left) == typeid(*right)) ? 1 : 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/4
_ZNKSt9type_infoeqERKS_ structural 37 lines
// glaurung: _ZNKSt9type_infoeqERKS_ @ 0x1730
typedef struct type_info type_info;
bool _ZNKSt9type_infoeqERKS_(const type_info * arg0, long * arg1) {
    extern int strcmp(const char *, const char *);
    signed char local_11;
    signed char local_21;
    long t11;
    long t145;
    long var1;
    int var11;
    int var16;
    long var6;
    long var8;
    // x86-64 prologue: save rbp, frame 48 bytes
    var1 = *(long *)(((long)arg0 + 0x8));
    t11 = *(long *)(((long)arg1 + 0x8));
    local_11 = 1;
    if ((var1 == t11)) {
        var6 = ((unsigned long)((unsigned char)(local_11)) & 255);
        t145 = (var6 & 1);
        var8 = (t145 & 255);
        // x86-64 epilogue: restore rbp
        return ((unsigned char)((unsigned int)((unsigned char)((var8 & 255)))) != 0);
    }
    var11 = (int)((signed char)(*(char *)(*(long *)(((long)arg0 + 0x8)))));
    local_21 = 0;
    if (((unsigned long)((unsigned int)(var11)) != 42)) {
        var16 = strcmp((const char *)(*(long *)(((long)arg0 + 0x8))), (const char *)(*(long *)(((long)arg1 + 0x8))));
        local_21 = ((unsigned long)((unsigned int)(var16)) == 0);
    }
    local_11 = local_21;
    var6 = ((unsigned long)((unsigned char)(local_11)) & 255);
    t145 = (var6 & 1);
    var8 = (t145 & 255);
    // x86-64 epilogue: restore rbp
    return ((unsigned char)((unsigned int)((unsigned char)((var8 & 255)))) != 0);
}
cpp_dynamic_cast_fails fail 41 lines
// glaurung: cpp_dynamic_cast_fails @ 0x1340
typedef struct Animal Animal;
typedef struct Puppy Puppy;
struct Cat;
struct Dog;
__attribute__((no_stack_protector)) int32_t cpp_dynamic_cast_fails(int32_t arg0) {
    extern void _ZN12_GLOBAL__N_13CatC2Ev(struct Cat *);
    extern void _ZN12_GLOBAL__N_13CatD2Ev(struct Cat *);
    extern void _ZN12_GLOBAL__N_13DogC2Ev(struct Dog *);
    extern void _ZN12_GLOBAL__N_13DogD2Ev(struct Dog *);
    extern long __dynamic_cast(long, long, long, int);
    unsigned char animal[8];
    unsigned char puppy[8];
    unsigned char local_10[8];
    unsigned char local_18[8];
    void * local_30;
    long local_38;
    long local_40;
    int local_44;
    long var13;
    long var6;
    // x86-64 prologue: save rbp, frame 80 bytes
    ((void (*)(char *))_ZN12_GLOBAL__N_13DogC2Ev)((char *)(&local_10[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_13CatC2Ev)((char *)(&local_18[0]));
    local_30 = (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 1))) == 0) ? &local_18[0] : &local_10[0]);
    *(long *)(&animal[0]) = (long)((long)local_30);
    var6 = *(long *)(&animal[0]);
    local_38 = var6;
    if ((var6 == 0)) {
        local_40 = 0;
    } else {
        var13 = __dynamic_cast(local_38, 0x3ce8, 0x3d10, 0);
        local_40 = var13;
    }
    *(long *)(&puppy[0]) = local_40;
    local_44 = ((*(long *)(&puppy[0]) != 0) ? 1 : 0);
    ((void (*)(char *))_ZN12_GLOBAL__N_13CatD2Ev)((char *)(&local_18[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_13DogD2Ev)((char *)(&local_10[0]));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_44);
}
cpp_dynamic_cast_succeeds fail 51 lines
// glaurung: cpp_dynamic_cast_succeeds @ 0x1160
typedef struct Animal Animal;
typedef struct Dog Dog;
struct Cat;
struct Puppy;
__attribute__((no_stack_protector)) int32_t cpp_dynamic_cast_succeeds(int32_t arg0) {
    extern void _ZN12_GLOBAL__N_13CatC2Ev(struct Cat *);
    extern void _ZN12_GLOBAL__N_13CatD2Ev(struct Cat *);
    extern void _ZN12_GLOBAL__N_15PuppyC2Ev(struct Puppy *);
    extern void _ZN12_GLOBAL__N_15PuppyD2Ev(struct Puppy *);
    extern long __dynamic_cast(long, long, long, int);
    unsigned char animal[8];
    unsigned char dog[8];
    unsigned char local_10[8];
    unsigned char local_18[8];
    void * local_40;
    long local_48;
    long local_50;
    int local_54;
    int local_58;
    int local_5c;
    long var26;
    long var6;
    long var9;
    // x86-64 prologue: save rbp, frame 96 bytes
    ((void (*)(char *))_ZN12_GLOBAL__N_15PuppyC2Ev)((char *)(&local_10[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_13CatC2Ev)((char *)(&local_18[0]));
    local_40 = (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 1))) != 0) ? &local_10[0] : &local_18[0]);
    *(long *)(&animal[0]) = (long)((long)local_40);
    var6 = *(long *)(&animal[0]);
    local_48 = var6;
    if ((var6 != 0)) {
        var9 = __dynamic_cast(local_48, 0x3ce8, 0x3cf8, 0);
        local_50 = var9;
    } else {
        local_50 = 0;
    }
    *(long *)(&dog[0]) = local_50;
    if ((*(long *)(&dog[0]) == 0)) {
        local_58 = 0xffffffff;
    } else {
        var26 = ((long (*)(void))(*(long *)((*(long *)(*(long *)(&dog[0])) + 24))))();
        local_54 = var26;
        local_58 = local_54;
    }
    local_5c = local_58;
    ((void (*)(char *))_ZN12_GLOBAL__N_13CatD2Ev)((char *)(&local_18[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_15PuppyD2Ev)((char *)(&local_10[0]));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_5c);
}
cpp_typeid_compare fail 99 lines
// glaurung: cpp_typeid_compare @ 0x1470
typedef struct Animal Animal;
struct Cat;
struct Dog;
struct Puppy;
__attribute__((no_stack_protector)) int32_t cpp_typeid_compare(int32_t arg0) {
    extern void _ZN12_GLOBAL__N_13CatC2Ev(struct Cat *);
    extern void _ZN12_GLOBAL__N_13CatD2Ev(struct Cat *);
    extern void _ZN12_GLOBAL__N_13DogC2Ev(struct Dog *);
    extern void _ZN12_GLOBAL__N_13DogD2Ev(struct Dog *);
    extern void _ZN12_GLOBAL__N_15PuppyC2Ev(struct Puppy *);
    extern void _ZN12_GLOBAL__N_15PuppyD2Ev(struct Puppy *);
    extern int _ZNKSt9type_infoeqERKS_(char *, long *);
    extern long __cxa_bad_typeid(void);
    unsigned char left[8];
    unsigned char right[8];
    unsigned char local_10[8];
    unsigned char local_18[8];
    unsigned char local_20[8];
    int local_40;
    long local_48;
    long local_50;
    long local_58;
    int local_5c;
    long t159;
    long t76;
    int var1;
    long var17;
    long var18;
    long var23;
    long var25;
    int var26;
    long var28;
    long var29;
    long var30;
    long var34;
    long var35;
    int var37;
    // x86-64 prologue: save rbp, frame 96 bytes
    ((void (*)(char *))_ZN12_GLOBAL__N_13DogC2Ev)((char *)(&local_10[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_15PuppyC2Ev)((char *)(&local_18[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_13CatC2Ev)((char *)(&local_20[0]));
    var1 = ((unsigned int)(arg0) & 3);
    local_40 = var1;
    if (((unsigned long)((unsigned int)(var1)) == 0)) {
        *(long *)(&left[0]) = (long)((long)(&local_10[0]));
        *(long *)(&right[0]) = (long)((long)(&local_10[0]));
    } else {
        if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_40)) - 1))) == 0)) {
            *(long *)(&left[0]) = (long)((long)(&local_10[0]));
            *(long *)(&right[0]) = (long)((long)(&local_18[0]));
        } else {
            if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_40)) - 2))) == 0)) {
                *(long *)(&left[0]) = (long)((long)(&local_18[0]));
                *(long *)(&right[0]) = (long)((long)(&local_18[0]));
            } else {
                *(long *)(&left[0]) = (long)((long)(&local_10[0]));
                *(long *)(&right[0]) = (long)((long)(&local_20[0]));
            }
        }
    }
    var17 = *(long *)(&left[0]);
    local_48 = var17;
    if ((var17 == 0)) {
        var18 = __cxa_bad_typeid();
    }
    local_58 = *(long *)((*(long *)(local_48) - 8));
    var23 = *(long *)(&right[0]);
    local_50 = var23;
    if ((var23 != 0)) {
        var25 = *(long *)(local_50);
        var26 = _ZNKSt9type_infoeqERKS_((char *)(local_58), (long *)(*(long *)((var25 - 0x8))));
        t76 = ((unsigned long)((unsigned int)(var26)) & 255);
        var28 = (var29 & -256);
        var30 = (var28 | (t76 & 255));
        t159 = (var30 & 1);
        var34 = (((unsigned long)((unsigned char)(t159)) != 0) ? 1 : 0);
        local_5c = var34;
        ((void (*)(char *))_ZN12_GLOBAL__N_13CatD2Ev)((char *)(&local_20[0]));
        ((void (*)(char *))_ZN12_GLOBAL__N_15PuppyD2Ev)((char *)(&local_18[0]));
        ((void (*)(char *))_ZN12_GLOBAL__N_13DogD2Ev)((char *)(&local_10[0]));
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_5c);
    }
    var35 = __cxa_bad_typeid();
    var25 = *(long *)(local_50);
    var37 = _ZNKSt9type_infoeqERKS_((char *)(local_58), (long *)(*(long *)((var25 - 0x8))));
    t76 = ((unsigned long)((unsigned int)(var37)) & 255);
    var28 = (var29 & -256);
    var30 = (var28 | (t76 & 255));
    t159 = (var30 & 1);
    var34 = (((unsigned long)((unsigned char)(t159)) != 0) ? 1 : 0);
    local_5c = var34;
    ((void (*)(char *))_ZN12_GLOBAL__N_13CatD2Ev)((char *)(&local_20[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_15PuppyD2Ev)((char *)(&local_18[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_13DogD2Ev)((char *)(&local_10[0]));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_5c);
}

clang -O2

0/3
cpp_dynamic_cast_fails fail 17 lines
// glaurung: cpp_dynamic_cast_fails @ 0x1190
typedef struct Animal Animal;
typedef struct Puppy Puppy;
__attribute__((no_stack_protector)) int32_t cpp_dynamic_cast_fails(int32_t arg0) {
    extern long __dynamic_cast(long, long, long, int);
    Animal * animal;
    Puppy * puppy;
    unsigned char local_10[16];
    long rsp;
    long var5;
    rsp = (rsp - 24);
    *(long *)((&local_10[0] + 8)) = 0x3d90;
    *(long *)(&local_10[0]) = 0x3dc0;
    var5 = __dynamic_cast((((unsigned long)((unsigned char)((arg0 & 1))) == 0) ? (long)(&local_10[0]) : (long)((rsp + 16))), 0x3d10, 0x3d38, 0);
    // x86-64 epilogue: tear down frame
    return (var5 != 0);
}
cpp_dynamic_cast_succeeds fail 23 lines
// glaurung: cpp_dynamic_cast_succeeds @ 0x1130
typedef struct Animal Animal;
typedef struct Dog Dog;
__attribute__((no_stack_protector)) int32_t cpp_dynamic_cast_succeeds(int32_t arg0) {
    extern long __dynamic_cast(long, long, long, int);
    Animal * animal;
    Dog * dog;
    unsigned char local_10[16];
    int ret;
    long rsp;
    long var5;
    rsp = (rsp - 24);
    *(long *)((&local_10[0] + 8)) = 0x3d60;
    *(long *)(&local_10[0]) = 0x3dc0;
    var5 = __dynamic_cast((((unsigned long)((unsigned char)((arg0 & 1))) == 0) ? (long)(&local_10[0]) : (long)((rsp + 16))), 0x3d10, 0x3d20, 0);
    if ((var5 == 0)) {
        // x86-64 epilogue: tear down frame
        return 0xffffffff;
    }
    ret = ((int (*)(long))(*(long *)((*(long *)((var5)) + 24))))(var5);
    // x86-64 epilogue: tear down frame
    return ret;
}
cpp_typeid_compare fail 48 lines
// glaurung: cpp_typeid_compare @ 0x11f0
typedef struct Animal Animal;
__attribute__((no_stack_protector)) int32_t cpp_typeid_compare(int32_t arg0) {
    extern int strcmp(const char *, const char *);
    const Animal * right;
    const Animal * left;
    unsigned char local_10[16];
    long local_18;
    long ret;
    long rsp;
    long var19;
    int var22;
    long var4;
    rsp = (rsp - 24);
    local_18 = 0x3d90;
    *(long *)(&local_10[0]) = 0x3d60;
    *(long *)((&local_10[0] + 8)) = 0x3dc0;
    var4 = (unsigned long)((unsigned int)((arg0 & 3)));
    if (((unsigned long)((unsigned int)(var4)) == 2)) {
        right = (const Animal *)&local_10[0];
        left = (const Animal *)&local_10[0];
    } else {
        if (((unsigned long)((unsigned int)(var4)) == 1)) {
            right = (const Animal *)&local_10[0];
            left = (const Animal *)(rsp);
        } else {
            if (((unsigned long)((unsigned int)(var4)) != 0)) {
                right = (const Animal *)((&local_10[0] + 8));
                left = (const Animal *)(rsp);
            } else {
                right = (const Animal *)(rsp);
                left = (const Animal *)(rsp);
            }
        }
    }
    var19 = *(long *)((*(long *)((*(long *)(((long)left)) - 8)) + 8));
    if ((var19 == *(long *)((*(long *)((*(long *)(((long)right)) - 8)) + 8)))) {
        // x86-64 epilogue: tear down frame
        return 1;
    }
    ret = 0;
    if (((unsigned long)((unsigned char)(*(char *)((var19)))) != 42)) {
        var22 = ((int (*)(void))strcmp)();
        ret = ((unsigned long)((unsigned int)(var22)) == 0);
    }
    // x86-64 epilogue: tear down frame
    return ret;
}

gcc -O0

0/4
_ZNKSt9type_infoeqERKS_ structural 21 lines
// glaurung: _ZNKSt9type_infoeqERKS_ @ 0x16e2
typedef struct type_info type_info;
bool _ZNKSt9type_infoeqERKS_(const type_info * arg0, long * arg1) {
    extern int strcmp(const char *, const char *);
    int var11;
    if ((*(long *)(((long)arg0 + 0x8)) == *(long *)(((long)arg1 + 0x8)))) {
        // x86-64 epilogue: restore rbp
        return 1;
    }
    if (((unsigned long)((unsigned char)(((unsigned int)((unsigned char)(*(char *)(*(long *)(((long)arg0 + 0x8))))) & 255))) == 42)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    var11 = strcmp((const char *)(*(long *)(((long)arg0 + 0x8))), (const char *)(*(long *)(((long)arg1 + 0x8))));
    if (((unsigned long)((unsigned int)(var11)) != 0)) {
        // x86-64 epilogue: restore rbp
        return 0;
    }
    // x86-64 epilogue: restore rbp
    return 1;
}
cpp_dynamic_cast_fails fail 43 lines
// glaurung: cpp_dynamic_cast_fails @ 0x1400
typedef struct Animal Animal;
typedef struct Puppy Puppy;
struct Cat;
struct Dog;
int32_t cpp_dynamic_cast_fails(int32_t arg0) {
    extern void _ZN12_GLOBAL__N_13CatD1Ev(const struct Cat *);
    extern void _ZN12_GLOBAL__N_13DogD2Ev(const struct Dog *);
    extern long __dynamic_cast(char *, long, long, int);
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    Animal * animal;
    Puppy * puppy;
    long local_18;
    unsigned char local_30[8];
    unsigned char local_38[8];
    long ret;
    long var10;
    long var17;
    int var21;
    char * var9;
    // x86-64 prologue: save rbp, frame 8 bytes
    local_18 = (long)(0x28);
    *(long *)(&local_38[0]) = 0x3d60;
    *(long *)(&local_30[0]) = 0x3d38;
    animal = (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 1))) == 0) ? (Animal *)&local_30[0] : (Animal *)&local_38[0]);
    var9 = (char *)animal;
    if ((animal == 0)) {
        var10 = 0;
    } else {
        var17 = __dynamic_cast(var9, 0x3df0, 0x3da8, 0);
        var10 = var17;
    }
    puppy = (Puppy *)(var10);
    var21 = ((puppy == 0) ? 0 : 1);
    ((void (*)(char *))_ZN12_GLOBAL__N_13CatD1Ev)((char *)(&local_30[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_13DogD2Ev)((char *)(&local_38[0]));
    ret = (unsigned long)((unsigned int)(var21));
    if ((local_18 != 0x28)) {
        __stack_chk_fail();
    }
    // x86-64 epilogue: restore rbp
    return ret;
}
cpp_dynamic_cast_succeeds fail 59 lines
// glaurung: cpp_dynamic_cast_succeeds @ 0x12fd
typedef struct Animal Animal;
typedef struct Dog Dog;
struct Cat;
struct Puppy;
int32_t cpp_dynamic_cast_succeeds(int32_t arg0) {
    extern __attribute__((noreturn)) long _Unwind_Resume(long);
    extern void _ZN12_GLOBAL__N_13CatD1Ev(const struct Cat *);
    extern void _ZN12_GLOBAL__N_15PuppyD1Ev(const struct Puppy *);
    extern long __dynamic_cast(char *, long, long, int);
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    Animal * animal;
    Dog * dog;
    long local_18;
    unsigned char local_30[8];
    unsigned char local_38[8];
    long ret;
    long var10;
    long var11;
    long var21;
    long var28;
    long var29;
    long var35;
    long var39;
    char * var9;
    // x86-64 prologue: save rbp, frame 8 bytes
    local_18 = (long)(0x28);
    *(long *)(&local_38[0]) = 0x3d08;
    *(long *)(&local_30[0]) = 0x3d38;
    animal = (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 1))) != 0) ? (Animal *)&local_38[0] : (Animal *)&local_30[0]);
    var9 = (char *)animal;
    if ((animal != 0)) {
        var10 = __dynamic_cast(var9, 0x3df0, 0x3dd8, 0);
        var11 = var10;
    } else {
        var11 = 0;
    }
    dog = (Dog *)(var11);
    if ((dog == 0)) {
        var21 = 0xffffffff;
    } else {
        var28 = ((long (*)(char *))(*(long *)((*(long *)((long)dog) + 24))))((char *)((long)dog));
        var29 = var28;
        var21 = (unsigned long)((unsigned int)(var28));
    }
    ((void (*)(char *))_ZN12_GLOBAL__N_13CatD1Ev)((char *)(&local_30[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_15PuppyD1Ev)((char *)(&local_38[0]));
    ret = (unsigned long)((unsigned int)(var21));
    if ((local_18 == 0x28)) {
        // x86-64 epilogue: restore rbp
        return ret;
    }
    __stack_chk_fail();
    // __glaurung_eh_landing_13cb
    var35 = var29;
    ((void (*)(char *))_ZN12_GLOBAL__N_13CatD1Ev)((char *)(&local_30[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_15PuppyD1Ev)((char *)(&local_38[0]));
    var39 = _Unwind_Resume(var35);
}
cpp_typeid_compare fail 98 lines
// glaurung: cpp_typeid_compare @ 0x14c3
typedef struct Animal Animal;
struct Cat;
struct Dog;
struct Puppy;
int32_t cpp_typeid_compare(int32_t arg0) {
    extern __attribute__((noreturn)) long _Unwind_Resume(long);
    extern void _ZN12_GLOBAL__N_13CatD1Ev(const struct Cat *);
    extern void _ZN12_GLOBAL__N_13DogD2Ev(const struct Dog *);
    extern void _ZN12_GLOBAL__N_15PuppyD1Ev(const struct Puppy *);
    extern int _ZNKSt9type_infoeqERKS_(char *, long *);
    extern long __cxa_bad_typeid(int);
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    const Animal * left;
    const Animal * right;
    long local_18;
    unsigned char local_30[8];
    unsigned char local_38[8];
    unsigned char local_40[8];
    long ret;
    char * var17;
    long var18;
    long var19;
    long var20;
    long var21;
    int var24;
    int var26;
    long var31;
    long var40;
    long var45;
    long var8;
    // x86-64 prologue: save rbp, frame 8 bytes
    local_18 = (long)(0x28);
    *(long *)(&local_40[0]) = 0x3d60;
    *(long *)(&local_38[0]) = 0x3d08;
    *(long *)(&local_30[0]) = 0x3d38;
    var8 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 3)));
    if (((unsigned long)((unsigned int)(var8)) == 2)) {
        left = (const Animal *)&local_38[0];
        right = (const Animal *)&local_38[0];
    } else {
        if (((((unsigned long)((unsigned int)(var8)) == 2) | ((long)((int)(var8)) < 2)) == 0)) {
            L_1554: ;
            left = (const Animal *)&local_40[0];
            right = (const Animal *)&local_30[0];
        } else {
            if (((unsigned long)((unsigned int)(var8)) == 0)) {
                left = (const Animal *)&local_40[0];
                right = (const Animal *)&local_40[0];
            } else {
                if (((unsigned long)((unsigned int)(var8)) == 1)) {
                    left = (const Animal *)&local_40[0];
                    right = (const Animal *)&local_38[0];
                } else {
                    goto L_1554;
                }
            }
        }
    }
    var17 = (char *)right;
    if ((right == 0)) {
        var18 = __cxa_bad_typeid(arg0);
        var19 = var18;
        var20 = var21;
        L_1585: ;
        var24 = _ZNKSt9type_infoeqERKS_((char *)(*(long *)((*(long *)((var19)) - 8))), (long *)(var20));
        if (((unsigned long)((unsigned char)((var24 & 255))) == 0)) {
            var26 = 0;
        } else {
            L_15a2: ;
            var26 = 1;
        }
    } else {
        var20 = *(long *)((*(long *)((var17)) - 8));
        var19 = (long)left;
        if ((left == 0)) {
            var31 = __cxa_bad_typeid(arg0);
            goto L_15a2;
        } else {
            goto L_1585;
        }
    }
    ((void (*)(char *))_ZN12_GLOBAL__N_13CatD1Ev)((char *)(&local_30[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_15PuppyD1Ev)((char *)(&local_38[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_13DogD2Ev)((char *)(&local_40[0]));
    ret = (unsigned long)((unsigned int)(var26));
    if ((local_18 == 0x28)) {
        // x86-64 epilogue: restore rbp
        return ret;
    }
    __stack_chk_fail();
    // __glaurung_eh_landing_15e5
    var40 = ret;
    ((void (*)(char *))_ZN12_GLOBAL__N_13CatD1Ev)((char *)(&local_30[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_15PuppyD1Ev)((char *)(&local_38[0]));
    ((void (*)(char *))_ZN12_GLOBAL__N_13DogD2Ev)((char *)(&local_40[0]));
    var45 = _Unwind_Resume(var40);
}

gcc -O2

0/3
cpp_dynamic_cast_fails fail 26 lines
// glaurung: cpp_dynamic_cast_fails @ 0x12c0
typedef struct Animal Animal;
typedef struct Puppy Puppy;
int32_t cpp_dynamic_cast_fails(int32_t arg0) {
    extern long __dynamic_cast(long, long, long, int, long);
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    Animal * animal;
    Puppy * puppy;
    long local_10;
    unsigned char local_18[8];
    unsigned char local_20[8];
    long rsp;
    long var11;
    long var8;
    rsp = (rsp - 40);
    local_10 = (long)(0x28);
    *(long *)(&local_20[0]) = 0x3d40;
    *(long *)(&local_18[0]) = 0x3d70;
    var8 = __dynamic_cast((((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 1))) == 0) ? (long)(&local_18[0]) : (long)((rsp + 8))), 0x3db8, 0x3df8, 0, (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 1))));
    var11 = (var8 != 0);
    if ((local_10 != 0x28)) {
        __stack_chk_fail();
    }
    // x86-64 epilogue: tear down frame
    return (unsigned int)((unsigned char)((var11 & 255)));
}
cpp_dynamic_cast_succeeds fail 33 lines
// glaurung: cpp_dynamic_cast_succeeds @ 0x1230
typedef struct Animal Animal;
typedef struct Dog Dog;
int32_t cpp_dynamic_cast_succeeds(int32_t arg0) {
    extern long __dynamic_cast(long, long, long, int, long);
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    Dog * dog;
    Animal * animal;
    long local_10;
    unsigned char local_18[8];
    unsigned char local_20[8];
    long ret;
    long rsp;
    long var12;
    long var8;
    rsp = (rsp - 40);
    local_10 = (long)(0x28);
    *(long *)(&local_20[0]) = 0x3d98;
    *(long *)(&local_18[0]) = 0x3d70;
    var8 = __dynamic_cast((((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 1))) == 0) ? (long)(&local_18[0]) : (long)((rsp + 8))), 0x3db8, 0x3dc8, 0, (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 1))));
    dog = (Dog *)(var8);
    if ((var8 == 0)) {
        ret = 0xffffffff;
    } else {
        var12 = ((long (*)(char *))(*(long *)((*(long *)((var8)) + 24))))((char *)((long)dog));
        ret = var12;
    }
    if ((local_10 != 0x28)) {
        __stack_chk_fail();
    }
    // x86-64 epilogue: tear down frame
    return ret;
}
cpp_typeid_compare fail 30 lines
// glaurung: cpp_typeid_compare @ 0x1340
int32_t cpp_typeid_compare(int32_t arg0) {
    extern int strcmp(const char *, const char *);
    long ret;
    long var1;
    int var10;
    long var2;
    long var3;
    long var8;
    var1 = (unsigned long)((unsigned int)((arg0 & 3)));
    var2 = 0x3d40;
    var3 = 0x3d98;
    if (((unsigned long)((unsigned int)(var1)) != 1)) {
        var2 = var3;
        if (((unsigned long)((unsigned int)(var1)) != 2)) {
            var2 = 0x3d40;
            var3 = (((unsigned long)((unsigned int)(var1)) == 0) ? 0x3d40 : 0x3d70);
        }
    }
    var8 = *(long *)((*(long *)((var2 - 0x8)) + 8));
    ret = 1;
    if ((var8 != *(long *)((*(long *)((var3 - 0x8)) + 8)))) {
        ret = 0;
        if (((unsigned long)((unsigned char)(*(char *)((var8)))) != 42)) {
            var10 = ((int (*)(void))strcmp)();
            return ((unsigned long)((unsigned int)(var10)) == 0);
        }
    }
    return ret;
}

← 213 fixtures