HeapsIO / heaps

Heaps : Haxe Game Framework
http://heaps.io
MIT License
3.19k stars 337 forks source link

address-sanitizer fires on initialization (hl/c target) #1239

Open byte0xcafe opened 1 week ago

byte0xcafe commented 1 week ago

Version & system Info:

OS: EndeavourOS Linux x86_64 
compiler:  gcc --version: gcc (GCC) 14.2.1 20240910

haxe --version: 4.3.6
hashlink-1.14 (compiled it myself)
haxelib list:
    domkit: [git]
    format: [3.7.0]
    greeter: [0.1.0]
    hashlink: [0.1.0]
    haxeui-core: [1.7.0]
    haxeui-heaps: [1.7.0]
    heaps: [2.0.0]
    hlc-compiler: [0.3.0]
    hlsdl: [1.14.0]
    hxcpp: [4.3.2]
    hxnativefiledialog: [1.0.0]
    lime-samples: [7.0.0]
    lime: [8.1.2]
    locator: [0.5.0]
    sinker: [0.6.0]

Working on a haxeui project using the heaps.io backend I occasionally got crashes of my app directly on startup (starting it via hashlink as well as using compiled hl/c).

Trying to nail the issue, I compiled my hl/c stuff with address-sanitzer and immediately got a hit in the generated init-code.

To investigate further, I added some printfs to the generated hl/c code and found, that the issue originates from the enum-init-code for some enums from heaps.io, in the run below it seems EventKind triggered it, but I also saw other enums triggering it.

The code seems iterating over some fields (see how r2 goes from 0 to 7) but at some point, the next iteration breaks and in this case, '8' ends up in r4 which is when interpreted as a pointer and triggers ASAN (within hl_types_ArrayObj_push).


[...]
t$hxd_$FlushMode
Type_initEnum @ 110
Type_initEnum @ 135
Type_initEnum @ 140
Type_initEnum @ 142
r6->size: 5
Type_initEnum 'N' 'h'
r12 = 1074034976
R4 = 129365776526064 R2 = 0
Type_initEnum @ 169
Type_initEnum 'S' 'h'
r12 = 1074034976
R4 = 1073961536 R2 = 1
Type_initEnum @ 169
Type_initEnum 'F' 'h'
r12 = 1074034976
R4 = 1074400384 R2 = 2
Type_initEnum @ 169
Type_initEnum 'F' 'h'
r12 = 1074034976
R4 = 1074944128 R2 = 3
Type_initEnum @ 169
Type_initEnum 'B' 'h'
r12 = 1074034976
R4 = 1074944176 R2 = 4
Type_initEnum @ 169
t$hxd_$DialogFlags
Type_initEnum @ 110
Type_initEnum @ 135
Type_initEnum @ 140
Type_initEnum @ 142
r6->size: 2
Type_initEnum 'Y' 'h'
r12 = 1074035576
R4 = 129365776526064 R2 = 0
Type_initEnum @ 169
Type_initEnum 'I' 'h'
r12 = 1074035576
R4 = 1073961824 R2 = 1
Type_initEnum @ 169
t$hxd_$Cursor
Type_initEnum @ 110
Type_initEnum @ 135
Type_initEnum @ 140
Type_initEnum @ 142
r6->size: 7
Type_initEnum 'D' 'h'
r12 = 1074036200
R4 = 129365776526064 R2 = 0
Type_initEnum @ 169
Type_initEnum 'B' 'h'
r12 = 1074036200
R4 = 1073962336 R2 = 1
Type_initEnum @ 169
Type_initEnum 'M' 'h'
r12 = 1074036200
R4 = 1074400544 R2 = 2
Type_initEnum @ 169
Type_initEnum 'T' 'h'
r12 = 1074036200
R4 = 1074947288 R2 = 3
Type_initEnum @ 169
Type_initEnum 'H' 'h'
r12 = 1074036200
R4 = 1074947336 R2 = 4
Type_initEnum @ 169
Type_initEnum 'C' 'h'
r12 = 1074036200
R4 = 1074947392 R2 = 5
Type_initEnum @ 169
Type_initEnum 'C' 'h'
r12 = 1074036200
R4 = 1074947392 R2 = 6
Type_initEnum @ 169
t$hxd_$EventKind    <-- issues happens in init-code for this enum
Type_initEnum @ 110
Type_initEnum @ 135
Type_initEnum @ 140
Type_initEnum @ 142
r6->size: 13
Type_initEnum 'E' 'h'
r12 = 1074036488
R4 = 129365776526064 R2 = 0
Type_initEnum @ 169
Type_initEnum 'E' 'h'
r12 = 1074036488
R4 = 1073962464 R2 = 1
Type_initEnum @ 169
Type_initEnum 'E' 'h'
r12 = 1074036488
R4 = 1074400584 R2 = 2
Type_initEnum @ 169
Type_initEnum 'E' 'h'
r12 = 1074036488
R4 = 1074948024 R2 = 3
Type_initEnum @ 169
Type_initEnum 'E' 'h'
r12 = 1074036488
R4 = 1074948072 R2 = 4
Type_initEnum @ 169
Type_initEnum 'E' 'h'
r12 = 1074036488
R4 = 1074948128 R2 = 5
Type_initEnum @ 169
Type_initEnum 'E' 'h'
r12 = 1074036488
R4 = 1074948128 R2 = 6
Type_initEnum @ 169
Type_initEnum 'E' 'E'
r12 = 1074036488
R4 = 1074933416 R2 = 7
Type_initEnum @ 169
Type_initEnum 'E' 'E'
r12 = 1074036488
R4 = 8 R2 = 1695909888
AddressSanitizer:DEADLYSIGNAL
=================================================================
==18292==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000018 (pc 0x567e642c78e8 bp 0x7ffd00d83a10 sp 0x7ffd00d83970 T0)
==18292==The signal is caused by a READ memory access.
==18292==Hint: address points to the zero page.
    #0 0x567e642c78e8 in hl_types_ArrayObj_push /tmp/build/hl/types/ArrayObj.c:134:11
    #1 0x567e647c50ba in Type_initEnum /tmp/build/_std/Type.c:168:8
    #2 0x567e64f2c037 in fun$init /tmp/build/hl/init.c:10993:8
    #3 0x567e64fee2f3 in hl_entry_point /tmp/build/plastyx.c:1019:2
    #4 0x567e642770bd in hlc_static_call /tmp/build/hl/reflect.c:17:4
    #5 0x75a851235993 in hl_call_method /tmp/hashlink-1.14/src/std/fun.c:197:8
    #6 0x75a851235c7e in hl_dyn_call /tmp/hashlink-1.14/src/std/fun.c:244:9
    #7 0x75a851236ad9 in hl_dyn_call_safe /tmp/hashlink-1.14/src/std/fun.c:473:8
    #8 0x567e6427695d in main /tmp/hashlink/hashlink-1.14_debug/include/hlc_main.c:158:8
    #9 0x75a850fb6e07 in __libc_start_call_main /usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #10 0x75a850fb6ecb in __libc_start_main /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:360:3
    #11 0x567e64141c34 in _start (/tmp/build/main+0x58fc34) (BuildId: c9a8d7f974e483bc7604dce3b4bf887028ed0aec)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /tmp/build/hl/types/ArrayObj.c:134:11 in hl_types_ArrayObj_push
==18292==ABORTING

The characters printed out above originate from my instrumentation in

hl__Enum Type_initEnum(hl_type* r0,hl_type* r1) : 
[...]
    if( r12 == NULL ) hl_null_access();
    printf("Type_initEnum '%s' '%s'\n", r8, r3->_hx___ename__->bytes);
    printf("r12 = %lu\n", (uint64_t)r12);
    r15 = hl_types_ArrayObj_push(r12,((vdynamic*)r9));
    PRINT_LINE("Type_initEnum");
    goto label$9fea9d9_3_29;
[...]

And here the generated hl_types_ArrayObj_push function:

int hl_types_ArrayObj_push(hl__types__ArrayObj r0,vdynamic* r1) {
    varray *r4, *r6;
    int r2, r5;
    r2 = r0->length;
    r4 = r0->array;
    //if(r4 == 0){
        printf("R4 = %lu R2 = %u\n", (uint64_t)r4, r2);
    //}
    r5 = r4->size;
    if( r5 != r2 ) goto label$1b258ef_5_6;
    hl_types_ArrayObj___expand(r0,r2);
    goto label$1b258ef_5_9;
    label$1b258ef_5_6:
    r5 = r0->length;
    ++r5;
    r0->length = r5;
    label$1b258ef_5_9:
    r6 = r0->array;
    ((vdynamic**)(r6 + 1))[r2] = r1;
    r5 = r0->length;
    return r5;
}

To ensure, the issue is not related to my code, which includes native extensions, I tried to reproduce with the heaps.io-hello-world-project. ASAN fires for this as well directly on startup and it is also an out-of-bounds READ but different location:

AddressSanitizer:DEADLYSIGNAL
=================================================================
==19477==ERROR: AddressSanitizer: SEGV on unknown address 0x00004020000d (pc 0x7c958e11ab30 bp 0x7ffc084c5390 sp 0x7ffc084c5368 T0)
==19477==The signal is caused by a READ memory access.
    #0 0x7c958e11ab30 in __sanitizer_internal_memmove /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_libc.cpp:75
    #1 0x7c958dfa4eb8 in hl_bytes_blit (/tmp/hashlink/tmp/hashlink-1.14/build//bin/libhl.so.1+0x69eb8) (BuildId: 771e3fba1794b2b8e54a9f23982d5d7ce0bef4ce)
    #2 0x60572e9f914d in hl_types_ArrayBytes_hl_UI16___expand hl/types/ArrayBytes_hl_UI16.c:1051
    #3 0x60572e9f4fb6 in hl_types_ArrayBytes_hl_UI16_push hl/types/ArrayBytes_hl_UI16.c:186
    #4 0x60572ea1d77b in h3d_impl_MemoryManager_initIndexes h3d/impl/MemoryManager.c:115
    #5 0x60572ea1d57d in h3d_impl_MemoryManager_init h3d/impl/MemoryManager.c:74
    #6 0x60572ea14fe6 in h3d_Engine_onCreate h3d/Engine.c:505
    #7 0x60572ed17631 in h3d_impl_GlDriver_init__$1 h3d/impl/GlDriver.c:5603
    #8 0x60572ebfbc18 in haxe_Timer_delay__$1 haxe/Timer.c:70
    #9 0x60572ebfb880 in haxe_Timer_new__$1 haxe/Timer.c:21
    #10 0x60572ebf77b4 in sys_thread_EventLoop_progress sys/thread/EventLoop.c:232
    #11 0x60572ee5b32f in hxd_System_runMainLoop hxd/System.c:312
    #12 0x60572ebfbc49 in haxe_Timer_delay__$1 haxe/Timer.c:70
    #13 0x60572ebfb880 in haxe_Timer_new__$1 haxe/Timer.c:21
    #14 0x60572ebf91a5 in sys_thread_EventLoop_loop sys/thread/EventLoop.c:491
    #15 0x60572f08c3d5 in sys_thread__Thread_Thread_Impl__processEvents sys/thread/_Thread/Thread_Impl_.c:43
    #16 0x60572f109cba in fun$init hl/init.c:11886
    #17 0x60572f16d70b in hl_entry_point /tmp/repro3/build/Main.c:521
    #18 0x60572f10c96c in hlc_static_call hl/reflect.c:17
    #19 0x7c958dfab1e9 in hl_call_method (/tmp/hashlink/tmp/hashlink-1.14/build//bin/libhl.so.1+0x701e9) (BuildId: 771e3fba1794b2b8e54a9f23982d5d7ce0bef4ce)
    #20 0x7c958dfab4d0 in hl_dyn_call (/tmp/hashlink/tmp/hashlink-1.14/build//bin/libhl.so.1+0x704d0) (BuildId: 771e3fba1794b2b8e54a9f23982d5d7ce0bef4ce)
    #21 0x7c958dfac2f4 in hl_dyn_call_safe (/tmp/hashlink/tmp/hashlink-1.14/build//bin/libhl.so.1+0x712f4) (BuildId: 771e3fba1794b2b8e54a9f23982d5d7ce0bef4ce)
    #22 0x60572e9d217a in main /tmp/hashlink/tmp/hashlink-1.14/build//../src/hlc_main.c:158
    #23 0x7c958da59e07  (/usr/lib/libc.so.6+0x25e07) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #24 0x7c958da59ecb in __libc_start_main (/usr/lib/libc.so.6+0x25ecb) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #25 0x60572e9d19b4 in _start (/tmp/repro3/build/Main+0x4089b4) (BuildId: 2eaee664e7adb445e3b705f611a49f14b8d70801)

The Main.hx is simply the hello-world-heaps example:

class Main extends hxd.App {
    override function init() {
        var tf = new h2d.Text(hxd.res.DefaultFont.get(), s2d);
        tf.text = "Hello World !";
    }
    static function main() {
        new Main();
    }
}

Compiled to hl/c like this:

haxe --main Main -lib heaps -lib hlsdl -debug -hl build/Main.c

And natively compiled like so:

gcc -o Main Main.c -I . -I ${HL}/../src -L ${HL}/bin/ -lhl -g -lSDL2 ${HL}/bin/uv.hdll ${HL}/bin/sdl.hdll ${HL}/bin/fmt.hdll ${HL}/bin/ui.hdll -luv -fsanitize=address -lSDL2 -lm

Where HL points to the hashlink-1.14 build/source.

The hello-world Haxe example runs smoothly though.