2 #include <opentracing/dynamic_load.h>
3 #include <opentracing/version.h>
5 namespace opentracing
{
6 BEGIN_OPENTRACING_ABI_NAMESPACE
8 class DynamicLibraryHandleUnix
: public DynamicLibraryHandle
{
10 explicit DynamicLibraryHandleUnix(void* handle
) : handle_
{handle
} {}
12 ~DynamicLibraryHandleUnix() override
{ dlclose(handle_
); }
19 // Undefined behavior sanitizer has a bug where it will produce a false positive
20 // when casting the result of dlsym to a function pointer.
22 // See https://github.com/envoyproxy/envoy/pull/2252#issuecomment-362668221
23 // https://github.com/google/sanitizers/issues/911
25 // Note: undefined behavior sanitizer is supported in clang and gcc > 4.9
26 #if defined(__clang__)
27 __attribute__((no_sanitize("function")))
28 // Copied from https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
29 #elif defined(__GNUC__) && \
30 ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40900)
31 __attribute__((no_sanitize_undefined
))
33 expected
<DynamicTracingLibraryHandle
>
34 DynamicallyLoadTracingLibrary(const char* shared_library
,
35 std::string
& error_message
) noexcept
try {
36 dlerror(); // Clear any existing error.
38 const auto handle
= dlopen(shared_library
, RTLD_NOW
| RTLD_LOCAL
);
39 if (handle
== nullptr) {
40 error_message
= dlerror();
41 return make_unexpected(dynamic_load_failure_error
);
44 std::unique_ptr
<DynamicLibraryHandle
> dynamic_library_handle
{
45 new DynamicLibraryHandleUnix
{handle
}};
47 const auto make_tracer_factory
=
48 reinterpret_cast<OpenTracingMakeTracerFactoryType
**>(
49 dlsym(handle
, "OpenTracingMakeTracerFactory"));
50 if (make_tracer_factory
== nullptr) {
51 error_message
= dlerror();
52 return make_unexpected(dynamic_load_failure_error
);
55 if (*make_tracer_factory
== nullptr) {
57 "An error occurred while looking up for OpenTracingMakeTracerFactory. "
58 "It seems that it was set to nullptr.";
59 return make_unexpected(dynamic_load_failure_error
);
62 const void* error_category
= nullptr;
63 void* tracer_factory
= nullptr;
64 const auto rcode
= (*make_tracer_factory
)(
65 OPENTRACING_VERSION
, OPENTRACING_ABI_VERSION
, &error_category
,
66 static_cast<void*>(&error_message
), &tracer_factory
);
68 if (error_category
== nullptr) {
69 error_message
= "failed to construct a TracerFactory: unknown error code";
70 return make_unexpected(dynamic_load_failure_error
);
72 const auto error_code
= std::error_code
{
73 rcode
, *static_cast<const std::error_category
*>(error_category
)};
74 if (error_message
.empty()) {
75 error_message
= error_code
.message();
77 return make_unexpected(dynamic_load_failure_error
);
80 if (tracer_factory
== nullptr) {
82 "failed to construct a TracerFactory: `tracer_factory` is null";
83 return make_unexpected(dynamic_load_failure_error
);
86 return DynamicTracingLibraryHandle
{
87 std::unique_ptr
<const TracerFactory
>{
88 static_cast<TracerFactory
*>(tracer_factory
)},
89 std::move(dynamic_library_handle
)};
90 } catch (const std::bad_alloc
&) {
91 return make_unexpected(std::make_error_code(std::errc::not_enough_memory
));
93 END_OPENTRACING_ABI_NAMESPACE
94 } // namespace opentracing