Skip to content

Instantly share code, notes, and snippets.

@kkaefer
Last active May 28, 2018 12:15
Show Gist options
  • Save kkaefer/8cb9cd042ac3b78ca917481182cadb15 to your computer and use it in GitHub Desktop.
Save kkaefer/8cb9cd042ac3b78ca917481182cadb15 to your computer and use it in GitHub Desktop.
Load cURL dynamically at runtime to avoid CURL_OPENSSL_3 vs. CURL_OPENSSL_4 symbol version mismatches
#include <curl/curl.h>
// Dynamically load all cURL functions. Debian-derived systems upgraded the OpenSSL version linked
// to in https://salsa.debian.org/debian/curl/commit/95c94957bb7e89e36e78b995fed468c42f64d18d
// They state:
// Rename libcurl3 to libcurl4, because libcurl exposes an SSL_CTX via
// CURLOPT_SSL_CTX_FUNCTION, and this object changes incompatibly between
// openssl 1.0 and openssl 1.1.
// Since we are not accessing the underlying OpenSSL context, we don't care whether we're linking
// against libcurl3 or libcurl4; both use the ABI version 4 which hasn't changed since 2006
// (see https://curl.haxx.se/libcurl/abi.html). In fact, cURL's ABI compatibility is very good as
// shown on https://abi-laboratory.pro/tracker/timeline/curl/
// Therefore, we're dynamically loading the cURL symbols we need to avoid linking against versioned
// symbols.
#include <dlfcn.h>
namespace curl {
#define CURL_FUNCTIONS \
X(global_init) \
X(getdate) \
X(easy_strerror) \
X(easy_init) \
X(easy_setopt) \
X(easy_cleanup) \
X(easy_getinfo) \
X(easy_reset) \
X(multi_init) \
X(multi_add_handle) \
X(multi_remove_handle) \
X(multi_cleanup) \
X(multi_info_read) \
X(multi_strerror) \
X(multi_socket_action) \
X(multi_setopt) \
X(share_init) \
X(share_cleanup) \
X(slist_append) \
X(slist_free_all)
#define X(name) static decltype(&curl_ ## name) name = nullptr;
CURL_FUNCTIONS
#undef X
static void* handle = nullptr;
static void* load(const char* name) {
fprintf(stderr, "loading %s\n", name);
void* symbol = dlsym(handle, name);
const char* error = dlerror();
if (error) {
fprintf(stderr, "Cannot load symbol '%s'\n", name);
dlclose(handle);
handle = nullptr;
abort();
}
return symbol;
}
__attribute__((constructor))
static void load() {
assert(!handle);
handle = dlopen("libcurl.so.4", RTLD_LAZY | RTLD_LOCAL);
if (!handle) {
fprintf(stderr, "Could not open shared library '%s'\n", "libcurl.so.4");
abort();
}
dlerror();
#define X(name) name = (decltype(&curl_ ## name))load("curl_" #name);
CURL_FUNCTIONS
#undef X
}
__attribute__((constructor))
static void unload() {
if (handle) {
dlclose(handle);
}
}
} // namespace curl
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment