asio icon indicating copy to clipboard operation
asio copied to clipboard

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

Open tt2468 opened this issue 3 years ago • 3 comments

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.

tt2468 avatar Jan 04 '22 08:01 tt2468

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.

2021-lex avatar Apr 16 '22 08:04 2021-lex

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:

  • When asio is added as a header-only library into multiple dynamic libraries which are loaded at runtime (i.e. via dlopen), duplicate symbols will be resolved in the global address space of the binary loading the library
  • In the case of obs-studio this means that whichever dynamic library (a "plugin" in that case) is loaded first gets to define the symbol/function pointer
  • Whichever dynamic library is loaded later will have its duplicate function pointer relocated to the identical function that was already resolved by the linker
  • Only functions decorated with ASIO_DECL are truly "private" because they are inlined

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).

PatTheMav avatar Sep 22 '23 22:09 PatTheMav