问题:
开子线程,调用curl_easy_perform和主线程调用curl_easy_perform,访问https连接时,有几率出现错误,返回值为27,Out of memory。
错误日志:
* About to connect() to xxx.com.cn port 443 (#0)
* Trying 54.223.100.xxx... * connected
* SSL: couldn't create a context: error:140A90F1:lib(20):func(169):reason(241)
* Closing connection #0
* Out of memory
搜索资料和跟踪代码发现是
- error:140A90F1:SSL routines:SSL_CTX_new:unable to load ssl2 md5 routines
- 在curl源码ossl_connect_step1()->SSL_CTX_new()中检测摘要算法时出错
1991 if ((ret->rsa_md5 = EVP_get_digestbyname(“ssl2-md5”)) == NULL) {
1992 SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES);
1993 goto err2;
1994 } - 起初怀疑是不是openssl-1.0.2u的问题,查阅代码发现摘要算法删除只有一个接口, EVP_cleanup()
-> openssl库应该没问题,就怀疑curl库是不是意外的调用了EVP_cleanup
-> 搜索发现libcurl只有curl_global_cleanup()中才会调用EVP_cleanup(),那肯定也不是libcurl的问题
-> 这个时候发现应用程序链接的动态库还有个libmosquitto,那里面肯定有调用openssl接口的地方,怀疑它
-> 搜索发现EVP_cleanup()只被mosquitto_lib_cleanup()调用,那么发现问题了,是不是在我发起curl_easy_perform()之前,调用过mosquitto_lib_cleanup()呢?
-> 浏览应用程序代码发现,还真是这个问题导致的!
总结
由于openssl库集成到了很多库里面,各个库的初始化和清除都会存在对openssl环境的初始化和清除操作!一定要注意全局的openssl库初始化和清除的关联性。
最开始看到资料里面的说明,也以为是链接的openssl库版本过多导致的问题,后来按这个方向发现问题依然存在!还是要对gcc这种的基础软件要有信心… 后面就怀疑OpenSSL,libcurl,libmosquitto,最后排出到了应用程序,终于找到了问题!
参阅资料:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=768997
https://curl.haxx.se/mail/lib-2018-07/0057.html