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. (EDIT now at 21.1.4, issue unchanged)

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