Use save_char instead of manually adding the null terminator - the buffer might not have grown enough to fit it, causing an out-of-bounds write.
Added test case to catch this.
It used to crash when running with ASAN like this:
=================================================================
==171884==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50c0000000c0 at pc 0x5d58b5be50ef bp 0x7fff24339b10 sp 0x7fff24339b00
WRITE of size 1 at 0x50c0000000c0 thread T0
#0 0x5d58b5be50ee in scan_decimal src/be_lexer.c:357
#1 0x5d58b5be55f5 in scan_numeral src/be_lexer.c:375
#2 0x5d58b5bea774 in lexer_next src/be_lexer.c:781
#3 0x5d58b5bebe64 in be_lexer_scan_next src/be_lexer.c:838
#4 0x5d58b5c206f5 in call_expr src/be_parser.c:811
#5 0x5d58b5c220f7 in suffix_expr src/be_parser.c:927
#6 0x5d58b5c25d5d in sub_expr src/be_parser.c:1083
#7 0x5d58b5c26774 in walrus_expr src/be_parser.c:1112
#8 0x5d58b5c27004 in expr src/be_parser.c:1138
#9 0x5d58b5c24385 in assign_expr src/be_parser.c:1010
#10 0x5d58b5c27043 in expr_stmt src/be_parser.c:1143
#11 0x5d58b5c32ad5 in statement src/be_parser.c:1779
#12 0x5d58b5c332cb in stmtlist src/be_parser.c:1791
#13 0x5d58b5c33b8f in mainfunc src/be_parser.c:1812
#14 0x5d58b5c34177 in be_parser_source src/be_parser.c:1830
#15 0x5d58b5bbafa8 in m_parser src/be_exec.c:166
#16 0x5d58b5bb9572 in be_execprotected src/be_exec.c:122
#17 0x5d58b5bbb413 in be_protectedparser src/be_exec.c:183
#18 0x5d58b5bbbce8 in fileparser src/be_exec.c:228
#19 0x5d58b5bbc46e in be_loadmode src/be_exec.c:272
#20 0x5d58b5c8e94d in doscript default/berry.c:215
#21 0x5d58b5c8eb21 in load_script default/berry.c:233
#22 0x5d58b5c90309 in analysis_args default/berry.c:396
#23 0x5d58b5c903e5 in main default/berry.c:404
#24 0x765e67c43ccf (/usr/lib/libc.so.6+0x25ccf) (BuildId: c0caa0b7709d3369ee575fcd7d7d0b0fc48733af)
#25 0x765e67c43d89 in __libc_start_main (/usr/lib/libc.so.6+0x25d89) (BuildId: c0caa0b7709d3369ee575fcd7d7d0b0fc48733af)
#26 0x5d58b5b60724 in _start (/tmp/berry/berry+0x18b724) (BuildId: 467e6084a589ea218e145696ffd370bf2f254090)
0x50c0000000c0 is located 0 bytes after 128-byte region [0x50c000000040,0x50c0000000c0)
allocated by thread T0 here:
#0 0x765e67ee007a in __interceptor_realloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:85
#1 0x5d58b5c02bf6 in be_realloc src/be_mem.c:141
#2 0x5d58b5be20f1 in save_char src/be_lexer.c:124
#3 0x5d58b5be2518 in save src/be_lexer.c:134
#4 0x5d58b5be4391 in scan_realexp src/be_lexer.c:295
#5 0x5d58b5be4ed7 in scan_decimal src/be_lexer.c:353
#6 0x5d58b5be55f5 in scan_numeral src/be_lexer.c:375
#7 0x5d58b5bea774 in lexer_next src/be_lexer.c:781
#8 0x5d58b5bebe64 in be_lexer_scan_next src/be_lexer.c:838
#9 0x5d58b5c206f5 in call_expr src/be_parser.c:811
#10 0x5d58b5c220f7 in suffix_expr src/be_parser.c:927
#11 0x5d58b5c25d5d in sub_expr src/be_parser.c:1083
#12 0x5d58b5c26774 in walrus_expr src/be_parser.c:1112
#13 0x5d58b5c27004 in expr src/be_parser.c:1138
#14 0x5d58b5c24385 in assign_expr src/be_parser.c:1010
#15 0x5d58b5c27043 in expr_stmt src/be_parser.c:1143
#16 0x5d58b5c32ad5 in statement src/be_parser.c:1779
#17 0x5d58b5c332cb in stmtlist src/be_parser.c:1791
#18 0x5d58b5c33b8f in mainfunc src/be_parser.c:1812
#19 0x5d58b5c34177 in be_parser_source src/be_parser.c:1830
#20 0x5d58b5bbafa8 in m_parser src/be_exec.c:166
#21 0x5d58b5bb9572 in be_execprotected src/be_exec.c:122
#22 0x5d58b5bbb413 in be_protectedparser src/be_exec.c:183
#23 0x5d58b5bbbce8 in fileparser src/be_exec.c:228
#24 0x5d58b5bbc46e in be_loadmode src/be_exec.c:272
#25 0x5d58b5c8e94d in doscript default/berry.c:215
#26 0x5d58b5c8eb21 in load_script default/berry.c:233
#27 0x5d58b5c90309 in analysis_args default/berry.c:396
#28 0x5d58b5c903e5 in main default/berry.c:404
#29 0x765e67c43ccf (/usr/lib/libc.so.6+0x25ccf) (BuildId: c0caa0b7709d3369ee575fcd7d7d0b0fc48733af)
SUMMARY: AddressSanitizer: heap-buffer-overflow src/be_lexer.c:357 in scan_decimal
Shadow bytes around the buggy address:
0x50bffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x50bffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x50bfffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x50bfffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x50c000000000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
=>0x50c000000080: 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa fa
0x50c000000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50c000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50c000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50c000000280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50c000000300: 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
==171884==ABORTING
Use
save_char
instead of manually adding the null terminator - the buffer might not have grown enough to fit it, causing an out-of-bounds write.Added test case to catch this.
It used to crash when running with ASAN like this: