Search code examples
c++multithreadingmemory-leaksopensslrsa

c++ openssl 1.1.1 running RSA algorithm in thread causing memory leaks


This is very strange! I look around and find nothing. My test code is below:

#include "pch.h"
#include "Windows.h"
#include "openssl/ssl.h"
 
#pragma comment(lib,"../Include/lib/libssl.lib")
#pragma comment(lib,"../Include/lib/libcrypto.lib")
#pragma comment(lib,"Crypt32.lib")
#pragma comment(lib,"ws2_32.lib")
 
#include <stdlib.h>
#include <crtdbg.h>
 
#define _CRTDBG_MAP_ALLOC
 
const char* priKey = "607BC8BA457EC0A1B5ABAD88061502BEA5844E17C7DD247345CD57E501B3300B4B8889D3DFCF5017847606508DF8B283C701F35007D5F4DBA96023DD3B0CCE062D8F63BCC16021B944A1E88861B70D456BAA1E0E69C90DFCA13B4D4EA5403DA25FEBF94B0515644A7D2DF88299189688DA5D8951512ADC3B1A35BAEEC147F69AB101048B9029E65A77A438A05AE30337E82B0571B80A955C72EA0DB3B457ECC8B81F346624E3D22755FEB3D84F810431974803E13E26BF95AF7AB590E17C0113BFE9B36BE12BE16D89273348E0CC094526CAF54ABF8044565EC9500EBF657265474BC362EBDFD78F513282AAF0EEF9BA0BB00F7FF9C7E61F00465BBD379D6201";
const char* pubKey = "AE7DF3EB95DF1F864F86DA9952BB44E760152986731253C96C135E5391AEFF68F5C1640552F1CCC2BA2C12C0C68C051E343B786F13215CEFC8221D9FA97D50E895EAF50D1AF32DC5EB40C9F1F8CA5145B43CEF83F2A89C9661AFA73A70D32951271C6BEFE1B5F24B512520DA7FD4EEC982F2D8057FE1938FA2FB54D8D282A25D8397298B75E154739EF16B8E2F18368F5BEEAD3D18528B9B1A63C731A71735CDB6102E187EF3377B72B58A124FA280891A79A2BD789D5DBA3618BBD74367F5C50A220204D90A59828C3C81FDBD9D2A91CBF6C8563C6FE987BE21B19BBC340DE4D42290D63909AD5D856D13B8CDC91D5701570045CE3609D4F8884F69120AD9A3";
 
void rsa_test(const char* n,const char* d)
{
    RSA* rsa = RSA_new();
 
    BIGNUM* bn = BN_new();
    BIGNUM* bd = BN_new();
    BIGNUM* be = BN_new();
    BN_set_word(be, 0x10001);
    if (n) BN_hex2bn(&bn, n);
 
    if (d) BN_hex2bn(&bd, d);
    RSA_set0_key(rsa, bn, be, bd);
 
    //calc hash
    const char* msg = "hello,rsa!!";
    BYTE shaResult[SHA256_DIGEST_LENGTH] = { 0 };
    SHA256((unsigned char*)msg, strlen(msg), shaResult);
 
    //sign
    unsigned int olen;
    unsigned char sign[256] = { 0 };
    RSA_sign(NID_sha256, shaResult, SHA256_DIGEST_LENGTH, sign, &olen,rsa);
 
    RSA_free(rsa);
}
 
DWORD thread_test(LPVOID lpParam)
{
    rsa_test(pubKey, priKey);
    return 0;
}
 
int main()
{
    //_CrtSetBreakAlloc(159);
 
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
 
    //CreateThread(nullptr, 0, thread_test, nullptr, 0, nullptr);
    //rsa_test(pubKey,priKey);
 
    system("pause");
}

Calling rsa_test(pubKey,priKey) directly in the main thread DO NOT cause memory leaks!

Calling CreateThread(nullptr, 0, thread_test, nullptr, 0, nullptr) comes out memory leaks!!!

Console output as follows:

Detected memory leaks!
Dumping objects ->
{173} normal block at 0x000002BDE6D44000, 264 bytes long.
 Data: <   _W- :_ s  ! 6> D8 89 FD 5F 57 2D C5 3A 5F 82 73 F1 00 21 FA 36 
{162} normal block at 0x000002BDE6D43AC0, 264 bytes long.
 Data: <                > 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 
{161} normal block at 0x000002BDE6D2E2A0, 160 bytes long.
 Data: <`               > 60 F1 0F 91 F6 7F 00 00 00 00 00 00 00 00 00 00 
{160} normal block at 0x000002BDE6D2DBA0, 160 bytes long.
 Data: <`               > 60 F1 0F 91 F6 7F 00 00 00 00 00 00 00 00 00 00 
{159} normal block at 0x000002BDE6D48230, 352 bytes long.
 Data: <        P       > 00 00 00 00 00 00 00 00 50 AB D3 E6 BD 02 00 00 
{158} normal block at 0x000002BDE6D286B0, 12 bytes long.
 Data: <            > 00 00 00 00 00 00 00 00 01 00 00 00 
Object dump complete.

Then I use _CrtSetBreakAlloc(159) (or other memory id) to location,and here is my call stack screenshot: call stack

my vs2017 showing the break point at CRYPTO_zalloc(crypto/mem.c)

So my question is how to free those leak memory in thread!

Thanks a lot!!

Download my test code(build with visual studio 2017 x64)


Solution

  • https://www.openssl.org/docs/man1.1.1/man3/OPENSSL_thread_stop.html

        OPENSSL_thread_stop();
    

    will do it for you. You can call it like below

    DWORD thread_test(LPVOID lpParam)
    {
        rsa_test(pubKey, priKey);
        OPENSSL_thread_stop();
        return 0;
    }