edubart / nelua-lang

Minimal, efficient, statically-typed and meta-programmable systems programming language heavily inspired by Lua, which compiles to C and native code.
https://nelua.io
MIT License
1.99k stars 64 forks source link

heap-use-after-free bug when code run with -SVt flags #219

Closed stefanos82 closed 1 year ago

stefanos82 commented 1 year ago

Nelua version:

Nelua 0.2.0-dev
Build number: 1547
Git date: 2023-03-26 10:04:34 -0300
Git hash: e084bf1cc8a5651c9fdd96bc4205a890e5ab1fca
Semantic version: 0.2.0-dev.1547+e084bf1c
Copyright (C) 2019-2022 Eduardo Bart (https://nelua.io/)

Nelua code:

require 'os'

do
  -----------------------------------------------
  -- Another example is:                        -
  -- local year = tointeger(os.date('%Y'))      -
  -----------------------------------------------

  local year = tonumber(os.date('%Y'), 10)
  print(year)
  ##[[
  after_inference(function()
    print(string.format("year.type: %s", year.type))
  end)
  ]]
end

Where is my code wrong exactly, that the compiler to throw an error?

stefanos@debian:nelua $ nelua -SVt tonumber.nelua 
using config file '/home/stefanos/.config/nelua/neluacfg.lua'
startup      36.8 ms
year.type: int64
parse        33.2 ms
preprocess   20.1 ms
analyze      106.2 ms
generate     15.5 ms
using cached generated /home/stefanos/.cache/nelua/tonumber.c
using cached binary /home/stefanos/.cache/nelua/tonumber
compile      0.3 ms
/home/stefanos/.cache/nelua/tonumber 
=================================================================
==39881==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000030 at pc 0x7f3781626ccf bp 0x7ffe1b9590b0 sp 0x7ffe1b958870
WRITE of size 4 at 0x602000000030 thread T0
    #0 0x7f3781626cce in __interceptor_memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:899
    #1 0x56280b6706f6 in nelua_memory_copy /home/stefanos/.cache/nelua/tonumber.c:465
    #2 0x56280b6706f6 in nelua_nlstring_copy /home/stefanos/.cache/nelua/tonumber.c:1396
    #3 0x56280b671869 in nelua_os_date_1 /home/stefanos/.cache/nelua/tonumber.c:1458
    #4 0x56280b671a14 in nelua_main /home/stefanos/.cache/nelua/tonumber.c:1467
    #5 0x56280b66f826 in main /home/stefanos/.cache/nelua/tonumber.c:1296
    #6 0x7f3780df3189 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #7 0x7f3780df3244 in __libc_start_main_impl ../csu/libc-start.c:381
    #8 0x56280b65c2e0 in _start (/home/stefanos/.cache/nelua/tonumber+0x112e0) (BuildId: dfd31633d0b71cb7233b4e7b28cd5fbe300c2ff9)

0x602000000030 is located 0 bytes inside of 5-byte region [0x602000000030,0x602000000035)
freed by thread T0 here:
    #0 0x7f3781690298 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52
    #1 0x56280b66dd76 in nelua_GeneralAllocator_dealloc /home/stefanos/.cache/nelua/tonumber.c:573
    #2 0x56280b66dd76 in nelua_GC_sweep /home/stefanos/.cache/nelua/tonumber.c:1212
    #3 0x56280b66e0c2 in nelua_GC_collect /home/stefanos/.cache/nelua/tonumber.c:1226
    #4 0x56280b66e5dd in nelua_GC_step /home/stefanos/.cache/nelua/tonumber.c:1237
    #5 0x56280b66f2e0 in nelua_GC_register /home/stefanos/.cache/nelua/tonumber.c:1271
    #6 0x56280b66f94d in nelua_GCAllocator_alloc_1 /home/stefanos/.cache/nelua/tonumber.c:1308
    #7 0x56280b66f97b in nelua_GCAllocator_xalloc_1 /home/stefanos/.cache/nelua/tonumber.c:1312
    #8 0x56280b6705f8 in nelua_nlstring_copy /home/stefanos/.cache/nelua/tonumber.c:1395
    #9 0x56280b671869 in nelua_os_date_1 /home/stefanos/.cache/nelua/tonumber.c:1458
    #10 0x56280b671a14 in nelua_main /home/stefanos/.cache/nelua/tonumber.c:1467
    #11 0x56280b66f826 in main /home/stefanos/.cache/nelua/tonumber.c:1296
    #12 0x7f3780df3189 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

previously allocated by thread T0 here:
    #0 0x7f37816915cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x56280b66f91d in nelua_GeneralAllocator_alloc_1 /home/stefanos/.cache/nelua/tonumber.c:555
    #2 0x56280b66f91d in nelua_GCAllocator_alloc_1 /home/stefanos/.cache/nelua/tonumber.c:1307
    #3 0x56280b66f97b in nelua_GCAllocator_xalloc_1 /home/stefanos/.cache/nelua/tonumber.c:1312
    #4 0x56280b6705f8 in nelua_nlstring_copy /home/stefanos/.cache/nelua/tonumber.c:1395
    #5 0x56280b671869 in nelua_os_date_1 /home/stefanos/.cache/nelua/tonumber.c:1458
    #6 0x56280b671a14 in nelua_main /home/stefanos/.cache/nelua/tonumber.c:1467
    #7 0x56280b66f826 in main /home/stefanos/.cache/nelua/tonumber.c:1296
    #8 0x7f3780df3189 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

SUMMARY: AddressSanitizer: heap-use-after-free ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:899 in __interceptor_memcpy
Shadow bytes around the buggy address:
  0x601ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x601ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x601ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x601fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x601fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x602000000000: fa fa 00 07 fa fa[fd]fa fa fa 00 00 fa fa 00 fa
  0x602000000080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x602000000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x602000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x602000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x602000000280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==39881==ABORTING
run          148.3 ms
total time   360.5 ms
edubart commented 1 year ago

I confirm this bug, I will investigate.

edubart commented 1 year ago

Looks like new changes in the AddressSanitizer made it incompatible with Nelua GC. Not just this program is crashing, but any program using the GC is crashing for me. I could fix with:

export ASAN_OPTIONS=detect_stack_use_after_return=0
nelua -SVt tonumber.nelua

Can you confirm if that works in your environment?

edubart commented 1 year ago

Related https://github.com/google/sanitizers/wiki/AddressSanitizerUseAfterReturn

The fake stack may be incompatible with some low-level code that uses certain assumptions about the stack memory layout. Code that takes an address of a local variable and assumes the variable is localed on the real stack. Implementations of C++ garbage collection may require special attention.

That is the problem, ASAN is enabling detect_stack_use_after_return by default in recent releases, and that option completly changes how the function stack works, and breaks the Nelua GC.

edubart commented 1 year ago

This was fixed in https://github.com/edubart/nelua-lang/commit/0805e0b8b75a85d9c67b7e558d9b87360d72c4d4 I opted to explicit disable that option when the environment variable ASAN_OPTIONS is not set.

stefanos82 commented 1 year ago

Looks like new changes in the AddressSanitizer made it incompatible with Nelua GC. Not just this program is crashing, but any program using the GC is crashing for me. I could fix with:

export ASAN_OPTIONS=detect_stack_use_after_return=1
nelua -SVt tonumber.nelua

Can you confirm if that works in your environment?

Under

Nelua 0.2.0-dev
Build number: 1547
Git date: 2023-03-26 10:04:34 -0300
Git hash: e084bf1cc8a5651c9fdd96bc4205a890e5ab1fca
Semantic version: 0.2.0-dev.1547+e084bf1c
Copyright (C) 2019-2022 Eduardo Bart (https://nelua.io/)

still crashes.

With the latest changes you pushed, I now get a different kind of error:

nelua -SVt tonumber.nelua 
using config file '/home/stefanos/.config/nelua/neluacfg.lua'
startup      31.8 ms
year.type: int64
parse        35.4 ms
preprocess   17.9 ms
analyze      99.2 ms
generate     14.7 ms
generated /home/stefanos/.cache/nelua/tonumber.c
gcc -x c "/home/stefanos/.cache/nelua/tonumber.c" -x none -fwrapv -fno-strict-aliasing -Wall -Wextra -fsanitize=address,undefined -g -pipe -o "/home/stefanos/.cache/nelua/tonumber"
compile      404.8 ms
/home/stefanos/.cache/nelua/tonumber 
AddressSanitizer:DEADLYSIGNAL
=================================================================
==6754==ERROR: AddressSanitizer: SEGV on unknown address 0x7fa825e00000 (pc 0x5640a3b5b93e bp 0x7fffdb08cd30 sp 0x7fffdb08cc60 T0)
==6754==The signal is caused by a READ memory access.
    #0 0x5640a3b5b93e in nelua_GC_markptrs /home/stefanos/.cache/nelua/tonumber.c:1048
    #1 0x5640a3b5cc07 in nelua_GC_markstack /home/stefanos/.cache/nelua/tonumber.c:1131
    #2 0x5640a3b5cd6d in nelua_GC_mark /home/stefanos/.cache/nelua/tonumber.c:1142
    #3 0x5640a3b5eed4 in nelua_GC_collect /home/stefanos/.cache/nelua/tonumber.c:1225
    #4 0x5640a3b5f3fb in nelua_GC_step /home/stefanos/.cache/nelua/tonumber.c:1237
    #5 0x5640a3b600fe in nelua_GC_register /home/stefanos/.cache/nelua/tonumber.c:1271
    #6 0x5640a3b6076b in nelua_GCAllocator_alloc_1 /home/stefanos/.cache/nelua/tonumber.c:1308
    #7 0x5640a3b60799 in nelua_GCAllocator_xalloc_1 /home/stefanos/.cache/nelua/tonumber.c:1312
    #8 0x5640a3b61416 in nelua_nlstring_copy /home/stefanos/.cache/nelua/tonumber.c:1395
    #9 0x5640a3b62687 in nelua_os_date_1 /home/stefanos/.cache/nelua/tonumber.c:1458
    #10 0x5640a3b62832 in nelua_main /home/stefanos/.cache/nelua/tonumber.c:1467
    #11 0x5640a3b60644 in main /home/stefanos/.cache/nelua/tonumber.c:1296
    #12 0x7fa8276f2189 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #13 0x7fa8276f2244 in __libc_start_main_impl ../csu/libc-start.c:381
    #14 0x5640a3b4d2e0 in _start (/home/stefanos/.cache/nelua/tonumber+0x112e0) (BuildId: dc1a286c6ab872b79c2d9b36a47dad82f531c2a2)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/stefanos/.cache/nelua/tonumber.c:1048 in nelua_GC_markptrs
==6754==ABORTING

New nelua specs:

Nelua 0.2.0-dev
Build number: 1556
Git date: 2023-07-01 09:20:26 -0300
Git hash: 19a4183fe1432383226fe81bf3794ceadf6985ac
Semantic version: 0.2.0-dev.1556+19a4183f
Copyright (C) 2019-2022 Eduardo Bart (https://nelua.io/)

Edit: I forgot to mention that I repeated

export ASAN_OPTIONS=detect_stack_use_after_return=1
nelua -SVt tonumber.nelua

which probably caused the crash.

Is this an expected crashing behavior @edubart ?

edubart commented 1 year ago

Sorry I made a typo, should have been detect_stack_use_after_return=0 in the comment. When it's 1 the crash is expected. You should unset ASAN_OPTIONS in you environment after my recent changes.

stefanos82 commented 1 year ago

Yep, after I reopened my terminal and run nelua -SVt tonumber.nelua, it worked without any problem.

Well done :+1: