HEATSHRINK_MIN_WINDOW_BITS defaults to 4, so this call to heatshrink_decoder_alloc():
|
heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, |
|
HEATSHRINK_MIN_WINDOW_BITS, 4); |
will always return NULL due to the lookahead_sz2 >= window_sz2 condition.
|
if ((window_sz2 < HEATSHRINK_MIN_WINDOW_BITS) || |
|
(window_sz2 > HEATSHRINK_MAX_WINDOW_BITS) || |
|
(input_buffer_size == 0) || |
|
(lookahead_sz2 < HEATSHRINK_MIN_LOOKAHEAD_BITS) || |
|
(lookahead_sz2 >= window_sz2)) { |
|
return NULL; |
Then because HEATSHRINK_FREE() doesn't use SZ:
|
#if HEATSHRINK_DYNAMIC_ALLOC |
|
/* Optional replacement of malloc/free */ |
|
#define HEATSHRINK_MALLOC(SZ) malloc(SZ) |
|
#define HEATSHRINK_FREE(P, SZ) free(P) |
|
#else |
heatshrink_decoder_free() would be optimized (test script default to -O3) to never touch the NULL hsd pointer.
|
void heatshrink_decoder_free(heatshrink_decoder *hsd) { |
|
size_t buffers_sz = (1 << hsd->window_sz2) + hsd->input_buffer_size; |
|
size_t sz = sizeof(heatshrink_decoder) + buffers_sz; |
|
HEATSHRINK_FREE(hsd, sz); |
|
(void)sz; /* may not be used by free */ |
This explains why running tests with default option doesn't trigger segfault.
But we can still observe it under -fsanitize=address -O0:
* Suite decoding:
.....AddressSanitizer:DEADLYSIGNAL
=================================================================
==196809==ERROR: AddressSanitizer: SEGV on unknown address 0x00000000000d (pc 0x557860fc2065 bp 0x7ffe9474c6d0 sp 0x7ffe9474c690 T0)
==196809==The signal is caused by a READ memory access.
==196809==Hint: address points to the zero page.
#0 0x557860fc2065 in heatshrink_decoder_free /home/user/heatshrink/heatshrink_decoder.c:73:31
#1 0x557860fb5992 in decoder_sink_should_reject_null_input_pointer /home/user/heatshrink/test_heatshrink_dynamic.c:289:5
#2 0x557860fb4956 in decoding /home/user/heatshrink/test_heatshrink_dynamic.c:622:14
#3 0x557860fbd583 in greatest_run_suite /home/user/heatshrink/test_heatshrink_dynamic.c:1008:1
#4 0x557860fbd279 in main /home/user/heatshrink/test_heatshrink_dynamic.c:1013:5
#5 0x14828f53e6c0 in __libc_start_call_main /usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:59:16
#6 0x14828f53e7f8 in __libc_start_main /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:360:3
#7 0x557860e560d4 in _start (/home/user/heatshrink/test_heatshrink_dynamic+0x300d4) (BuildId: 1f5d54bb0d03513b124d476de0068ff1b8df1fa8)
HEATSHRINK_MIN_WINDOW_BITSdefaults to 4, so this call toheatshrink_decoder_alloc():heatshrink/test_heatshrink_dynamic.c
Lines 285 to 286 in 7d419e1
will always return NULL due to the
lookahead_sz2 >= window_sz2condition.heatshrink/heatshrink_decoder.c
Lines 52 to 57 in 7d419e1
Then because
HEATSHRINK_FREE()doesn't useSZ:heatshrink/heatshrink_config.h
Lines 9 to 13 in 7d419e1
heatshrink_decoder_free()would be optimized (test script default to-O3) to never touch the NULLhsdpointer.heatshrink/heatshrink_decoder.c
Lines 72 to 76 in 7d419e1
This explains why running tests with default option doesn't trigger segfault.
But we can still observe it under
-fsanitize=address -O0: