Day 3: not much progress. I’ve added a little code to render a basic game map, but most of my time has been taken up by a bug in the Rust ncurses bindings, which prevented special “ACS” characters from displaying.

Screenshot of the map rendering

I spent three hours last night tracking down the bug, on the hunch that Rust wasn’t correctly finding the array where the codes for the special characters were kept (acs_map). Long story short, after looking through the disassembly of the game1, I found that the function that accesses acs_map was essentially a no-op:

000000000000ddb0 <_ZN7ncurses9constants7acs_map17hbae0ad2383a3a04eE>:
    ddb0:   55                      push   %rbp
    ddb1:   48 89 e5                mov    %rsp,%rbp
    ddb4:   eb 00                   jmp    ddb6 <_ZN7ncurses9constants7acs_map17hbae0ad2383a3a04eE+0x6>
    ddb6:   eb 00                   jmp    ddb8 <_ZN7ncurses9constants7acs_map17hbae0ad2383a3a04eE+0x8>
    ddb8:   5d                      pop    %rbp
    ddb9:   c3                      retq
    ddba:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)

After figuring that out, the question was how to get Rust to properly read the array. acs_map is a static global array (not a pointer to one), and was currently declared as [chtype; 0] (0 length because we don’t know the length). *const chtype caused segfaults. [chtype; 128] worked, and looking at the generated assembly, I saw that Rust was memcpying the array. I think this is because arrays implement Copy. The accessor function basically looked like this:

pub fn acs_map() -> [chtype; 0] {
    unsafe {
        wrapped::acs_map
    }
}

so Rust would copy the array…except it was told the array was 0-size, so it did nothing, expecting that you wouldn’t be so naïve as to try and dereference it, which of course we were. The solution was to cast the base of the array to a pointer before accessing it, preventing Rust from trying to memcpy. Adding the length “fixed” it because then Rust copied over the data we were trying to access first.

I’ve filed a pull request to fix the bug. Next up: actually rendering the programs you control. I’ll be talking a little more about game mechanics soon.

  1. I’m terrible at reading AMD64 assembly, as we’re taught MIPS at school, never mind the fact that the Rust-generated assembly is a lot messier than C’s.