summaryrefslogtreecommitdiffstats
path: root/src/dynamic_load_unix.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dynamic_load_unix.cpp')
-rw-r--r--src/dynamic_load_unix.cpp94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/dynamic_load_unix.cpp b/src/dynamic_load_unix.cpp
new file mode 100644
index 0000000..17e08fd
--- /dev/null
+++ b/src/dynamic_load_unix.cpp
@@ -0,0 +1,94 @@
+#include <dlfcn.h>
+#include <opentracing/dynamic_load.h>
+#include <opentracing/version.h>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+namespace {
+class DynamicLibraryHandleUnix : public DynamicLibraryHandle {
+ public:
+ explicit DynamicLibraryHandleUnix(void* handle) : handle_{handle} {}
+
+ ~DynamicLibraryHandleUnix() override { dlclose(handle_); }
+
+ private:
+ void* handle_;
+};
+} // namespace
+
+// Undefined behavior sanitizer has a bug where it will produce a false positive
+// when casting the result of dlsym to a function pointer.
+//
+// See https://github.com/envoyproxy/envoy/pull/2252#issuecomment-362668221
+// https://github.com/google/sanitizers/issues/911
+//
+// Note: undefined behavior sanitizer is supported in clang and gcc > 4.9
+#if defined(__clang__)
+__attribute__((no_sanitize("function")))
+// Copied from https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
+#elif defined(__GNUC__) && \
+ ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40900)
+__attribute__((no_sanitize_undefined))
+#endif
+expected<DynamicTracingLibraryHandle>
+DynamicallyLoadTracingLibrary(const char* shared_library,
+ std::string& error_message) noexcept try {
+ dlerror(); // Clear any existing error.
+
+ const auto handle = dlopen(shared_library, RTLD_NOW | RTLD_LOCAL);
+ if (handle == nullptr) {
+ error_message = dlerror();
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ std::unique_ptr<DynamicLibraryHandle> dynamic_library_handle{
+ new DynamicLibraryHandleUnix{handle}};
+
+ const auto make_tracer_factory =
+ reinterpret_cast<OpenTracingMakeTracerFactoryType**>(
+ dlsym(handle, "OpenTracingMakeTracerFactory"));
+ if (make_tracer_factory == nullptr) {
+ error_message = dlerror();
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ if (*make_tracer_factory == nullptr) {
+ error_message =
+ "An error occurred while looking up for OpenTracingMakeTracerFactory. "
+ "It seems that it was set to nullptr.";
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ const void* error_category = nullptr;
+ void* tracer_factory = nullptr;
+ const auto rcode = (*make_tracer_factory)(
+ OPENTRACING_VERSION, OPENTRACING_ABI_VERSION, &error_category,
+ static_cast<void*>(&error_message), &tracer_factory);
+ if (rcode != 0) {
+ if (error_category == nullptr) {
+ error_message = "failed to construct a TracerFactory: unknown error code";
+ return make_unexpected(dynamic_load_failure_error);
+ }
+ const auto error_code = std::error_code{
+ rcode, *static_cast<const std::error_category*>(error_category)};
+ if (error_message.empty()) {
+ error_message = error_code.message();
+ }
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ if (tracer_factory == nullptr) {
+ error_message =
+ "failed to construct a TracerFactory: `tracer_factory` is null";
+ return make_unexpected(dynamic_load_failure_error);
+ }
+
+ return DynamicTracingLibraryHandle{
+ std::unique_ptr<const TracerFactory>{
+ static_cast<TracerFactory*>(tracer_factory)},
+ std::move(dynamic_library_handle)};
+} catch (const std::bad_alloc&) {
+ return make_unexpected(std::make_error_code(std::errc::not_enough_memory));
+}
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing