C++ OpenSSL堆栈API-推送到堆栈后释放对象

C++ OpenSSL堆栈API-推送到堆栈后释放对象,c++,openssl,C++,Openssl,我正在试图了解,在将X509对象推入(X509)结构的堆栈之后,我是否需要释放它们,或者sk\u X509\u free()调用是否为我释放了包括内容在内的所有内容。我在OpenSSL中找不到这方面的文档 std::vector<std::string> caPems; // Fill the vector from input // ... BIO *bufio = NULL; X509 *x509 = NULL, *x509_ca = NULL; bool succ

我正在试图了解,在将
X509
对象推入(X509)结构的
堆栈之后,我是否需要释放它们,或者
sk\u X509\u free()
调用是否为我释放了包括内容在内的所有内容。我在OpenSSL中找不到这方面的文档

std::vector<std::string> caPems;    

// Fill the vector from input
// ...


BIO *bufio = NULL;
X509 *x509 = NULL, *x509_ca = NULL;
bool success = false;
STACK_OF(X509)* x509_ca_stack;

x509_ca_stack = sk_X509_new_null();
if (x509_ca_stack) {
    success = true;
    for (const std::string& caPem : caPems) {
        BIO_new_mem_buf(caPem.c_str(), caPem.size());
        PEM_read_bio_X509(bufio, &x509_ca, NULL, NULL);
        BIO_free_all(bufio);
        if (x509_ca != nullptr) {
            sk_X509_push(x509_ca_stack, x509_ca);
            x509_ca = NULL; // should I free after push???
        } else
            success = false;
    }
    if (success)
        foo(x509_ca_stack);
    sk_X509_free(x509_ca_stack); // or is this free enough for the entire stack?
} else {
    printf("ERROR: failed loading cert\n");
}
std::向量caPems;
//从输入填充向量
// ...
BIO*bufio=NULL;
X509*X509=NULL,*X509_ca=NULL;
布尔成功=假;
(X509)*X509_-ca_堆栈的堆栈;
x509_ca_stack=sk_x509_new_null();
如果(x509_ca_堆栈){
成功=真实;
用于(常量标准::字符串和caPem:caPems){
BIO_new_mem_buf(caPem.c_str(),caPem.size());
PEM_read_bio_X509(bufio和X509_ca,空,空);
生物自由(bufio);
如果(x509_ca!=nullptr){
sk_X509_推送(X509_ca_堆栈,X509_ca);
x509_ca=NULL;//推送后是否应释放???
}否则
成功=错误;
}
如果(成功)
foo(x509_-ca_-stack);
sk_X509_free(X509_ca_stack);//或者这对于整个堆栈来说足够自由吗?
}否则{
printf(“错误:加载证书失败\n”);
}
编辑:valgrind没有任何帮助,无论我释放还是没有释放,它都没有显示任何内容。

因为openssl 1.1 X509(以及许多其他)是引用计数的。 sk_XXX_push()API不会自动增加引用,因此在执行推送操作时,您将移交X509引用。所以,您的代码无效,并且确实会泄漏,因为sk_X509_free()不会减少内部X509的引用计数

编辑:我更正了上面的问题,我原本以为sk_X509_free()会自动释放ref。它不会。 来自openssl文档

sk_TYPE_free()释放sk结构。它不会释放sk的任何元素。在此调用之后,sk不再有效

如果出于某种原因确实需要创建X509的深度副本,可以使用X509_dup()复制X509对象并将其推入堆栈:

sk_X509_push(stack, X509_dup(cert));
在这种情况下,两个X509对象都需要显式释放

您还可以使用
sk_X509_pop_free(stack,X509_free)
自动取消所有堆栈元素的刷新并删除堆栈本身

总之,您的代码可以通过两种方式修复:

  • 在末尾添加X509_free(),而不是在sk_X509_push()之后添加
  • 用sk_X509_pop_free()替换sk_X509_free()

不是100%确定,但查看源代码时,堆栈代码似乎会在调用
sk_X509_push()
时复制数据
sk_X509_push()
调用
OPENSSL_sk_push()
,它调用
OPENSSL_sk_insert()
。因此,您应该释放数据的本地副本。期待其他评论。请参阅sk_xxx_push()进行分配和复制