Skip to content

Clang static analyzer false positive for unique_ptr inside std::pair #164084

@bepaald

Description

@bepaald

The following code causes c++-analyzer to emit a warning:

#include <memory>
#include <openssl/evp.h>

std::pair<std::unique_ptr<unsigned char[]>, int> decryptA(unsigned char *encdata, int enclength)
{
  std::pair<std::unique_ptr<unsigned char[]>, int> decrypted{new unsigned char[enclength], enclength};

  std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ctx(EVP_CIPHER_CTX_new(), &::EVP_CIPHER_CTX_free);
  if (EVP_DecryptUpdate(ctx.get(), decrypted.first.get(), &decrypted.second, encdata, enclength) != 1)
    return {nullptr, 0};

  return decrypted;
}
[~] $ /usr/lib/clang/c++-analyzer -c main93.cc
main93.cc:14:10: warning: Potential leak of memory pointed to by 'decrypted.first._M_t._M_t._M_head_impl' [cplusplus.NewDeleteLeaks]
   14 |   return decrypted;
       |          ^~~~~~~~~
 1 warning generated.

I believe this is a false positive (but let me know if I'm mistaken). This is version 20.1.8, running on Arch Linux.

Apologies that the code depends on openssl, if I change the call to EVP_DecryptUpdate() to anything else the warning goes away:

/* !! NO MEMORY LEAK REPORTED FROM THIS CODE !! */
/* Only change: replace EVP_DecryptUpdate with a dummy function with the same signature */

#include <memory>
#include <openssl/evp.h>

int dummy(EVP_CIPHER_CTX *, unsigned char *, int *, unsigned char *, int);

std::pair<std::unique_ptr<unsigned char[]>, int> decryptC(unsigned char *encdata, int enclength)
{
  std::pair<std::unique_ptr<unsigned char[]>, int> decrypted{new unsigned char[enclength], enclength};

  std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ctx(EVP_CIPHER_CTX_new(), &::EVP_CIPHER_CTX_free);
  if (dummy(ctx.get(), decrypted.first.get(), &decrypted.second, encdata, enclength) != 1)
    return {nullptr, 0};

  return decrypted;
}

Similarly, if I do not put the std::unique_ptr and int together in a std::pair, but keep them separate (until returning from the function), the problem also goes away.

/* !! NO MEMORY LEAK REPORTED FROM THIS CODE !! */
/* Only change: do not save the unique_ptr and int in a pair, but keep them separate until the return statement */

#include <memory>
#include <openssl/evp.h>

std::pair<std::unique_ptr<unsigned char[]>, int> decryptB(unsigned char *encdata, int enclength)
{
  std::unique_ptr<unsigned char[]> decrypted_first(new unsigned char[enclength]);
  int decrypted_second = enclength;

  std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ctx(EVP_CIPHER_CTX_new(), &::EVP_CIPHER_CTX_free);
  if (EVP_DecryptUpdate(ctx.get(), decrypted_first.get(), &decrypted_second, encdata, enclength) != 1)
    return {nullptr, 0};

  return std::make_pair(std::move(decrypted_first), decrypted_second);
}

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions