此次只记录了解决方法,详细原因和分析见原文。
解决办法
Dynamic loading of shared library with RTLD_DEEPBIND
当我一dlopen中加了参数RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND之后,程序功能正常了,正常了!
这个困扰我几天的问题,就这样戏剧性地解决掉了。
When we are supposed to use RTLD_DEEPBIND? 说明了原因:
You should use RTLD_DEEPBIND when you want to ensure that symbols looked up in the loaded library start within the library, and its dependencies before looking up the symbol in the global namespace.
This allows you to have the same named symbol being used in the library as might be available in the global namespace because of another library carrying the same definition; which may be wrong, or cause problems.
当希望dlopen载入的库首先从自己和它的依赖库中查找符号,然后再去全局符号中去查找时,就用RTLD_DEEPBIND。这样就允许dlopen载入的库中存在与全局符号重名的符号,而对这个载入的库来说错的或者可能引起问题的全局符号可能是由其它库引入的。
现在,libcurl用dlopen方式运行时动态加载,加载时使用RTLD_DEEPBIND参数,这样,它就会首先从libcurl.so以及它所依赖的其它库中查找符号,从而避免了使用有问题的全局符号。
相关的程序片段
//用cURLpp发送RESTful post 请求
int DingDing::post_request_curl(const std::string& url, const std::string& jsonBody, std::string& strReturn)
{
void *handle;
static CURLcode (*f_global_init)(long) = NULL;
static CURL *(*f_easy_init)(void) = NULL;
static struct curl_slist *(*f_slist_append)(struct curl_slist *, const char *) = NULL;
static CURLcode (*f_easy_setopt)(CURL *, CURLoption, ...) = NULL;
static CURLcode (*f_easy_perform)(CURL *) = NULL;
static void (*f_easy_cleanup)(CURL *) = NULL;
static void (*f_global_cleanup)(void) = NULL;
char *error;
//handle = dlopen ("libcurl.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
handle = dlopen ("libcurl.so", RTLD_LAZY | RTLD_DEEPBIND);
//handle = dlopen ("libcurl.so", RTLD_LAZY | RTLD_LOCAL);
if (!handle) {
LOGINFO << "载入libcurl库出错,错误信息:" << dlerror();
exit(1);
}
dlerror(); /* Clear any existing error */
if ((error = dlerror()) != NULL) {
LOGINFO << "载入libcurl库出错,错误信息:" << dlerror();
exit(1);
}
f_global_init = (CURLcode (*)(long)) dlsym(handle, "curl_global_init");
if ((error = dlerror()) != NULL) {
LOGINFO << "载入libcurl库出错,错误信息:" << dlerror();
exit(1);
}
f_easy_init = (CURL *(*)(void)) dlsym(handle, "curl_easy_init");
if ((error = dlerror()) != NULL) {
LOGINFO << "载入libcurl库出错,错误信息:" << dlerror();
exit(1);
}
f_slist_append = (struct curl_slist *(*)(struct curl_slist *, const char *))
dlsym(handle, "curl_slist_append");
if ((error = dlerror()) != NULL) {
LOGINFO << "载入libcurl库出错,错误信息:" << dlerror();
exit(1);
}
f_easy_setopt = (CURLcode (*)(CURL *, CURLoption, ...)) dlsym(handle, "curl_easy_setopt");
if ((error = dlerror()) != NULL) {
LOGINFO << "载入libcurl库出错,错误信息:" << dlerror();
exit(1);
}
f_easy_perform = (CURLcode (*)(CURL *)) dlsym(handle, "curl_easy_perform");
if ((error = dlerror()) != NULL) {
LOGINFO << "载入libcurl库出错,错误信息:" << dlerror();
exit(1);
}
f_easy_cleanup = (void (*)(CURL *)) dlsym(handle, "curl_easy_cleanup");
if ((error = dlerror()) != NULL) {
LOGINFO << "载入libcurl库出错,错误信息:" << dlerror();
exit(1);
}
f_global_cleanup = (void (*)(void)) dlsym(handle, "curl_global_cleanup");
if ((error = dlerror()) != NULL) {
LOGINFO << "载入libcurl库出错,错误信息:" << dlerror();
exit(1);
}
CURL *ch;
CURLcode rv;
f_global_init(CURL_GLOBAL_ALL);
ch = f_easy_init();
struct curl_slist *chunk = NULL;
chunk = f_slist_append(chunk, "Content-Type: application/json");
f_easy_setopt(ch, CURLOPT_VERBOSE, 1L);
f_easy_setopt(ch, CURLOPT_HTTPHEADER, chunk);
//curl_easy_setopt(ch, CURLOPT_HEADER, 0L);
f_easy_setopt(ch, CURLOPT_POSTFIELDS, jsonBody.c_str());
//curl_easy_setopt(ch, CURLOPT_NOPROGRESS, 1L);
//curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L);
//curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, *writefunction);
//curl_easy_setopt(ch, CURLOPT_WRITEDATA, stdout);
//curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, *writefunction);
//curl_easy_setopt(ch, CURLOPT_HEADERDATA, stderr);
//curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM");
f_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 0L);
f_easy_setopt(ch, CURLOPT_URL, url.c_str());
/* Turn off the default CA locations, otherwise libcurl will load CA
* certificates from the locations that were detected/specified at
* build-time
*/
//curl_easy_setopt(ch, CURLOPT_CAINFO, NULL);
//curl_easy_setopt(ch, CURLOPT_CAPATH, NULL);
/* first try: retrieve page without ca certificates -> should fail
* unless libcurl was built --with-ca-fallback enabled at build-time
*/
rv = f_easy_perform(ch);
if(rv == CURLE_OK)
LOGINFO << "libcurl请求发送成功";
else
LOGINFO << "libcurl请求发送失败";
f_easy_cleanup(ch);
f_global_cleanup();
return rv;
}
原文链接:https://blog.youkuaiyun.com/found/article/details/105263450