Is OpenSSL from_pem()/from_der leaking memory?

Greetings Rustaceans, sending peace.

Using the same code I posted here How to extract the curve_name from X509 ECC cert

And running it through valgrind I get a bunch of "Still Reachable" (copied in a small snip below of the report). And yes I know that valgrind FAQ says

"still reachable" means your program is probably ok -- it didn't free some memory it could have. This is quite common and often reasonable. Don't use --show-reachable=yes if you don't want to see these reports.

So I write to:

  1. Just to double-check that these are NOT real memory leaks?

  2. Is there anything that I can do to make them disappear (I have tried drop(x509), but it did not make a difference). Got more or less the same results when I call from_der() with a der encoded cert.

  3. I suspect that this is much like OS X 10.10 Valgrind 3.11.0 Box allocation leaks?
    So do let me know if there way/command (lsof) I can use to observe if this is a run-time system library issue?

  • Valgrid Report Sumary Snip
$ valgrind --leak-check=full --show-leak-kinds=all ./target/debug/parse-cert-example 
==29092== Memcheck, a memory error detector
==29092== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==29092== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==29092== Command: ./target/debug/parse-cert-example
==29092== 
curve_name: P-384
curve_name_long: secp384r1
Complete X509 decoded cert: X509 { serial_number: "7497258AC73F7A54", signature_algorithm: ecdsa-with-SHA384, issuer: [countryName = "US", organizationName = "AffirmTrust", commonName = "AffirmTrust Premium ECC"], subject: [countryName = "US", organizationName = "AffirmTrust", commonName = "AffirmTrust Premium ECC"], not_before: Jan 29 14:20:24 2010 GMT, not_after: Dec 31 14:20:24 2040 GMT, public_key: PKey { algorithm: "EC" } }
X509 version: 2
X509 Public Key: PKey { algorithm: "EC" }
X509 Public Key Length: 384
X509 signature_algorithm: "ecdsa-with-SHA384"
X509 Subject Key ID: [154, 175, 41, 122, 192, 17, 53, 53, 38, 81, 48, 0, 195, 106, 254, 64, 213, 174, 214, 60]
X509 Subject: [countryName = "US", organizationName = "AffirmTrust", commonName = "AffirmTrust Premium ECC"]
X509 Issuer: [countryName = "US", organizationName = "AffirmTrust", commonName = "AffirmTrust Premium ECC"]
X509 validity: Jan 29 14:20:24 2010 GMT to Dec 31 14:20:24 2040 GMT
X509 Digest: "bd71fdf6da97e4cf62d1647add2581b07d79adf8397eb4ecba9c5e8488821423"

csv_data_cert_string:
 bd71fdf6da97e4cf62d1647add2581b07d79adf8397eb4ecba9c5e8488821423,2,384,"ecdsa-with-SHA384",[countryName = "US", organizationName = "AffirmTrust", commonName = "AffirmTrust Premium ECC"],[countryName = "US", organizationName = "AffirmTrust", commonName = "AffirmTrust Premium ECC"],Jan 29 14:20:24 2010 GMT to Dec 31 14:20:24 2040 GMT
==29092== 
==29092== HEAP SUMMARY:
==29092==     in use at exit: 333,330 bytes in 3,870 blocks
==29092==   total heap usage: 7,464 allocs, 3,594 frees, 499,380 bytes allocated
==29092== 
==29092== 3 bytes in 1 blocks are still reachable in loss record 1 of 709
==29092==    at 0x484DCD3: realloc (vg_replace_malloc.c:1437)
==29092==    by 0x4AD5BA2: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ACC532: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AEBB2A: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB5227: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB6127: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A81270: OSSL_DECODER_do_all_provided (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A8E64B: OSSL_DECODER_CTX_new_for_pkey (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4B608E3: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x49EEB9A: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x49F03E7: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x49EED18: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092== 
==29092== 4 bytes in 1 blocks are still reachable in loss record 2 of 709
==29092==    at 0x4848899: malloc (vg_replace_malloc.c:381)
==29092==    by 0x4AD8682: CRYPTO_strndup (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AD5301: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AD6CD7: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AD6EBA: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AD6AAC: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB57AB: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AAD1C8: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AB8F5B: EVP_KEYMGMT_do_all_provided (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A8E441: OSSL_DECODER_CTX_new_for_pkey (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4B608E3: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x49EEB9A: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092== 
==29092== 4 bytes in 1 blocks are still reachable in loss record 3 of 709
==29092==    at 0x4848899: malloc (vg_replace_malloc.c:381)
==29092==    by 0x4AD8682: CRYPTO_strndup (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AD5301: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AD6CD7: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AD6B00: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB57AB: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AAD1C8: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AB8F5B: EVP_KEYMGMT_do_all_provided (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A8E441: OSSL_DECODER_CTX_new_for_pkey (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4B608E3: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x49EEB9A: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x49F03E7: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092== 
==29092== 4 bytes in 1 blocks are still reachable in loss record 4 of 709
==29092==    at 0x4848899: malloc (vg_replace_malloc.c:381)
==29092==    by 0x4AD8682: CRYPTO_strndup (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AD5301: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AD6CD7: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AD6DB9: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AD6AE6: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB57AB: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AAD1C8: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AB8F5B: EVP_KEYMGMT_do_all_provided (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A8E441: OSSL_DECODER_CTX_new_for_pkey (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4B608E3: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x49EEB9A: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092== 
==29092== 4 bytes in 1 blocks are still reachable in loss record 5 of 709
==29092==    at 0x4848899: malloc (vg_replace_malloc.c:381)
==29092==    by 0x4AD8682: CRYPTO_strndup (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AD5301: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB4EF3: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A87C3A: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ACC5E8: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ACC50B: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AEBB2A: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB5227: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB6127: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A81270: OSSL_DECODER_do_all_provided (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A8E64B: OSSL_DECODER_CTX_new_for_pkey (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092== 
==29092== 7 bytes in 1 blocks are still reachable in loss record 6 of 709
==29092==    at 0x4848899: malloc (vg_replace_malloc.c:381)
==29092==    by 0x4AD85DA: CRYPTO_strdup (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A37317: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A37417: CONF_module_add (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A3974C: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4E1DEE7: __pthread_once_slow (pthread_once.c:116)
==29092==    by 0x4AE2A5C: CRYPTO_THREAD_run_once (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A39895: CONF_modules_load (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A39F0D: CONF_modules_load_file_ex (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ADEF5F: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4E1DEE7: __pthread_once_slow (pthread_once.c:116)
==29092==    by 0x4AE2A5C: CRYPTO_THREAD_run_once (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092== 
==29092== 8 bytes in 1 blocks are still reachable in loss record 7 of 709
==29092==    at 0x4848899: malloc (vg_replace_malloc.c:381)
==29092==    by 0x4AD764D: CRYPTO_zalloc (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ADF391: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A8D114: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A8DAFC: ERR_set_mark (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A3A021: CONF_modules_load_file_ex (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ADEF5F: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4E1DEE7: __pthread_once_slow (pthread_once.c:116)
==29092==    by 0x4AE2A5C: CRYPTO_THREAD_run_once (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ADF9C5: OPENSSL_init_crypto (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x48AC9B6: OPENSSL_init_ssl (in /usr/lib/x86_64-linux-gnu/libssl.so.3)
==29092==    by 0x125D0E: openssl_sys::openssl::init::{{closure}} (lib.rs:122)
==29092== 
==29092== 8 bytes in 1 blocks are still reachable in loss record 8 of 709
==29092==    at 0x4848899: malloc (vg_replace_malloc.c:381)
==29092==    by 0x4AD85DA: CRYPTO_strdup (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A37317: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A37417: CONF_module_add (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A396E6: OPENSSL_load_builtin_modules (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A3974C: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4E1DEE7: __pthread_once_slow (pthread_once.c:116)
==29092==    by 0x4AE2A5C: CRYPTO_THREAD_run_once (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A39895: CONF_modules_load (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A39F0D: CONF_modules_load_file_ex (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ADEF5F: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4E1DEE7: __pthread_once_slow (pthread_once.c:116)
==29092== 
==29092== 8 bytes in 1 blocks are still reachable in loss record 9 of 709
==29092==    at 0x4848899: malloc (vg_replace_malloc.c:381)
==29092==    by 0x4A917D4: ENGINE_add (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ADF1EE: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4E1DEE7: __pthread_once_slow (pthread_once.c:116)
==29092==    by 0x4AE2A5C: CRYPTO_THREAD_run_once (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ADF95C: OPENSSL_init_crypto (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A39751: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4E1DEE7: __pthread_once_slow (pthread_once.c:116)
==29092==    by 0x4AE2A5C: CRYPTO_THREAD_run_once (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A39895: CONF_modules_load (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4A39F0D: CONF_modules_load_file_ex (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ADEF5F: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092== 
==29092== 8 bytes in 1 blocks are still reachable in loss record 10 of 709
==29092==    at 0x4848899: malloc (vg_replace_malloc.c:381)
==29092==    by 0x4AD85DA: CRYPTO_strdup (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
....

==29092== 
==29092== 32,768 bytes in 1 blocks are still reachable in loss record 707 of 709
==29092==    at 0x4848899: malloc (vg_replace_malloc.c:381)
==29092==    by 0x4AD764D: CRYPTO_zalloc (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AE2834: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4B08CF5: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AAC859: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ACC64B: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ACC50B: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AEBB2A: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB5227: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB587D: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AA0502: EVP_MD_fetch (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x49DC957: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092== 
==29092== 65,536 bytes in 2 blocks are still reachable in loss record 708 of 709
==29092==    at 0x4848899: malloc (vg_replace_malloc.c:381)
==29092==    by 0x4AD764D: CRYPTO_zalloc (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AE27C2: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4B08CF5: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AAC859: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ACC64B: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ACC50B: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AEBB2A: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB5227: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB587D: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AAD1C8: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AB8F5B: EVP_KEYMGMT_do_all_provided (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092== 
==29092== 65,536 bytes in 2 blocks are still reachable in loss record 709 of 709
==29092==    at 0x4848899: malloc (vg_replace_malloc.c:381)
==29092==    by 0x4AD764D: CRYPTO_zalloc (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AE2834: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4B08CF5: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AAC859: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ACC64B: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4ACC50B: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AEBB2A: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB5227: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4BB587D: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AAD1C8: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092==    by 0x4AB8F5B: EVP_KEYMGMT_do_all_provided (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==29092== 
==29092== LEAK SUMMARY:
==29092==    definitely lost: 0 bytes in 0 blocks
==29092==    indirectly lost: 0 bytes in 0 blocks
==29092==      possibly lost: 0 bytes in 0 blocks
==29092==    still reachable: 333,330 bytes in 3,870 blocks
==29092==         suppressed: 0 bytes in 0 blocks
==29092== 
==29092== For lists of detected and suppressed errors, rerun with: -s
==29092== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

If you run that code in a loop, does the usage keep growing?

1 Like

OpenSSL allocates a bunch of global state on startup, which is not cleaned up during shutdown. You can see in the output that all of the leaked bytes are "still reachable" which indicates they aren't "true" leaks and are probably from this global state.

I think there's a valgrind flag to ignore reachable allocations, or you can see if there's a suppression file for OpenSSL's state.

No, it pretty much the same number for 1 or several certs. I have tried withe 10, 100, 1000 and it reported the same.

Thanks, I know of the Valgrind flag, but the suppression "flag/file" for OpenSSL I am not aware of, will look into. I wonder how I would do that from importing it as a create?

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.