Fixture 167

rust trait objects

Rust · 6 functions · 2 lanes · 1 of 12 function-lanes behave identically

2 of 2 lanes have a function that returns a different result after decompilation: rustc-O0 (0/6), rustc-O2 (1/6).

tests/decompiler_fixtures/src/167_rust_trait_objects.rs source
// 167_rust_trait_objects.rs
//
// Rust dynamic dispatch through `&dyn Trait`. A trait object is a FAT POINTER:
// two machine words, (data pointer, vtable pointer). Unlike a C++ object, the
// vtable pointer is NOT stored in the object — it travels alongside it in the
// reference, so a `&dyn Op` passed by value occupies two registers and a
// `&[&dyn Op]` is an array of 16-byte pairs.
//
// The recovery signals:
//   * a virtual call is `call [rax + 8*k]` where rax is the SECOND half of a
//     pair the callee never loaded from the object;
//   * the Rust vtable layout is [drop_in_place, size, align, method0, method1,
//     ...], so the first user method sits at offset 24 on x86-64, not 0;
//   * unsizing a `&Concrete` to a `&dyn Op` is a pure compile-time act: it
//     materialises a pointer to a static vtable with no runtime work, so the
//     only evidence is a relocation into .data.rel.ro;
//   * `Box<dyn Op>` adds drop glue reached through vtable slot 0.
//
// Exposure: every driver is `#[no_mangle] pub extern "C" fn` over plain i32/u32
// scalars and caller-owned `*mut i32` buffers. Selectors are taken modulo the
// number of impls, counts are masked to <= 16, pointers are null-checked, and
// every arithmetic operation is `wrapping_*`. No input the harness can pass can
// panic or index out of bounds.
//
// Deterministic: the trait objects point at `static` instances or at freshly
// boxed values whose contents are a pure function of the arguments; no address
// is ever observed.

/// The object-safe trait. Two methods, so vtable slot ORDER matters: a
/// decompiler that swaps them produces a plausible-looking wrong answer.
trait Op {
    fn apply(&self, x: i32) -> i32;
    fn tag(&self) -> i32;
}

struct AddK {
    k: i32,
}
struct MulK {
    k: i32,
}
struct Clamp {
    lo: i32,
    hi: i32,
}
struct Affine {
    a: i32,
    b: i32,
}

impl Op for AddK {
    fn apply(&self, x: i32) -> i32 {
        x.wrapping_add(self.k)
    }
    fn tag(&self) -> i32 {
        11
    }
}

impl Op for MulK {
    fn apply(&self, x: i32) -> i32 {
        x.wrapping_mul(self.k)
    }
    fn tag(&self) -> i32 {
        22
    }
}

impl Op for Clamp {
    fn apply(&self, x: i32) -> i32 {
        if x < self.lo {
            self.lo
        } else if x > self.hi {
            self.hi
        } else {
            x
        }
    }
    fn tag(&self) -> i32 {
        33
    }
}

impl Op for Affine {
    fn apply(&self, x: i32) -> i32 {
        x.wrapping_mul(self.a).wrapping_add(self.b)
    }
    fn tag(&self) -> i32 {
        44
    }
}

static ADD7: AddK = AddK { k: 7 };
static MUL3: MulK = MulK { k: 3 };
static CLAMP: Clamp = Clamp { lo: -100, hi: 100 };
static AFFINE: Affine = Affine { a: 5, b: -9 };

/// Unsizing coercion site: four `&'static Concrete` values become
/// `&'static dyn Op` fat pointers, each pairing the same data pointer with a
/// different static vtable.
#[inline(never)]
fn choose(sel: u32) -> &'static dyn Op {
    match sel & 3 {
        0 => &ADD7,
        1 => &MUL3,
        2 => &CLAMP,
        _ => &AFFINE,
    }
}

/// One dynamic call through a fat pointer. `sel` is masked, so every input
/// selects a valid impl.
#[no_mangle]
pub extern "C" fn rust_dyn_apply(sel: u32, x: i32) -> i32 {
    choose(sel).apply(x)
}

/// Both vtable slots on the same object, so slot ordering is observable: a
/// decompiler that reads slot 3 where slot 4 belongs returns the other method's
/// value.
#[no_mangle]
pub extern "C" fn rust_dyn_two_slots(sel: u32, x: i32) -> i32 {
    let op = choose(sel);
    op.apply(x).wrapping_mul(100).wrapping_add(op.tag())
}

/// A fat pointer crossing a function boundary as an ARGUMENT: `op` arrives in
/// two registers and neither half is loaded from memory.
#[inline(never)]
fn twice(op: &dyn Op, x: i32) -> i32 {
    op.apply(op.apply(x))
}

#[no_mangle]
pub extern "C" fn rust_dyn_pass_fat(sel: u32, x: i32) -> i32 {
    twice(choose(sel), x)
}

/// A pipeline over an array of trait objects: the loop indexes 16-byte pairs,
/// reloading a different vtable each iteration, so the call target genuinely
/// varies at runtime and cannot be devirtualized.
#[no_mangle]
pub extern "C" fn rust_dyn_pipeline(x: i32, mask: u32) -> i32 {
    let ops: [&dyn Op; 4] = [&ADD7, &MUL3, &CLAMP, &AFFINE];
    let mut acc = x;
    for (i, op) in ops.iter().enumerate() {
        if mask & (1u32 << i) != 0 {
            acc = op.apply(acc);
        }
    }
    acc
}

/// Heap trait object. `Box<dyn Op>` is the same fat pointer, but dropping it
/// goes through vtable slot 0 (`drop_in_place`) plus the size/align slots, which
/// is the shape a decompiler most often mistakes for a data field.
#[inline(never)]
fn boxed(sel: u32, k: i32) -> Box<dyn Op> {
    match sel & 3 {
        0 => Box::new(AddK { k }),
        1 => Box::new(MulK { k }),
        2 => Box::new(Clamp {
            lo: -(k.wrapping_abs() & 0xff),
            hi: k.wrapping_abs() & 0xff,
        }),
        _ => Box::new(Affine {
            a: k,
            b: k.wrapping_neg(),
        }),
    }
}

/// The box is created, called through, and dropped inside the wrapper; only the
/// computed i32 escapes, so no address is ever observable.
#[no_mangle]
pub extern "C" fn rust_dyn_boxed(sel: u32, k: i32, x: i32) -> i32 {
    let op = boxed(sel, k);
    let r = op.apply(x).wrapping_add(op.tag());
    // `op` drops here: vtable slot 0 then the deallocation.
    r
}

/// Write one dynamic-dispatch result per element into a caller-owned buffer, so
/// the per-impl behaviour is visible as a buffer diff rather than a single
/// return value.
///
/// `out` is null-checked and `n` is clamped to the harness's 16-element buffer.
#[no_mangle]
pub extern "C" fn rust_dyn_fill(out: *mut i32, n: u32, x: i32) -> i32 {
    if out.is_null() {
        return -1;
    }
    let len = if n > 16 { 16 } else { n } as usize;
    // SAFETY: the caller owns at least 16 i32s at `out`; `len <= 16`.
    let dst: &mut [i32] = unsafe { core::slice::from_raw_parts_mut(out, len) };
    let mut sum: i32 = 0;
    for (i, slot) in dst.iter_mut().enumerate() {
        let op = choose(i as u32);
        let v = op.apply(x.wrapping_add(i as i32)).wrapping_add(op.tag());
        *slot = v;
        sum = sum.wrapping_add(v);
    }
    sum
}

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.

rustc -O0

0/6
rust_dyn_apply fail 10 lines
// glaurung: rust_dyn_apply @ 0x7ff0
long rust_dyn_apply(unsigned int arg0, unsigned int arg1) {
    extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
    long ret;
    long var0;
    long var2;
    var0 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(arg0);
    ret = ((long (*)(long, unsigned int))(*(long *)((var2 + 0x18))))(var0, arg1);
    return ret;
}
rust_dyn_boxed fail 31 lines
// glaurung: rust_dyn_boxed @ 0x8590
__attribute__((no_stack_protector)) unsigned int rust_dyn_boxed(unsigned int arg0, int arg1, long * arg2) {
    extern __attribute__((noreturn)) long _Unwind_Resume(long);
    extern long _ZN23_167_rust_trait_objects5boxed17h7fd2f955c5540387E(unsigned int, int);
    extern void _ZN4core3ptr80drop_in_place_LT_alloc__boxed__Box_LT_dyn_u20_167_rust_trait_objects__Op_GT__GT_17h3cbb2df48a91365bE(char *);
    int local_4;
    unsigned char local_40[8];
    int local_44;
    int local_4c;
    int local_50;
    int local_8;
    int local_c;
    long stack_1;
    long var0;
    long var19;
    long var4;
    long var8;
    var0 = _ZN23_167_rust_trait_objects5boxed17h7fd2f955c5540387E(arg0, arg1);
    *(long *)(&local_40[0]) = var0;
    var4 = ((long (*)(long, long))(*(long *)(((long)arg2 + 0x18))))(*(long *)(&local_40[0]), (unsigned long)((unsigned int)((long)arg2)));
    local_44 = var4;
    var8 = ((long (*)(long))(*(long *)(((long)arg2 + 0x20))))(*(long *)(&local_40[0]));
    local_4c = var8;
    local_8 = local_44;
    local_4 = local_4c;
    local_50 = ((unsigned int)(local_44) + (unsigned int)(local_4c));
    local_c = local_50;
    _ZN4core3ptr80drop_in_place_LT_alloc__boxed__Box_LT_dyn_u20_167_rust_trait_objects__Op_GT__GT_17h3cbb2df48a91365bE((char *)(&local_40[0]));
    return (unsigned int)(local_50);
    var19 = _Unwind_Resume(stack_1);
}
rust_dyn_fill fail 98 lines
// glaurung: rust_dyn_fill @ 0x8650
__attribute__((no_stack_protector)) unsigned int rust_dyn_fill(char * arg0, unsigned int arg1, long * arg2) {
    extern long _ZN110__LT_core__iter__adapters__enumerate__Enumerate_LT_I_GT__u20_as_u20_core__iter__traits__iterator__Iterator_GT_4next17h7608ef65c26f9b4bE(char *);
    extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
    extern int _ZN4core3ptr7mut_ptr31__LT_impl_u20__BP_mut_u20_T_GT_7is_null17h1d166d76aab99a9eE(char *);
    extern long * _ZN4core4iter6traits8iterator8Iterator9enumerate17hc2d855ee0ebdea14E(long *);
    extern long _ZN4core5slice29__LT_impl_u20__u5b_T_u5d__GT_8iter_mut17hd603a13a84836734E(long);
    extern long _ZN4core5slice3raw18from_raw_parts_mut17h7e6428c598b7c73fE(char *, long);
    extern long * _ZN63__LT_I_u20_as_u20_core__iter__traits__collect__IntoIterator_GT_9into_iter17h0a17a1addf51cbb9E(long *);
    int local_10;
    unsigned char local_108[24];
    int local_14;
    int local_18;
    int local_1c;
    long local_28;
    long local_30;
    long local_38;
    int local_4;
    long local_40;
    long local_50;
    long local_58;
    unsigned char local_a8[64];
    int local_c;
    unsigned char local_c0[24];
    int local_c4;
    int local_c8;
    long local_e8;
    int local_ec;
    int var0;
    long var10;
    long * var13;
    long * var16;
    long var23;
    long var24;
    long var26;
    long var31;
    long var32;
    long var33;
    long var37;
    long var39;
    long var41;
    long var42;
    int var46;
    long var6;
    var0 = _ZN4core3ptr7mut_ptr31__LT_impl_u20__BP_mut_u20_T_GT_7is_null17h1d166d76aab99a9eE(arg0);
    if (((unsigned long)((unsigned char)((var0 & 1))) != 0)) {
        return (unsigned int)(-1);
    } else {
        local_c8 = (((unsigned long)(16) < (unsigned long)(arg1)) ? 16 : (unsigned long)(arg1));
        local_58 = (unsigned int)(local_c8);
        var6 = ((long (*)(char *))_ZN4core5slice3raw18from_raw_parts_mut17h7e6428c598b7c73fE)(arg0);
        local_50 = var6;
        local_c4 = 0;
        var10 = ((long (*)(void))_ZN4core5slice29__LT_impl_u20__u5b_T_u5d__GT_8iter_mut17hd603a13a84836734E)();
        var13 = _ZN4core4iter6traits8iterator8Iterator9enumerate17hc2d855ee0ebdea14E((long *)(&local_a8[0]));
        var16 = _ZN63__LT_I_u20_as_u20_core__iter__traits__collect__IntoIterator_GT_9into_iter17h0a17a1addf51cbb9E((long *)(&local_c0[0]));
        *(long *)((&local_a8[0] + 24)) = *(long *)(&local_c0[0]);
        *(long *)((&local_a8[0] + 32)) = *(long *)((&local_c0[0] + 8));
        *(long *)((&local_a8[0] + 40)) = *(long *)((&local_c0[0] + 16));
        var23 = (long)arg2;
        while (1) {
            var24 = _ZN110__LT_core__iter__adapters__enumerate__Enumerate_LT_I_GT__u20_as_u20_core__iter__traits__iterator__Iterator_GT_4next17h7608ef65c26f9b4bE((char *)((&local_a8[0] + 24)));
            *(long *)((&local_a8[0] + 56)) = var23;
            *(long *)((&local_a8[0] + 48)) = var24;
            var26 = *(long *)((&local_a8[0] + 56));
            if ((((var26 == 0) ? 0 : 1) == 0)) {
                break;
            }
            var31 = *(long *)((&local_a8[0] + 48));
            *(long *)(&local_108[0]) = var31;
            local_40 = var31;
            var32 = *(long *)((&local_a8[0] + 56));
            local_e8 = var32;
            local_38 = var32;
            var33 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE((unsigned long)((unsigned int)(var31)));
            var37 = *(long *)(&local_108[0]);
            *(long *)((&local_108[0] + 8)) = var33;
            *(long *)((&local_108[0] + 16)) = var26;
            local_30 = var33;
            local_28 = var26;
            local_4 = var37;
            var39 = ((long (*)(void))(*(long *)((var26 + 0x18))))();
            var41 = *(long *)((&local_108[0] + 16));
            local_ec = var39;
            var42 = ((long (*)(long))(*(long *)((var41 + 0x20))))(*(long *)((&local_108[0] + 8)));
            var23 = (unsigned long)((unsigned int)(var42));
            local_10 = local_ec;
            local_c = var42;
            var46 = ((unsigned int)(local_ec) + (unsigned int)(var42));
            local_1c = var46;
            *(int *)((local_e8)) = var46;
            local_18 = local_c4;
            local_14 = var46;
            local_c4 = ((unsigned int)(local_c4) + (unsigned int)(var46));
        }
        return (unsigned int)(local_c4);
    }
}
rust_dyn_pass_fat fail 11 lines
// glaurung: rust_dyn_pass_fat @ 0x80d0
long rust_dyn_pass_fat(unsigned int arg0, int arg1) {
    extern long _ZN23_167_rust_trait_objects5twice17h36528406cc8e74b3E(long, long *);
    extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
    long ret;
    long var0;
    long var3;
    var0 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(arg0);
    ret = _ZN23_167_rust_trait_objects5twice17h36528406cc8e74b3E(var0, (long *)(var3));
    return ret;
}
rust_dyn_pipeline fail 76 lines
// glaurung: rust_dyn_pipeline @ 0x8100
__attribute__((no_stack_protector)) unsigned int rust_dyn_pipeline(int arg0, unsigned int arg1) {
    extern long _ZN110__LT_core__iter__adapters__enumerate__Enumerate_LT_I_GT__u20_as_u20_core__iter__traits__iterator__Iterator_GT_4next17h5d49829560f42720E(char *);
    extern long * _ZN4core4iter6traits8iterator8Iterator9enumerate17h20dcc5431a417106E(long *);
    extern long _ZN4core5slice29__LT_impl_u20__u5b_T_u5d__GT_4iter17h7f8eae9626c086e2E(long);
    extern long _ZN4core9panicking5panic17hf516d800ede7db8cE(const char *, int, long);
    extern long * _ZN63__LT_I_u20_as_u20_core__iter__traits__collect__IntoIterator_GT_9into_iter17h60cdd159fea15aa3E(long *);
    long local_10;
    unsigned char local_58[64];
    unsigned char local_70[24];
    int local_74;
    long local_8;
    long local_80;
    long local_88;
    long local_90;
    long local_98;
    long local_a0;
    long local_a8;
    long local_b0;
    unsigned char local_b8[8];
    long local_c8;
    long local_d0;
    long * var12;
    long * var15;
    long var22;
    long var23;
    long var24;
    long var31;
    long var32;
    long var44;
    long var48;
    long var9;
    *(long *)(&local_b8[0]) = (long)((long)(0x4607c));
    local_b0 = 0x565d8;
    local_a8 = (long)(0x46080);
    local_a0 = 0x56600;
    local_98 = (long)(0x46084);
    local_90 = 0x56628;
    local_88 = (long)(0x4608c);
    local_80 = 0x56650;
    local_74 = arg0;
    var9 = _ZN4core5slice29__LT_impl_u20__u5b_T_u5d__GT_4iter17h7f8eae9626c086e2E((long)(&local_b8[0]));
    var12 = _ZN4core4iter6traits8iterator8Iterator9enumerate17h20dcc5431a417106E((long *)(&local_58[0]));
    var15 = _ZN63__LT_I_u20_as_u20_core__iter__traits__collect__IntoIterator_GT_9into_iter17h60cdd159fea15aa3E((long *)(&local_70[0]));
    *(long *)((&local_58[0] + 24)) = *(long *)(&local_70[0]);
    *(long *)((&local_58[0] + 32)) = *(long *)((&local_70[0] + 8));
    *(long *)((&local_58[0] + 40)) = *(long *)((&local_70[0] + 16));
    var22 = var23;
    L_81d5: ;
    var24 = _ZN110__LT_core__iter__adapters__enumerate__Enumerate_LT_I_GT__u20_as_u20_core__iter__traits__iterator__Iterator_GT_4next17h5d49829560f42720E((char *)((&local_58[0] + 24)));
    *(long *)((&local_58[0] + 56)) = var22;
    *(long *)((&local_58[0] + 48)) = var24;
    if ((((*(long *)((&local_58[0] + 56)) == 0) ? 0 : 1) == 0)) {
        // x86-64 epilogue: tear down frame
        return (unsigned int)(local_74);
    }
    var31 = *(long *)((&local_58[0] + 48));
    local_d0 = var31;
    local_10 = var31;
    var32 = *(long *)((&local_58[0] + 56));
    local_c8 = var32;
    local_8 = var32;
    if (((unsigned long)(var31) < (unsigned long)(32))) {
        var22 = (unsigned long)((unsigned int)((1 << ((unsigned long)((unsigned int)((local_d0 & 31))) & 31))));
        if (((unsigned long)((unsigned int)((arg1 & (unsigned long)((unsigned int)(var22))))) == 0)) {
            goto L_81d5;
        }
        goto L_8292;
    }
    var44 = _ZN4core9panicking5panic17hf516d800ede7db8cE((const char *)("attempt to shift left with overflow"), 35, 0x56678);
    /* asm: ud2 */
    L_8292: ;
    var48 = ((long (*)(long, long))(*(long *)((*(long *)((local_c8 + 0x8)) + 24))))(*(long *)(local_c8), (unsigned long)((unsigned int)(local_74)));
    local_74 = var48;
    goto L_81d5;
}
rust_dyn_two_slots fail 30 lines
// glaurung: rust_dyn_two_slots @ 0x8020
unsigned int rust_dyn_two_slots(unsigned int arg0, unsigned int arg1) {
    extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
    int local_10;
    long local_18;
    long local_20;
    int local_2c;
    long local_38;
    int local_4;
    long local_40;
    int local_8;
    int local_c;
    long var0;
    long var4;
    long var5;
    long var9;
    var0 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(arg0);
    local_40 = var0;
    local_38 = var4;
    local_20 = var0;
    local_18 = var4;
    var5 = ((long (*)(void))(*(long *)((var4 + 0x18))))();
    local_8 = var5;
    local_4 = 100;
    local_2c = (var5 * 100);
    var9 = ((long (*)(long))(*(long *)((local_38 + 0x20))))(local_40);
    local_10 = local_2c;
    local_c = var9;
    return (unsigned int)(((unsigned long)((unsigned int)(local_2c)) + (unsigned long)((unsigned int)(var9))));
}

rustc -O2

1/6
rust_dyn_apply fail 8 lines
// glaurung: rust_dyn_apply @ 0x7120
long rust_dyn_apply(unsigned int arg0, unsigned int arg1) {
    extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
    long var1;
    long var4;
    var1 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(arg0);
    /* unrecovered indirect jump through *(long *)((var4 + 0x18)) */
}
rust_dyn_boxed fail 32 lines
// glaurung: rust_dyn_boxed @ 0x72f0
static unsigned char glaurung_global_57c70[16] __attribute__((aligned(16)));
unsigned int rust_dyn_boxed(unsigned int arg0, int arg1, long * arg2) {
    extern long _ZN23_167_rust_trait_objects5boxed17h7fd2f955c5540387E(unsigned int, int);
    extern unsigned char glaurung_global_57c70[16];
    long local_30;
    long var0;
    long var1;
    long var10;
    long var11;
    long var15;
    long var3;
    long var4;
    long var5;
    long var7;
    long var8;
    var0 = (unsigned long)((unsigned int)((long)arg2));
    var1 = _ZN23_167_rust_trait_objects5boxed17h7fd2f955c5540387E(arg0, arg1);
    var3 = var1;
    var4 = (long)arg2;
    local_30 = var1;
    var5 = ((long (*)(long, long))(*(long *)(((long)arg2 + 0x18))))(var1, (unsigned long)((unsigned int)(var0)));
    var7 = (unsigned long)((unsigned int)(var5));
    var8 = ((long (*)(long))(*(long *)((var4 + 0x20))))(var3);
    var10 = (unsigned long)((unsigned int)(var8));
    var11 = ((long (*)(long))(*(long *)((var4))))(var3);
    if ((*(long *)((var4 + 0x8)) != 0)) {
        var15 = ((long (*)(long))(*(long *)(&glaurung_global_57c70[0])))(var3);
    }
    // x86-64 epilogue: tear down frame
    return (unsigned int)((var10 + var7));
}
rust_dyn_fill fail 43 lines
// glaurung: rust_dyn_fill @ 0x7390
unsigned int rust_dyn_fill(char * arg0, unsigned int arg1, long * arg2) {
    extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
    long local_40;
    long var12;
    long var13;
    long var15;
    long var17;
    long var18;
    long var20;
    long var22;
    long var23;
    int var26;
    long var3;
    long var9;
    if ((arg0 == 0)) {
        return 0xffffffff;
    } else {
        var3 = (((unsigned long)(arg1) < (unsigned long)(16)) ? arg1 : 16);
        if (((unsigned long)((unsigned int)(var3)) == 0)) {
            return 0;
        } else {
            local_40 = (long)((unsigned int)((long)arg2));
            var9 = 0;
            var12 = 0;
            var13 = (var3 << 2);
            do {
                var15 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE((unsigned long)((unsigned int)(var9)));
                var17 = var15;
                var18 = (long)arg2;
                var20 = ((long (*)(long, long))(*(long *)(((long)arg2 + 0x18))))(var15, (unsigned long)((unsigned int)((local_40 + var9))));
                var22 = (unsigned long)((unsigned int)(var20));
                var23 = ((long (*)(long))(*(long *)((var18 + 0x20))))(var17);
                var26 = (var23 + var22);
                *(int *)(((long)arg0 + var9 * 4)) = var26;
                var12 = (unsigned long)((unsigned int)((var12 + (unsigned long)((unsigned int)(var26)))));
                var9 = (var9 + 1);
                var13 = (var13 - 4);
            } while ((var13 != 0));
            return (unsigned int)(var12);
        }
    }
}
rust_dyn_pass_fat fail 13 lines
// glaurung: rust_dyn_pass_fat @ 0x71a0
long rust_dyn_pass_fat(unsigned int arg0, int arg1) {
    extern long _ZN23_167_rust_trait_objects5twice17h36528406cc8e74b3E(long, long, long);
    extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
    long ret;
    long var0;
    long var1;
    long var3;
    var0 = (unsigned long)((unsigned int)(arg1));
    var1 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(arg0);
    ret = _ZN23_167_rust_trait_objects5twice17h36528406cc8e74b3E(var1, var3, (unsigned long)((unsigned int)(var0)));
    return ret;
}
rust_dyn_pipeline pass 13 lines
// glaurung: rust_dyn_pipeline @ 0x71c0
unsigned int rust_dyn_pipeline(long arg0, long arg1) {
    long var1;
    int var3;
    int var5;
    var1 = (((unsigned long)((unsigned char)((arg1 & 1))) == 0) ? arg0 : (unsigned long)((unsigned int)((arg0 + 7))));
    var3 = (((unsigned long)((unsigned char)((arg1 & 2))) == 0) ? var1 : (unsigned long)((unsigned int)((var1 + (var1 * 2)))));
    if (((unsigned long)((unsigned char)((arg1 & 4))) != 0)) {
        var5 = (((long)((int)(var3)) < 100) ? var3 : 100);
        var3 = ((-99 <= (long)((int)(var5))) ? var5 : 0xffffff9c);
    }
    return (((unsigned long)((unsigned char)((arg1 & 8))) == 0) ? var3 : (unsigned long)((unsigned int)(((var3 + (var3 * 4)) - 9))));
}
rust_dyn_two_slots fail 21 lines
// glaurung: rust_dyn_two_slots @ 0x7140
unsigned int rust_dyn_two_slots(unsigned int arg0, unsigned int arg1) {
    extern long _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(unsigned int);
    long var0;
    long var1;
    long var3;
    long var4;
    long var5;
    long var6;
    int var8;
    long var9;
    var0 = (unsigned long)(arg1);
    var1 = _ZN23_167_rust_trait_objects6choose17h99d18eb70998ed2fE(arg0);
    var3 = var1;
    var4 = var5;
    var6 = ((long (*)(long, long))(*(long *)((var5 + 0x18))))(var1, (unsigned long)((unsigned int)(var0)));
    var8 = (var6 * 100);
    var9 = ((long (*)(long))(*(long *)((var4 + 0x20))))(var3);
    // x86-64 epilogue: tear down frame
    return (unsigned int)((var9 + var8));
}

← 213 fixtures