Slice and Array not pointing at the same data

The problem is in Emulator.init:

pub fn init(program_bytes: []const u8) !Emulator {
    // ...
    var emu: Emulator = .{
        // ...
    };
    // ...
    emu.memory_s = &emu.memory; // points to the current stack frame
    // ...
    return emu; // this returns a copy of 'emu', including the `emu.memory` array
}

// ...

fn foo() void {
    const emu = try Emulator.init(bytes);
    // 'emu.memory' resides on the 'foo' stack frame, but
    // 'emu.memory_s' points to data on the 'init' stack frame,
    // which no longer exists and will be overwritten by junk
}

In summary:

  • emu is initialized and stored on the init function’s stack frame. This includes the emu.memory field (important reminder: arrays are values in zig, they don’t decay into pointers like in C).
  • A pointer pointing to emu.memory is then stored to emu.memory_s, meaning that emu.memory_s is pointing to the current stack frame.
  • Finally, emu is returned to the caller (the foo function), meaning that its data is copied by value to the result location. After this, the init stack frame is no longer active and any data residing on it invalidated.
  • The emu inside the foo function’s memory_s field is pointing to data that is no longer valid and which may be overwritten by any random junk data.

I would advice against defining self-referential structs (meaning structs with fields that point to the struct instance itself) as they are very error-prone and easy to make mistakes with when struct instances are copied around without updating pointers.

The memory_s field is pretty redundant; just pass &emu.memory directly instead.

The problem you’re experience is kind of similar to a few recent threads (Seg faults using dir.Walker through interface - #2 by castholm and Local Random Number Generator sometimes core dumps2 - #3 by castholm), so if anything is unclear I would also suggest that you check both of those threads and my answers.

3 Likes