如何正确取消初始化 OpenSSL [英] How to properly uninitialize OpenSSL

查看:36
本文介绍了如何正确取消初始化 OpenSSL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的 OpenSSL 客户端中,我遇到的问题是,在我选择静态而不是动态链接 libeay32 和 ssleay32 的那一刻,我从 Visual Leak Detector 收到了大量内存泄漏错误.我从 这个线程 中复制了来自 OP 的命令,但我还剩下 6 个.然后我按照 4LegsDrivenCat 在同一线程中的建议添加了 sk_SSL_COMP_free(SSL_COMP_get_compression_methods()); 并且只剩下 4 个,所有这些显然都与加载我用来与服务器的证书.

我使用 Visual Studio 2013 Express、OpenSSL 1.0.1L(32 位和 64 位)、VLD 2.4RC2,我的电脑是 Windows 7 64 位.

下面的调用堆栈是安全模式下 VLD 的 64 位.在 32 位 VLD 在安全模式下崩溃(虽然它在快速模式下工作,但不会产生像样的调用堆栈).我删除了调用堆栈中引用我自己的函数以及十六进制数据的部分.

Visual Leak Detector 2.4RC2 版已安装.警告:Visual Leak Detector 检测到内存泄漏!---------- 块 5671 在 0x000000000097E9B0:180 字节 ----------泄漏哈希:0xA14DA3AA,计数:1,共 180 字节调用堆栈 (TID 7088):0x000000007746FAC0(文件和行号不可用):ntdll.dll!RtlAllocateHeapf:ddvctoolscrtcrtw32heapmalloc.c (58): MyLib.dll!_heap_alloc_basef:ddvctoolscrtcrtw32miscdbgheap.c (431): MyLib.dll!_heap_alloc_dbg_impl + 0xA 字节f:ddvctoolscrtcrtw32miscdbgheap.c (239): MyLib.dll!_nh_malloc_dbg_impl + 0x22 字节f:ddvctoolscrtcrtw32miscdbgheap.c (302): MyLib.dll!_nh_malloc_dbg + 0x2A 字节f:ddvctoolscrtcrtw32miscdbgmalloc.c (56): MyLib.dll!malloc + 0x21 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptomem.c (312): MyLib.dll!CRYPTO_malloc + 0xF 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptolhashlhash.c (121): MyLib.dll!lh_new + 0x16 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (450): MyLib.dll!int_thread_get + 0x13 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (509): MyLib.dll!int_thread_set_item + 0xF 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (1031): MyLib.dll!ERR_get_stated:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (730): MyLib.dll!ERR_put_error + 0x5 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_lib.c (703): MyLib.dll!PEM_read_bio + 0x20 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_info.c (280): MyLib.dll!PEM_X509_INFO_read_bio + 0x10 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (278): MyLib.dll!X509_load_cert_crl_filed:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (123): MyLib.dll!by_file_ctrld:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_lu.c (120): MyLib.dll!X509_LOOKUP_ctrld:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_d2.c (92): MyLib.dll!X509_STORE_load_locations + 0x1D 字节---------- 块 5670 在 0x000000001AC815C0:164 字节 ----------泄漏哈希:0x38C8916E,计数:1,共 164 字节调用堆栈 (TID 7088):0x000000007746FAC0(文件和行号不可用):ntdll.dll!RtlAllocateHeapf:ddvctoolscrtcrtw32heapmalloc.c (58): MyLib.dll!_heap_alloc_basef:ddvctoolscrtcrtw32miscdbgheap.c (431): MyLib.dll!_heap_alloc_dbg_impl + 0xA 字节f:ddvctoolscrtcrtw32miscdbgheap.c (239): MyLib.dll!_nh_malloc_dbg_impl + 0x22 字节f:ddvctoolscrtcrtw32miscdbgheap.c (302): MyLib.dll!_nh_malloc_dbg + 0x2A 字节f:ddvctoolscrtcrtw32miscdbgmalloc.c (56): MyLib.dll!malloc + 0x21 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptomem.c (312): MyLib.dll!CRYPTO_malloc + 0xF 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptolhashlhash.c (119): MyLib.dll!lh_new + 0x13 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (450): MyLib.dll!int_thread_get + 0x13 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (509): MyLib.dll!int_thread_set_item + 0xF 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (1031): MyLib.dll!ERR_get_stated:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (730): MyLib.dll!ERR_put_error + 0x5 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_lib.c (703): MyLib.dll!PEM_read_bio + 0x20 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_info.c (280): MyLib.dll!PEM_X509_INFO_read_bio + 0x10 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (278): MyLib.dll!X509_load_cert_crl_filed:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (123): MyLib.dll!by_file_ctrld:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_lu.c (120): MyLib.dll!X509_LOOKUP_ctrld:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_d2.c (92): MyLib.dll!X509_STORE_load_locations + 0x1D 字节---------- 块 5669 在 0x000000001ADABE80:588 字节 ----------泄漏哈希:0xC3E47B0F,计数:1,共 588 字节调用堆栈 (TID 7088):0x000000007746FAC0(文件和行号不可用):ntdll.dll!RtlAllocateHeapf:ddvctoolscrtcrtw32heapmalloc.c (58): MyLib.dll!_heap_alloc_basef:ddvctoolscrtcrtw32miscdbgheap.c (431): MyLib.dll!_heap_alloc_dbg_impl + 0xA 字节f:ddvctoolscrtcrtw32miscdbgheap.c (239): MyLib.dll!_nh_malloc_dbg_impl + 0x22 字节f:ddvctoolscrtcrtw32miscdbgheap.c (302): MyLib.dll!_nh_malloc_dbg + 0x2A 字节f:ddvctoolscrtcrtw32miscdbgmalloc.c (56): MyLib.dll!malloc + 0x21 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptomem.c (312): MyLib.dll!CRYPTO_malloc + 0xF 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (1019): MyLib.dll!ERR_get_state + 0x17 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (730): MyLib.dll!ERR_put_error + 0x5 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_lib.c (703): MyLib.dll!PEM_read_bio + 0x20 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_info.c (280): MyLib.dll!PEM_X509_INFO_read_bio + 0x10 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (278): MyLib.dll!X509_load_cert_crl_filed:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (123): MyLib.dll!by_file_ctrld:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_lu.c (120): MyLib.dll!X509_LOOKUP_ctrld:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_d2.c (92): MyLib.dll!X509_STORE_load_locations + 0x1D 字节---------- 块 5672 在 0x000000001ADC4180:76 字节 ----------泄漏哈希:0x02B2EA5E,计数:1,共 76 字节调用堆栈 (TID 7088):0x000000007746FAC0(文件和行号不可用):ntdll.dll!RtlAllocateHeapf:ddvctoolscrtcrtw32heapmalloc.c (58): MyLib.dll!_heap_alloc_basef:ddvctoolscrtcrtw32miscdbgheap.c (431): MyLib.dll!_heap_alloc_dbg_impl + 0xA 字节f:ddvctoolscrtcrtw32miscdbgheap.c (239): MyLib.dll!_nh_malloc_dbg_impl + 0x22 字节f:ddvctoolscrtcrtw32miscdbgheap.c (302): MyLib.dll!_nh_malloc_dbg + 0x2A 字节f:ddvctoolscrtcrtw32miscdbgmalloc.c (56): MyLib.dll!malloc + 0x21 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptomem.c (312): MyLib.dll!CRYPTO_malloc + 0xF 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptolhashlhash.c (193): MyLib.dll!lh_insert + 0x15 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (515): MyLib.dll!int_thread_set_itemd:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (1031): MyLib.dll!ERR_get_stated:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (730): MyLib.dll!ERR_put_error + 0x5 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_lib.c (703): MyLib.dll!PEM_read_bio + 0x20 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_info.c (280): MyLib.dll!PEM_X509_INFO_read_bio + 0x10 字节d:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (278): MyLib.dll!X509_load_cert_crl_filed:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (123): MyLib.dll!by_file_ctrld:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_lu.c (120): MyLib.dll!X509_LOOKUP_ctrld:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_d2.c (92): MyLib.dll!X509_STORE_load_locations + 0x1D 字节Visual Leak Detector 检测到 4 个内存泄漏(1008 字节).使用的最大数字:529114 字节.总分配:1070421 字节.Visual Leak Detector 现已退出.

我将泄漏归结为对 SSL_CTX_load_verify_locations 的调用.有谁知道在使用此功能时我需要取消分配什么?只是注释掉这个函数导致泄漏消失,所以不是我传给它的参数造成的.

解决方案

d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c

注意这一点,似乎需要释放一些错误状态(或字符串).

<小时><块引用>

如何正确取消初始化 OpenSSL

启动和关闭的代码如下所示(包括FIPS).如果您执行诸如加载 DH 参数之类的操作,那么您也需要对其进行清理.

博士Henson 对他为每个线程调用 ERR_remove_state 的建议非常有帮助.请参阅 OpenSSL 邮件中的清除顺序以避免内存泄漏?清单.

启动

  • SSL_library_init();
  • SSL_load_error_strings();
  • FIPS_mode_set(1);
  • CRYPTO_set_id_callback();
  • CRYPTO_set_locking_callback();

关闭

  • FIPS_mode_set(0);
  • CRYPTO_set_locking_callback(NULL);
  • CRYPTO_set_id_callback(NULL);
  • ENGINE_cleanup();
  • CONF_modules_unload();
  • ERR_free_strings();
  • EVP_cleanup();
  • CRYPTO_cleanup_all_ex_data();

而且,对于每个线程:

  • ERR_remove_state();

如果你的程序是多线程的,你只需要CRYPTO_set_id_callbackCRYPTO_set_locking_callback.请参阅 Openssl threads(3) 手册页.

我相信您可以在 OpenSSL 1.0.2 及更高版本中调用 SSL_COMP_free_compression_methods.这解决了下面的一些投诉.但它在 OpenSSL 1.0.1 及以下版本中不可用.

<小时><块引用>

SSL_COMP_get_compression_methods()...

是的,这会导致泄漏.它是众所周知的,并且由于 ssl_comp_methods 被延迟分配但从未被释放.请参阅 OpenSSL 问题 2561:内置 SSL 的内存泄漏 -在压缩.

一些 OpenSSL 开发人员认为不值得花时间修复它.请参阅多线程服务器上的小内存泄漏 在 OpenSSL 邮件列表中.

以下是开发者的立场之一:

<块引用>

未释放且独立于执行的操作数,不是内存泄漏.图书馆在某个时间为进程的生命周期分配内存初始化或首次使用函数.这是正常的.

追踪这个是浪费时间恕我直言.

这是关于该特定泄漏的另一个线程:释放 ssl_comp_methods 的首选方式?.这是同一个开发人员的回应:

<块引用>

为什么有人痴迷于释放分配给静态的内存指针最多一次.没有与此类相关的内存泄漏"分配,因为使用的额外内存量是固定的.

他没有意识到Java和.Net会在程序的生命周期中多次加载/卸载库,因此少量的谁在乎"可以无限制地增长.

当他被告知备用用例时,这是他的回复.我猜,他是在建议 Oracle 和 Java 重新构建他们的语言.或者不要在其中使用 OpenSSL.

<块引用>

卸载共享库通常是不安全的.

以下是一位维护 Java VM 的人的回应:

<块引用>

作为替代"JavaVM 的维护者,我可以确认我们绝对必须支持库卸载,因为一位客户是大量使用它 - 那是几年前的事了.早期的 Sun VM不支持库卸载,但那些虚拟机也没有垃圾收集过时的类.

<小时>

这里是修复 ssl_comp_methods 泄漏的部分.

在所有情况下,您都需要添加如下所述的补丁.

对于手动执行的程序,只需添加一个名为 free_compressions(或类似的)的函数,并像上面列出的所有其他方法一样在关闭时调用它.函数需要导出.

要在 Linux 下自动完成,需要一点技巧.您必须使用 GCC 扩展:__attribute__ ((destructor)).

/* 添加到 /ssl/ssl_ciph.c 的末尾 */#if !defined(OPENSSL_NO_COMP) &&定义(__GNU_C__)void free_compressions(void) __attribute__ ((析构函数));void free_compressions(void){如果(ssl_comp_methods != NULL){sk_SSL_COMP_free(ssl_comp_methods);ssl_comp_methods = NULL;}}#万一

要在 Windows 下自动执行,您必须在 DllMain 中执行.但是你必须小心DllMain中做什么,以及如何做.所以也许是这样的:

/* 添加到<openssl dir>/ssl/ssl.h*/#if !defined(OPENSSL_NO_COMP) &&定义(WIN32)__declspec(dllexport)void free_compressions(void);#结束/* 添加到<openssl dir>/ssl/ssl_ciph.c的末尾*/#if !defined(OPENSSL_NO_COMP) &&定义(WIN32)void free_compressions(void){如果(ssl_comp_methods != NULL){sk_SSL_COMP_free(ssl_comp_methods);ssl_comp_methods = NULL;}}#万一

-----

<块引用>

为什么这个帖子被低估了?我链接的线程不那么详细,它得到了 10 票(加上我的 1 票).这几年你们是不是变得更严格了?

看接近原因(你现在做不到),接近投票是投出原因:

<块引用>

寻求调试帮助的问题(为什么此代码不起作用?")必须包括所需的行为、特定问题或错误以及在问题本身中重现它所需的最短代码.

通常适用.但在你的情况下它没有;对于那些不熟悉这个问题的人来说,这并不容易理解.事实上,你可以编写一个简单的程序,它只是初始化然后单元化库,它可能会泄漏......

作为政策问题,该站点不能制定规则始终提供相关代码,但某些 OpenSSL 内存泄漏除外"(这实际上是我们处理您的情况所需要的).

In my OpenSSL client I have the problem that the very moment I chose to link libeay32 and ssleay32 statically instead of dynamically I got tons of memory leak errors from Visual Leak Detector. I copied the commands from the OP in this thread, but I still had 6 left. Then I added sk_SSL_COMP_free(SSL_COMP_get_compression_methods()); as advised by 4LegsDrivenCat in the same thread and only 4 more were left, all of which are apparently related to loading a trusted certificate which I use to compare to the server's certificate.

I use Visual Studio 2013 Express, OpenSSL 1.0.1L (both 32 and 64 Bit), VLD 2.4RC2 and my PC is Windows 7 64 Bit.

The callstack below is 64 Bit from VLD in safe mode. In 32 Bit VLD crashed in safe mode (while it works in fast mode but doesn't yield a decent callstack). I removed the parts of the callstack that referred to my own functions as well as the hex-data.

Visual Leak Detector Version 2.4RC2 installed.
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 5671 at 0x000000000097E9B0: 180 bytes ----------
  Leak Hash: 0xA14DA3AA, Count: 1, Total 180 bytes
  Call Stack (TID 7088):
    0x000000007746FAC0 (File and line number not available): ntdll.dll!RtlAllocateHeap
    f:ddvctoolscrtcrtw32heapmalloc.c (58): MyLib.dll!_heap_alloc_base
    f:ddvctoolscrtcrtw32miscdbgheap.c (431): MyLib.dll!_heap_alloc_dbg_impl + 0xA bytes
    f:ddvctoolscrtcrtw32miscdbgheap.c (239): MyLib.dll!_nh_malloc_dbg_impl + 0x22 bytes
    f:ddvctoolscrtcrtw32miscdbgheap.c (302): MyLib.dll!_nh_malloc_dbg + 0x2A bytes
    f:ddvctoolscrtcrtw32miscdbgmalloc.c (56): MyLib.dll!malloc + 0x21 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptomem.c (312): MyLib.dll!CRYPTO_malloc + 0xF bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptolhashlhash.c (121): MyLib.dll!lh_new + 0x16 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (450): MyLib.dll!int_thread_get + 0x13 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (509): MyLib.dll!int_thread_set_item + 0xF bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (1031): MyLib.dll!ERR_get_state
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (730): MyLib.dll!ERR_put_error + 0x5 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_lib.c (703): MyLib.dll!PEM_read_bio + 0x20 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_info.c (280): MyLib.dll!PEM_X509_INFO_read_bio + 0x10 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (278): MyLib.dll!X509_load_cert_crl_file
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (123): MyLib.dll!by_file_ctrl
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_lu.c (120): MyLib.dll!X509_LOOKUP_ctrl
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_d2.c (92): MyLib.dll!X509_STORE_load_locations + 0x1D bytes

---------- Block 5670 at 0x000000001AC815C0: 164 bytes ----------
  Leak Hash: 0x38C8916E, Count: 1, Total 164 bytes
  Call Stack (TID 7088):
    0x000000007746FAC0 (File and line number not available): ntdll.dll!RtlAllocateHeap
    f:ddvctoolscrtcrtw32heapmalloc.c (58): MyLib.dll!_heap_alloc_base
    f:ddvctoolscrtcrtw32miscdbgheap.c (431): MyLib.dll!_heap_alloc_dbg_impl + 0xA bytes
    f:ddvctoolscrtcrtw32miscdbgheap.c (239): MyLib.dll!_nh_malloc_dbg_impl + 0x22 bytes
    f:ddvctoolscrtcrtw32miscdbgheap.c (302): MyLib.dll!_nh_malloc_dbg + 0x2A bytes
    f:ddvctoolscrtcrtw32miscdbgmalloc.c (56): MyLib.dll!malloc + 0x21 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptomem.c (312): MyLib.dll!CRYPTO_malloc + 0xF bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptolhashlhash.c (119): MyLib.dll!lh_new + 0x13 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (450): MyLib.dll!int_thread_get + 0x13 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (509): MyLib.dll!int_thread_set_item + 0xF bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (1031): MyLib.dll!ERR_get_state
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (730): MyLib.dll!ERR_put_error + 0x5 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_lib.c (703): MyLib.dll!PEM_read_bio + 0x20 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_info.c (280): MyLib.dll!PEM_X509_INFO_read_bio + 0x10 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (278): MyLib.dll!X509_load_cert_crl_file
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (123): MyLib.dll!by_file_ctrl
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_lu.c (120): MyLib.dll!X509_LOOKUP_ctrl
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_d2.c (92): MyLib.dll!X509_STORE_load_locations + 0x1D bytes

---------- Block 5669 at 0x000000001ADABE80: 588 bytes ----------
  Leak Hash: 0xC3E47B0F, Count: 1, Total 588 bytes
  Call Stack (TID 7088):
    0x000000007746FAC0 (File and line number not available): ntdll.dll!RtlAllocateHeap
    f:ddvctoolscrtcrtw32heapmalloc.c (58): MyLib.dll!_heap_alloc_base
    f:ddvctoolscrtcrtw32miscdbgheap.c (431): MyLib.dll!_heap_alloc_dbg_impl + 0xA bytes
    f:ddvctoolscrtcrtw32miscdbgheap.c (239): MyLib.dll!_nh_malloc_dbg_impl + 0x22 bytes
    f:ddvctoolscrtcrtw32miscdbgheap.c (302): MyLib.dll!_nh_malloc_dbg + 0x2A bytes
    f:ddvctoolscrtcrtw32miscdbgmalloc.c (56): MyLib.dll!malloc + 0x21 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptomem.c (312): MyLib.dll!CRYPTO_malloc + 0xF bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (1019): MyLib.dll!ERR_get_state + 0x17 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (730): MyLib.dll!ERR_put_error + 0x5 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_lib.c (703): MyLib.dll!PEM_read_bio + 0x20 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_info.c (280): MyLib.dll!PEM_X509_INFO_read_bio + 0x10 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (278): MyLib.dll!X509_load_cert_crl_file
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (123): MyLib.dll!by_file_ctrl
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_lu.c (120): MyLib.dll!X509_LOOKUP_ctrl
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_d2.c (92): MyLib.dll!X509_STORE_load_locations + 0x1D bytes

---------- Block 5672 at 0x000000001ADC4180: 76 bytes ----------
  Leak Hash: 0x02B2EA5E, Count: 1, Total 76 bytes
  Call Stack (TID 7088):
    0x000000007746FAC0 (File and line number not available): ntdll.dll!RtlAllocateHeap
    f:ddvctoolscrtcrtw32heapmalloc.c (58): MyLib.dll!_heap_alloc_base
    f:ddvctoolscrtcrtw32miscdbgheap.c (431): MyLib.dll!_heap_alloc_dbg_impl + 0xA bytes
    f:ddvctoolscrtcrtw32miscdbgheap.c (239): MyLib.dll!_nh_malloc_dbg_impl + 0x22 bytes
    f:ddvctoolscrtcrtw32miscdbgheap.c (302): MyLib.dll!_nh_malloc_dbg + 0x2A bytes
    f:ddvctoolscrtcrtw32miscdbgmalloc.c (56): MyLib.dll!malloc + 0x21 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptomem.c (312): MyLib.dll!CRYPTO_malloc + 0xF bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptolhashlhash.c (193): MyLib.dll!lh_insert + 0x15 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (515): MyLib.dll!int_thread_set_item
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (1031): MyLib.dll!ERR_get_state
    d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c (730): MyLib.dll!ERR_put_error + 0x5 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_lib.c (703): MyLib.dll!PEM_read_bio + 0x20 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptopempem_info.c (280): MyLib.dll!PEM_X509_INFO_read_bio + 0x10 bytes
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (278): MyLib.dll!X509_load_cert_crl_file
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509y_file.c (123): MyLib.dll!by_file_ctrl
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_lu.c (120): MyLib.dll!X509_LOOKUP_ctrl
    d:cfilesprojectswinsslopenssl-1.0.1lcryptox509x509_d2.c (92): MyLib.dll!X509_STORE_load_locations + 0x1D bytes


Visual Leak Detector detected 4 memory leaks (1008 bytes).
Largest number used: 529114 bytes.
Total allocations: 1070421 bytes.
Visual Leak Detector is now exiting.

edit: I pinned the leaks down to the call to SSL_CTX_load_verify_locations. Does anyone know what I need to de-allocate when using this function? Just commenting this function causes the leaks to disappear, so it's not because of the parameters I pass to it.

解决方案

d:cfilesprojectswinsslopenssl-1.0.1lcryptoerrerr.c

Latching on to this, it looks like some error state (or strings) needs to be free'd.


How to properly uninitialize OpenSSL

The code for startup and shutdown is shown below (including FIPS). If you do things like load DH parameters, then you will need to clean them up, too.

Dr. Henson was very helpful with his suggestion of calling ERR_remove_state for each thread. See Order of Cleanup to avoid memory leaks? on the OpenSSL mailing list.

Startup

  • SSL_library_init();
  • SSL_load_error_strings();
  • FIPS_mode_set(1);
  • CRYPTO_set_id_callback(<fn>);
  • CRYPTO_set_locking_callback(<fn>);

Shutdown

  • FIPS_mode_set(0);
  • CRYPTO_set_locking_callback(NULL);
  • CRYPTO_set_id_callback(NULL);
  • ENGINE_cleanup();
  • CONF_modules_unload();
  • ERR_free_strings();
  • EVP_cleanup();
  • CRYPTO_cleanup_all_ex_data();

And, for each thread:

  • ERR_remove_state();

You only need CRYPTO_set_id_callback and CRYPTO_set_locking_callback if your program is multi-threaded. See the Openssl threads(3) man page.

I believe you can call SSL_COMP_free_compression_methods in OpenSSL 1.0.2 and above. That addresses some of the complaint below. But its not available in OpenSSL 1.0.1 and below.


SSL_COMP_get_compression_methods()...

Yeah, this causes a leak. Its well known and due to ssl_comp_methods being lazily allocated but never freed. See OpenSSL Issue 2561: Memory leak with SSL built-in compressions.

Some of the OpenSSL devs don't feel its worth their time to fix it. See Small memory leak on multithreaded server on the OpenSSL mailing list.

The following is one of the dev's position on it:

A fixed amount of memory that is not deallocated and is independent of the number of operations performed, is NOT a memory leak. Libraries to allocate memory for the lifetime of the process during one time initialization or first use of a function. This is normal.

Tracking this down is a waste of time IMHO.

And here's another thread about that particular leak: Preferred way to free ssl_comp_methods?. And here's that same dev's response:

Why is anyone obsessed about freeing memory that is assigned to static pointers at most once. There's no "memory leak" associated with such allocations because the amount of extra memory used is fixed.

What he failed to realize is Java and .Net will load/unload the library many times during a program's lifecycle, so that small amount of "who cares" can grow unbounded.

When he was told about the alternate use case, here was his reply. I guess, he is suggesting that Oracle and Java re-architect their languages. Or don't use OpenSSL in them.

Unloading of shared libraries is generally unsafe.

Here was the response of one of the folks who maintain a Java VM:

As the maintainer of an "alternative" JavaVM I can confirm that we absolutely had to support library unloading because one customer was using it heavily - and that was quite a few years ago. Early Sun VMs didn't support library unloading, but then those VMs also did not garbage-collect obsolete classes either.


Here a section on fixing the ssl_comp_methods leak.

In all cases, you will need to add the patch described below.

For a program to do it manually, just add a function named free_compressions (or similar) and call it on shutdown like all the other methods listed above. The function needs to be exported.

To do it automatically under Linux, its takes a little trickery. You have to use a GCC extension: __attribute__ ((destructor)).

/* Add to end of <openssl dir>/ssl/ssl_ciph.c */
#if !defined(OPENSSL_NO_COMP) && defined(__GNU_C__)
void free_compressions(void) __attribute__ ((destructor));
void free_compressions(void)
{
    if (ssl_comp_methods != NULL)
        {
        sk_SSL_COMP_free(ssl_comp_methods);
        ssl_comp_methods = NULL;
        }
}
#endif 

To do it automatically under Windows, you have to do it in DllMain. But you have to be careful about what you do in DllMain, and how you do it. So maybe something like:

/* Add to end of <openssl dir>/ssl/ssl.h*/
#if !defined(OPENSSL_NO_COMP) && defined(WIN32)
__declspec(dllexport)
    void free_compressions(void);
#endof

/* Add to end of <openssl dir>/ssl/ssl_ciph.c */
#if !defined(OPENSSL_NO_COMP) && defined(WIN32)
void free_compressions(void)
{
    if (ssl_comp_methods != NULL)
        {
        sk_SSL_COMP_free(ssl_comp_methods);
        ssl_comp_methods = NULL;
        }
}
#endif 

-----

Why is this thread being downvoted? The thread I linked is a lot less detailed and it got 10 upvotes (plus one from me). Did you guys become a lot more strict in the last few years?

Looking at the close reason (which you can't do at the moment), the close vote was cast with the reason:

Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself.

Normally that applies. But in your case it does not; and its not readily apparent to those not familiar with the issue. In fact, you could write a simple program that just initializes and then unitializes the library and it will probably leak...

As a matter of policy, the site can't make a rule "Always provide relevant code except for some OpenSSL memory leaks" (which is effectively what we need to handle your case).

这篇关于如何正确取消初始化 OpenSSL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆