drowe67 / codec2

Open source speech codec designed for communications quality speech between 700 and 3200 bit/s. The main application is low bandwidth HF/VHF digital radio.
GNU Lesser General Public License v2.1
202 stars 32 forks source link

Enabling libasan causes failures during tests #43

Open tmiw opened 8 months ago

tmiw commented 8 months ago

@barjac reported an AddressSanitizer error during freedv-gui build:

[100%] Built target freedv_datac0c1_rx
make[1]: Leaving directory '/home/baz/build/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/build_linux'
/usr/bin/cmake -E cmake_progress_start /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/build_linux/CMakeFiles 0
+ cd src
+ export LD_LIBRARY_PATH=/home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/LPCNet/build_linux/src
+ LD_LIBRARY_PATH=/home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/LPCNet/build_linux/src
+ ./freedv_tx 2020 /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/LPCNet/wav/wia.wav -
+ ./freedv_rx 2020 - /dev/null
=================================================================
==36243==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffefa65e990 at pc 0x000000402ffb bp 0x7ffefa6593d0 sp 0x7ffefa6593c8
READ of size 8 at 0x7ffefa65e990 thread T0
    #0 0x402ffa in my_get_next_tx_char /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/src/freedv_tx.c:46
    #1 0x7f66ff6b3c02 in freedv_comptx_2020 /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/src/freedv_2020.c:174
    #2 0x7f66ff6a575c in freedv_comptx /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/src/freedv_api.c:389
    #3 0x7f66ff6a5ea5 in freedv_tx /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/src/freedv_api.c:329
    #4 0x40284d in main /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/src/freedv_tx.c:205
    #5 0x7f66ff47c736 in __libc_start_call_main (/lib64/libc.so.6+0x23736)
    #6 0x7f66ff47c7f4 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x237f4)
    #7 0x402ea0 in _start (/home/baz/build/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/build_linux/src/freedv_tx+0x402ea0)

Address 0x7ffefa65e990 is located in stack of thread T0 at offset 240 in frame
    #0 0x40231f in main /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/src/freedv_tx.c:59

  This frame has 3 object(s):
    [32, 36) 'opt_idx' (line 97)
    [48, 128) 'f2020' (line 66)
    [160, 256) 'my_cb_state' (line 187) <== Memory access at offset 240 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/src/freedv_tx.c:46 in my_get_next_tx_char
Shadow bytes around the buggy address:
  0x10005f4c3ce0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005f4c3cf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005f4c3d00: cb cb cb cb 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005f4c3d10: 00 00 00 00 f1 f1 f1 f1 04 f2 00 00 00 00 00 00
  0x10005f4c3d20: 00 00 00 00 f2 f2 f2 f2 f8 f8 f8 f8 f8 f8 f8 f8
=>0x10005f4c3d30: f8 f8[f8]f8 f3 f3 f3 f3 00 00 00 00 00 00 00 00
  0x10005f4c3d40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005f4c3d50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005f4c3d60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005f4c3d70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10005f4c3d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
==36243==ABORTING
frames decoded: 0  output speech samples: 0
+ cd /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864

Additionally, it appears a large number of ctests fail with AddressSanitizer enabled. Building with the following on an aarch64 Ubuntu VM:

$ CFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address cmake -DLPCNET_BUILD_DIR=../../LPCNet/build_linux -DUNITTEST=1 ..
$ make -j6
$ ASAN_OPTIONS=detect_odr_violation=0 make test
....
61% tests passed, 60 tests failed out of 155

Total Test time (real) = 252.27 sec

The following tests FAILED:
          1 - test_clang_format (Failed)
         13 - test_ch_papr (Failed)
         19 - test_COHPSK_modem_octave_port (Failed)
         20 - test_COHPSK_modem_AWGN_BER (Failed)
         21 - test_COHPSK_modem_freq_offset (Failed)
         23 - test_OFDM_modem_octave_port (Failed)
         24 - test_OFDM_modem_octave_port_Nc_31 (Failed)
         34 - test_OFDM_modem_700D (Failed)
         35 - test_OFDM_modem_700D_ldpc (Failed)
         36 - test_OFDM_modem_2020_ldpc (Failed)
         37 - test_OFDM_modem_AWGN_BER (Failed)
         38 - test_OFDM_modem_fading_BER (Failed)
         39 - test_OFDM_modem_phase_est_bw (Failed)
         41 - test_OFDM_modem_time_sync_2020 (Failed)
         42 - test_OFDM_modem_700E_AWGN (Failed)
         43 - test_OFDM_modem_2020B_AWGN (Failed)
         47 - test_OFDM_modem_datac1 (Failed)
         51 - test_OFDM_modem_datac13_octave (Failed)
         52 - test_OFDM_modem_datac4_ldpc_burst (Failed)
         53 - test_OFDM_modem_datac13_ldpc_burst (Failed)
         66 - test_freedv_api_1600 (Failed)
         68 - test_freedv_api_700D_backwards_compatability (Failed)
         69 - test_freedv_api_700D_speech (Failed)
         71 - test_freedv_api_700D_AWGN_BER (Failed)
         72 - test_freedv_api_700D_AWGN_BER_USECOMPLEX (Failed)
         76 - test_freedv_api_2020_to_ofdm_demod (Failed)
         77 - test_freedv_api_2020_from_ofdm_mod (Failed)
         78 - test_freedv_api_2020_awgn (Failed)
         79 - test_freedv_api_2020B_mpp (Failed)
         80 - test_freedv_api_2400A (Failed)
         81 - test_freedv_api_2400B (Failed)
         82 - test_freedv_api_800XA (Failed)
         83 - test_freedv_api_rawdata_800XA (Failed)
         84 - test_freedv_api_rawdata_2400A (Failed)
         85 - test_freedv_api_rawdata_2400B (Failed)
         86 - test_peak_levels (Failed)
         87 - test_peak_levels_lpcnet (Failed)
         98 - test_freedv_reliable_text_ideal_2020 (Failed)
        100 - test_freedv_reliable_text_fade_2020 (Failed)
        101 - test_memory_leak_FreeDV_1600_tx (Failed)
        102 - test_memory_leak_FreeDV_1600_rx (Failed)
        103 - test_memory_leak_FreeDV_700D_tx (Failed)
        104 - test_memory_leak_FreeDV_700D_rx (Failed)
        105 - test_memory_leak_FreeDV_700C_tx (Failed)
        106 - test_memory_leak_FreeDV_700C_rx (Failed)
        107 - test_memory_leak_FreeDV_FSK_LDPC_tx (Failed)
        108 - test_memory_leak_FreeDV_DATAC0_tx (Failed)
        109 - test_memory_leak_FreeDV_DATAC1_tx (Failed)
        110 - test_memory_leak_FreeDV_DATAC3_tx (Failed)
        111 - test_memory_leak_FreeDV_DATAC4_tx (Failed)
        112 - test_memory_leak_FreeDV_DATAC13_tx (Failed)
        113 - test_memory_leak_FreeDV_700E_tx (Failed)
        114 - test_memory_leak_FreeDV_2020_tx (Failed)
        115 - test_memory_leak_FreeDV_2020_rx (Failed)
        116 - test_memory_leak_FreeDV_2020B_tx (Failed)
        117 - test_memory_leak_FreeDV_2020B_rx (Failed)
        125 - test_vq_mbest (Failed)
        145 - test_freedv_data_raw_ofdm_datac4_burst_file (Failed)
        146 - test_freedv_data_raw_ofdm_datac13_burst_file (Failed)
        153 - test_demo_700d_python (Failed)
Errors while running CTest
Output from these tests are in: /home/parallels/freedv-gui/codec2/build_linux/Testing/Temporary/LastTest.log
Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely.
make: *** [Makefile:91: test] Error 8

(More tests were failing without disabling the ODR detection. I disabled above since it seemed like a false alarm.)

Example of one of the ctest failures:

test 69
    Start 69: test_freedv_api_700D_speech

69: Test command: /usr/bin/sh "-c" "cd /home/parallels/freedv-gui/codec2/build_linux/src;
                            ./freedv_tx 700D ../../raw/ve9qrp_10s.raw - |
                            ./ch - - --No -20 |
                            ./freedv_rx 700D - /dev/null --squelch -2 -vv"
69: Test timeout computed to be: 1500
69: ch: Fs: 8000 NodB: -20.00 foff: 0.00 Hz fading: 0 nhfdelay: 0 clip: 32767.00 ssbfilt: 1 complexout: 0
69: =================================================================
69: ==49821==ERROR: AddressSanitizer: stack-use-after-scope on address 0xffffce666d80 at pc 0xaaaab4232d98 bp 0xffffce662bb0 sp 0xffffce662bc0
69: READ of size 8 at 0xffffce666d80 thread T0
69:     #0 0xaaaab4232d94 in my_get_next_tx_char /home/parallels/freedv-gui/codec2/src/freedv_tx.c:46
69:     #1 0xffff841c6a40 in freedv_comptx_ofdm /home/parallels/freedv-gui/codec2/src/freedv_700.c:266
69:     #2 0xffff841bd2a4 in freedv_comptx /home/parallels/freedv-gui/codec2/src/freedv_api.c:375
69:     #3 0xffff841bd984 in freedv_tx /home/parallels/freedv-gui/codec2/src/freedv_api.c:329
69:     #4 0xaaaab42328f0 in main /home/parallels/freedv-gui/codec2/src/freedv_tx.c:205
69:     #5 0xffff83f273f8 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
69:     #6 0xffff83f274c8 in __libc_start_main_impl ../csu/libc-start.c:392
69:     #7 0xaaaab4232c2c in _start (/home/parallels/freedv-gui/codec2/build_linux/src/freedv_tx+0x2c2c)
69: 
69: Address 0xffffce666d80 is located in stack of thread T0 at offset 128 in frame
69:     #0 0xaaaab42321ac in main /home/parallels/freedv-gui/codec2/src/freedv_tx.c:59
69: 
69:   This frame has 3 object(s):
69:     [32, 36) 'opt_idx' (line 97)
69:     [48, 144) 'my_cb_state' (line 187) <== Memory access at offset 128 is inside this variable
69:     [176, 256) 'f2020' (line 66)
69: HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
69:       (longjmp and C++ exceptions *are* supported)
69: SUMMARY: AddressSanitizer: stack-use-after-scope /home/parallels/freedv-gui/codec2/src/freedv_tx.c:46 in my_get_next_tx_char
69: Shadow bytes around the buggy address:
69:   0x200ff9cccd60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69:   0x200ff9cccd70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69:   0x200ff9cccd80: cb cb cb cb 00 00 00 00 00 00 00 00 00 00 00 00
69:   0x200ff9cccd90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69:   0x200ff9cccda0: f1 f1 f1 f1 04 f2 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
69: =>0x200ff9cccdb0:[f8]f8 f2 f2 f2 f2 00 00 00 00 00 00 00 00 00 00
69:   0x200ff9cccdc0: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
69:   0x200ff9cccdd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69:   0x200ff9cccde0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69:   0x200ff9cccdf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69:   0x200ff9ccce00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69: Shadow byte legend (one shadow byte represents 8 application bytes):
69:   Addressable:           00
69:   Partially addressable: 01 02 03 04 05 06 07 
69:   Heap left redzone:       fa
69:   Freed heap region:       fd
69:   Stack left redzone:      f1
69:   Stack mid redzone:       f2
69:   Stack right redzone:     f3
69:   Stack after return:      f5
69:   Stack use after scope:   f8
69:   Global redzone:          f9
69:   Global init order:       f6
69:   Poisoned by user:        f7
69:   Container overflow:      fc
69:   Array cookie:            ac
69:   Intra object redzone:    bb
69:   ASan internal:           fe
69:   Left alloca redzone:     ca
69:   Right alloca redzone:    cb
69:   Shadow gap:              cc
69: ==49821==ABORTING
69: ch: SNR3k(dB):      nan  C/No....:      nan
69: ch: peak.....:     0.00  RMS.....:      nan   CPAPR.....:   nan 
69: ch: Nsamples.:        0  clipped.:      nan%  OutClipped:   nan%
69: frames decoded: 0  output speech samples: 0
69: 
69: =================================================================
69: ==49822==ERROR: LeakSanitizer: detected memory leaks
69: 
69: Direct leak of 9 byte(s) in 1 object(s) allocated from:
69:     #0 0xffffb5da8e30 in __interceptor_strdup ../../../../src/libsanitizer/asan/asan_interceptors.cpp:454
69:     #1 0xaaaac0d02888 in main /home/parallels/freedv-gui/codec2/src/ch.c:152
69:     #2 0xffffb59473f8 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
69:     #3 0xffffb59474c8 in __libc_start_main_impl ../csu/libc-start.c:392
69:     #4 0xaaaac0d0442c in _start (/home/parallels/freedv-gui/codec2/build_linux/src/ch+0x442c)
69: 
69: SUMMARY: AddressSanitizer: 9 byte(s) leaked in 1 allocation(s).
1/1 Test #69: test_freedv_api_700D_speech ......***Failed  Required regular expression not found. Regex=[frames decoded: 62  output speech samples: 7
]  1.11 sec

A quick look seems to indicate that it's due to the following definition for my_cb_state (in both freedv_rx and freedv_tx):

  } else {
    /* set up callback for txt msg chars */
    struct my_callback_state my_cb_state;
    sprintf(my_cb_state.tx_str, "cq cq cq hello world\r");
    my_cb_state.ptx_str = my_cb_state.tx_str;
    my_cb_state.calls = 0;
    freedv_set_callback_txt(freedv, NULL, &my_get_next_tx_char, &my_cb_state);
  }

This definition should be moved to the top of main() to eliminate this error.

drowe67 commented 8 months ago

Thanks @tmiw. If you think you have a quick fix and don't mind working on it pls feel free to go ahead and raise a PR.

tmiw commented 8 months ago

I created https://github.com/drowe67/codec2/pull/45 with what I was able to get to tonight. There's still something like 14 ctest failures with libasan on, but I suspect at least a couple are due to configuration issues on my end.

drowe67 commented 8 months ago

@tmiw - did any of the issues detected by AddressSanitizer cause any actual, real world issues, when running say freedv-gui? The changes in https://github.com/drowe67/codec2/pull/45 are minor tweaks mainly in test code for soon to be deprecated modes. All this code was running fine before this tool was applied.

We already have a suite of valgrind tests that I guess traps most memory issues.

tmiw commented 8 months ago

@tmiw - did any of the issues detected by AddressSanitizer cause any actual, real world issues, when running say freedv-gui? The changes in #45 are minor tweaks mainly in test code for soon to be deprecated modes. All this code was running fine before this tool was applied.

We already have a suite of valgrind tests that I guess traps most memory issues.

This originally kicked off because @barjac couldn't build with AddressSanitizer while attempting to debug a freedv-gui issue. Fixing that of course ended up kicking off additional issues (for example, the behavior apparently varying wildly depending on what locale freedv-gui is set to). Also, I'm fairly sure he was able to duplicate the crashes in freedv-gui without AddressSanitizer enabled at one point, too.

For reference, the most recent crashes seemed to be happening while trying to decode 800XA:

==261635==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000185637 at pc 0x7f503ae47971 bp 0x7f501a342f50 sp 0x7f501a342700
WRITE of size 8 at 0x602000185637 thread T23
    #0 0x7f503ae47970 in __interceptor_memset (/lib64/libasan.so.8+0x47970)
    #1 0x7f503acbc176 in fvhff_extract_frame_voice /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/src/freedv_vhf_framing.c:556
    #2 0x7f503acbef19 in fvhff_extract_frame /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/src/freedv_vhf_framing.c:738
    #3 0x7f503acbef19 in fvhff_deframe_bits /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/src/freedv_vhf_framing.c:855
    #4 0x7f503acbaf18 in freedv_comprx_fsk /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/src/freedv_fsk.c:671
    #5 0x7f503aca9d8a in freedv_comprx /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/codec2/src/freedv_api.c:806
    #6 0x4a45f8 in FreeDVReceiveStep::execute(std::shared_ptr<short>, int, int*) /home/baz/BLD/BLD_MgaX_FREEDV/freedv-git/SOURCES/freedv-1.9.9-202403221300-3e864/src/pipeline/FreeDVReceiveStep.cpp:100

(and earlier, were happening when decoding 2020 too)

There are also security implications, too. While admittedly unlikely, I imagine someone could come up with an OTA signal (or even just a WAV file that they convinced someone to play back in freedv-gui) that triggered one of the buffer overflows fixed by this PR and caused them to gain control of the user's system or something.

Anyway, that's a long way of saying that these modes should be fixed as long as the modes are still being used by something (e.g. freedv-gui). :)

drowe67 commented 8 months ago

@tmiw - I'm not convinced this is an issue we should be addressing at this time.

We made a decision at PLT that non-critical bugs - especially in deprecated modes - would not be addressed at this time. Fixing ctests in deprecated code (that pass just fine) is not where we should working right now.

As codec 2 lead I'm making the call to pause any further libcodec2 work in this area - if you'd like to discuss further please raise at PLT.