]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/opentracing-cpp/src/dynamic_load_unix.cpp
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / opentracing-cpp / src / dynamic_load_unix.cpp
CommitLineData
f67539c2
TL
1#include <dlfcn.h>
2#include <opentracing/dynamic_load.h>
3#include <opentracing/version.h>
4
5namespace opentracing {
6BEGIN_OPENTRACING_ABI_NAMESPACE
7namespace {
8class DynamicLibraryHandleUnix : public DynamicLibraryHandle {
9 public:
10 explicit DynamicLibraryHandleUnix(void* handle) : handle_{handle} {}
11
12 ~DynamicLibraryHandleUnix() override { dlclose(handle_); }
13
14 private:
15 void* handle_;
16};
17} // namespace
18
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.
21//
22// See https://github.com/envoyproxy/envoy/pull/2252#issuecomment-362668221
23// https://github.com/google/sanitizers/issues/911
24//
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))
32#endif
33expected<DynamicTracingLibraryHandle>
34DynamicallyLoadTracingLibrary(const char* shared_library,
35 std::string& error_message) noexcept try {
36 dlerror(); // Clear any existing error.
37
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);
42 }
43
44 std::unique_ptr<DynamicLibraryHandle> dynamic_library_handle{
45 new DynamicLibraryHandleUnix{handle}};
46
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);
53 }
54
55 if (*make_tracer_factory == nullptr) {
56 error_message =
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);
60 }
61
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);
67 if (rcode != 0) {
68 if (error_category == nullptr) {
69 error_message = "failed to construct a TracerFactory: unknown error code";
70 return make_unexpected(dynamic_load_failure_error);
71 }
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();
76 }
77 return make_unexpected(dynamic_load_failure_error);
78 }
79
80 if (tracer_factory == nullptr) {
81 error_message =
82 "failed to construct a TracerFactory: `tracer_factory` is null";
83 return make_unexpected(dynamic_load_failure_error);
84 }
85
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));
92}
93END_OPENTRACING_ABI_NAMESPACE
94} // namespace opentracing