chriskohlhoff / asio

Asio C++ Library
http://think-async.com/Asio
4.92k stars 1.22k forks source link

Shared resources crash on MacOS caused by addons using different ASIO versions #975

Open tt2468 opened 2 years ago

tt2468 commented 2 years ago

I've been having some crash issues on MacOS when software plugins that link their own ASIO are installed. Basically, one plugin might statically link 1.12.1, while another will link 1.21.0. When one opens a socket, it's fine. But when the second plugin opens a socket, we get a SIGSEGV in the kqueue_reactor code. This only happens when there's an ASIO version mismatch between the two plugins. Keep in mind, these plugins do not share resources from our end. websocketpp and asio are both statically linked.

Here's a stacktrace:

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   obs-websocket.so                0x000000013afbfda2 asio::detail::kqueue_reactor::descriptor_state* asio::detail::object_pool<asio::detail::kqueue_reactor::descriptor_state>::alloc<bool>(bool) + 12 (object_pool.hpp:111) [inlined]
1   obs-websocket.so                0x000000013afbfda2 asio::detail::kqueue_reactor::allocate_descriptor_state() + 50 (kqueue_reactor.ipp:527)
2   obs-websocket.so                0x000000013afbfb1f asio::detail::kqueue_reactor::register_descriptor(int, asio::detail::kqueue_reactor::descriptor_state*&) + 5 (kqueue_reactor.ipp:144) [inlined]
3   obs-websocket.so                0x000000013afbfb1f asio::detail::reactive_socket_service_base::do_open(asio::detail::reactive_socket_service_base::base_implementation_type&, int, int, int, std::__1::error_code&) + 111 (reactive_socket_service_base.ipp:185)
4   obs-websocket.so                0x000000013afbf83f asio::detail::reactive_socket_service<asio::ip::tcp>::open(asio::detail::reactive_socket_service<asio::ip::tcp>::implementation_type&, asio::ip::tcp const&, std::__1::error_code&) + 33 (reactive_socket_service.hpp:127) [inlined]
5   obs-websocket.so                0x000000013afbf83f asio::basic_socket_acceptor<asio::ip::tcp, asio::execution::any_executor<asio::execution::context_as_t<asio::execution_context&>, asio::execution::detail::blocking::never_t<0>, asio::execution::prefer_only<asio::execution::detail::blocking::possibly_t<0> >, asio::execution::prefer_only<asio::execution::detail::outstanding_work::tracked_t<0> >, asio::execution::prefer_only<asio::execution::detail::outstanding_work::untracked_t<0> >, asio::execution::prefer_only<asio::execution::detail::relationship::fork_t<0> >, asio::execution::prefer_only<asio::execution::detail::relationship::continuation_t<0> > > >::open(asio::ip::tcp const&, std::__1::error_code&) + 36 (basic_socket_acceptor.hpp:490) [inlined]
6   obs-websocket.so                0x000000013afbf83f websocketpp::transport::asio::endpoint<websocketpp::config::asio::transport_config>::listen(asio::ip::basic_endpoint<asio::ip::tcp> const&, std::__1::error_code&) + 143 (endpoint.hpp:426)
7   obs-websocket.so                0x000000013afb63c7 void websocketpp::transport::asio::endpoint<websocketpp::config::asio::transport_config>::listen<asio::ip::tcp>(asio::ip::tcp const&, unsigned short, std::__1::error_code&) + 46 (endpoint.hpp:485) [inlined]
8   obs-websocket.so                0x000000013afb63c7 WebSocketServer::Start() + 599 (WebSocketServer.cpp:132)
9   obs-websocket.so                0x000000013afb5b00 WebSocketServer::onObsLoaded() + 64 (WebSocketServer.cpp:232)
10  com.obsproject.obs-studio       0x0000000107c5652f OBSStudioAPI::on_event(obs_frontend_event) + 111
11  com.obsproject.obs-studio       0x0000000107c6e82c OBSBasic::OBSInit() + 5068
12  com.obsproject.obs-studio       0x0000000107c47669 OBSApp::OBSInit() + 681
13  com.obsproject.obs-studio       0x0000000107c4b9e8 main + 5176
14  libdyld.dylib                   0x00007fff203f8f3d start + 1

This appears to be possibly related to #641

This is keeping multiple independent plugin developers for OBS from updating their ASIO versions, because updating one plugin means all other plugins using ASIO must update to the same exact version.

2021-lex commented 2 years ago

Any news on this issue? I think I have a similar problem with my AU plugin on MacOS when running it inside Ableton Live 10 With latest version of asio (asio-1-22-1 ) I get a crash but with a previous version I don't.

PatTheMav commented 1 year ago

I've taken some time today to dive into this and while I haven't been able to find the exact root cause, I did gain some insights:

In the specific case of the "advanced scene switcher" plugin, the core (but not root) issue is that when a "scheduler" service is needed, the execution context's service registry already has a scheduler service (its type_info is correctly set), but it is not properly initialised.

So when a kqueue_generator is initialised (which requires a scheduler as part of its initialiser), it crashes when it attempts to call the empty/non-existent get_task callback.


I haven't dug into why there is a wrong/badly initialised scheduler already present in the service registry, but given that any call to a templated function from a consecutive dynamic library will end up in the address space of the first dynamic library that has asio included might always lead to issues on version mismatches.

[!NOTE] Possibly fixed in the project via https://github.com/obsproject/obs-studio/pull/9623. Implementing asio as a header-only library in dynamic libraries and loading both at runtime indirectly violates C++' One-Definition-Rule, though I dunno if decorating more functions with ASIO_DECL to inline them might also fix this issue (as inline functions seem to be moved into the TEXT section of the library).

ruurdadema commented 2 months ago

I know this is old, but for future readers (including myself):

ASIO allows you to define ASIO_DISABLE_VISIBILITY to disable any symbol visibility pragmas. Combine this with setting visibility to hidden and the problem will be solved.

More info on this: https://forum.juce.com/t/asio-think-async-version-1-22-1-crashes-pro-tools/56482/2