In some cases when loading ASIO dynamically into a host process on macOS the address of the service_registry::create static method fails to correctly resolve. This leads to a cascade of issues, including uninitialized objects. The end result is that the call to scheduler_.concurrency_hint() in kqueue_reactor fails with a EXC_BAD_ACCESS crash.
So far, this has occurred on macOS running on an M1 processor. I'm not sure if other macOS architectures are affected, and it doesn't seem to be an issue on Windows.
When debugging in Xcode, the memory address of the factory method is incorrect, which means that the call to the factory method in the service_registry::do_use_service method fails and the kqueue_reactor and scheduler objects do not initialize correctly.
There is a stackoverflow issue that goes into more details and highlights others who have run into the issue here.
The code that fails is in detail/impl/service_registry.hpp - this is it:
So when the call to service_registry::do_use_service occurs on the final line, and it attempts to call the factory method to create a new instance of the service, it fails, which causes uninitialized objects leading to the crash.
The Fix
The fix that worked for me was to simply add ASIO_DECL to the definition of the service_registry::create method, as follows:
// Factory function for creating a service instance.
template <typename Service, typename Owner>
ASIO_DECL static execution_context::service* create(void* owner);
Is there any reason not to declare the create method like this? The matching destroy method right below it is declared with ASIO_DECL.
I'm still not sure why dynamically loading in some host processes works fine, and yet others fail to resolve the address correctly.
I had the same issue and can confirm that other macOS (Intel) architectures are also affected. I created a related pull request with the minor fix proposed by @meverett https://github.com/chriskohlhoff/asio/pull/1257
The Crash
In some cases when loading ASIO dynamically into a host process on macOS the address of the
service_registry::create
static method fails to correctly resolve. This leads to a cascade of issues, including uninitialized objects. The end result is that the call toscheduler_.concurrency_hint()
inkqueue_reactor
fails with a EXC_BAD_ACCESS crash.So far, this has occurred on macOS running on an M1 processor. I'm not sure if other macOS architectures are affected, and it doesn't seem to be an issue on Windows.
When debugging in Xcode, the memory address of the
factory
method is incorrect, which means that the call to the factory method in theservice_registry::do_use_service
method fails and thekqueue_reactor
andscheduler
objects do not initialize correctly.There is a stackoverflow issue that goes into more details and highlights others who have run into the issue here.
The code that fails is in
detail/impl/service_registry.hpp
- this is it:Specifically, this is the line where the method address fails to resolve correctly:
So when the call to
service_registry::do_use_service
occurs on the final line, and it attempts to call the factory method to create a new instance of the service, it fails, which causes uninitialized objects leading to the crash.The Fix
The fix that worked for me was to simply add
ASIO_DECL
to the definition of theservice_registry::create
method, as follows:Is there any reason not to declare the
create
method like this? The matchingdestroy
method right below it is declared withASIO_DECL
.I'm still not sure why dynamically loading in some host processes works fine, and yet others fail to resolve the address correctly.