obsproject / obs-studio

OBS Studio - Free and open source software for live streaming and screen recording
https://obsproject.com
GNU General Public License v2.0
60.25k stars 7.98k forks source link

Linux: RNNoise segfault (symbol clashing) #3561

Closed fzwoch closed 4 years ago

fzwoch commented 4 years ago

Platform

Operating system and version: Linux Debian Sid OBS Studio version: 26.0.0

Expected Behavior

Should be able to use RNNoise noise suppression filter for any audio source.

Current Behavior

Using RNNoise noise suppression filter results in a segmentation fault.

Steps to Reproduce

  1. Manually build OBS Studio
  2. Start OBS Studio
  3. Go to any audio source -> Filters -> Add (+) -> Noise Suppresion -> OK

Additional information

0x00007ffff27c4a25 in _celt_autocorr () from /lib/x86_64-linux-gnu/libcodec2.so.0.9
(gdb) bt
#0  0x00007ffff27c4a25 in _celt_autocorr () at /lib/x86_64-linux-gnu/libcodec2.so.0.9
#1  0x00007ffff27c4d2a in pitch_downsample () at /lib/x86_64-linux-gnu/libcodec2.so.0.9
#2  0x00007fff475e13b5 in compute_frame_features (in=0x7fff46ac3520, features=0x7fff46ac3470, Exp=0x7fff46ac33b0, Ep=0x7fff46ac3350, Ex=0x7fff46ac32f0, P=0x7fff46ac6240, X=0x7fff46ac5330, st=0x555556fa7160)
    at ../plugins/obs-filters/rnnoise/src/denoise.c:326
#3  rnnoise_process_frame (st=0x555556fa7160, out=0x555556f7cc60, in=<optimized out>) at ../plugins/obs-filters/rnnoise/src/denoise.c:471
#4  0x00007fff475eff6c in process_rnnoise (ng=0x555556fa1da0) at ../plugins/obs-filters/noise-suppress-filter.c:343
#5  process (ng=<optimized out>) at ../plugins/obs-filters/noise-suppress-filter.c:392
#6  noise_suppress_filter_audio (data=0x555556fa1da0, audio=<optimized out>) at ../plugins/obs-filters/noise-suppress-filter.c:468
#7  0x00007ffff5c85b13 in filter_async_audio (in=<optimized out>, source=0x555556ad18a0) at ../libobs/obs-source.c:3068
#8  obs_source_output_audio (source=0x555556ad18a0, audio=audio@entry=0x7fff46acbea0) at ../libobs/obs-source.c:3246
#9  0x00007fffd8149da5 in pulse_stream_read (p=<optimized out>, nbytes=<optimized out>, userdata=0x555556acb280) at ../plugins/linux-pulseaudio/pulse-input.c:217
#10 0x00007ffff02f1b2d in  () at /lib/x86_64-linux-gnu/libpulse.so.0
#11 0x00007fffee129bf5 in  () at /usr/lib/x86_64-linux-gnu/pulseaudio/libpulsecommon-13.0.so
#12 0x00007fffee12c5ab in  () at /usr/lib/x86_64-linux-gnu/pulseaudio/libpulsecommon-13.0.so
#13 0x00007fffee12c966 in  () at /usr/lib/x86_64-linux-gnu/pulseaudio/libpulsecommon-13.0.so
#14 0x00007fffee12d1ba in  () at /usr/lib/x86_64-linux-gnu/pulseaudio/libpulsecommon-13.0.so
#15 0x00007ffff03071a3 in pa_mainloop_dispatch () at /lib/x86_64-linux-gnu/libpulse.so.0
#16 0x00007ffff03074ce in pa_mainloop_iterate () at /lib/x86_64-linux-gnu/libpulse.so.0
#17 0x00007ffff0307570 in pa_mainloop_run () at /lib/x86_64-linux-gnu/libpulse.so.0
#18 0x00007ffff0315439 in  () at /lib/x86_64-linux-gnu/libpulse.so.0
#19 0x00007fffee13c268 in  () at /usr/lib/x86_64-linux-gnu/pulseaudio/libpulsecommon-13.0.so
#20 0x00007ffff4cfbea7 in start_thread (arg=<optimized out>) at pthread_create.c:477
#21 0x00007ffff4c2beaf in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Notice that in the callstack pitch_downsample() symbol is called from /lib/x86_64-linux-gnu/libcodec2.so.0.9. That library is probably pulled in by FFMPEG. The intention probably was to use the symbol from plugins/obs-filters/rnnoise/src/pitch.c.

So it seems like libcodec2.so and OBS Studio share portions of code and there are duplicate symbol names in libcodec2.so and OBS Studio executable. I'm unsure about the symbol loading strategy of the dynamic loader on Linux - but it seems like the symbol from the loaded shared library gets precedence over the internal symbol in OBS Studio.

Since the symbols can be incompatible to each and OBS Studio was compiled with a different expectation than libcodec2.so delivers a segmentation fault is likely..

kkartaltepe commented 4 years ago

I think its fairly safe (runs on my machine) to try and setup this library to only reference its own symbols via something like

diff --git a/plugins/obs-filters/CMakeLists.txt b/plugins/obs-filters/CMakeLists.txt
index 0b827209e..5653f4552 100644
--- a/plugins/obs-filters/CMakeLists.txt
+++ b/plugins/obs-filters/CMakeLists.txt
@@ -85,6 +85,7 @@ target_link_libraries(obs-filters
        libobs
        ${obs-filters_PLATFORM_DEPS}
        ${obs-filters_NOISEREDUCTION_LIBRARIES})
+target_link_options(obs-filters PRIVATE "-Wl,-Bsymbolic-functions")
 set_target_properties(obs-filters PROPERTIES FOLDER "plugins")

 install_obs_plugin_with_data(obs-filters data)

If that works I think we can consider carrying it upstream.

fzwoch commented 4 years ago

Confirmed, works for me too.

Maybe worth if guarding for Linux or Linux and macOS only?

kkartaltepe commented 4 years ago

Can you let me know if this alternate patch works too? (My platform doesnt have the conflicting libcodec2)

diff --git a/plugins/obs-filters/CMakeLists.txt b/plugins/obs-filters/CMakeLists.txt
index 0b827209e..e15cff488 100644
--- a/plugins/obs-filters/CMakeLists.txt
+++ b/plugins/obs-filters/CMakeLists.txt
@@ -20,6 +20,7 @@ if(NOT LIBRNNOISE_FOUND)
                "rnnoise/src/*.h"
                "rnnoise/include/*.h")
        add_definitions(-DCOMPILE_OPUS)
+       set_property(SOURCE ${rnnoise_SOURCES} PROPERTY COMPILE_FLAGS "-fno-semantic-interposition")
        include_directories("rnnoise/include")
        source_group("rnnoise" FILES ${rnnoise_SOURCES})
        set(LIBRNNOISE_FOUND TRUE)
@@ -85,6 +86,7 @@ target_link_libraries(obs-filters
        libobs
        ${obs-filters_PLATFORM_DEPS}
        ${obs-filters_NOISEREDUCTION_LIBRARIES})
+# target_link_options(obs-filters PRIVATE "-Wl,-Bsymbolic-functions")
 set_target_properties(obs-filters PROPERTIES FOLDER "plugins")

 install_obs_plugin_with_data(obs-filters data)
fzwoch commented 4 years ago

Nope, that one does not work. Then it will still call into libcodec2.so.

fzwoch commented 4 years ago

This one seemed to work for me though:

diff --git a/plugins/obs-filters/CMakeLists.txt b/plugins/obs-filters/CMakeLists.txt
index 0b827209..44563f40 100644
--- a/plugins/obs-filters/CMakeLists.txt
+++ b/plugins/obs-filters/CMakeLists.txt
@@ -20,6 +20,7 @@ if(NOT LIBRNNOISE_FOUND)
                "rnnoise/src/*.h"
                "rnnoise/include/*.h")
        add_definitions(-DCOMPILE_OPUS)
+       set_property(SOURCE ${rnnoise_SOURCES} PROPERTY COMPILE_FLAGS "-fvisibility=protected")
        include_directories("rnnoise/include")
        source_group("rnnoise" FILES ${rnnoise_SOURCES})
        set(LIBRNNOISE_FOUND TRUE)