Skip to content

Commit

Permalink
[Sema] adds -Wfree-nonheap-object member var checks
Browse files Browse the repository at this point in the history
Checks to make sure that stdlib's (std::)free is being appropriately
used for member variables.

Differential Revision: https://reviews.llvm.org/D90269
  • Loading branch information
cjdb authored and gburgessiv committed Nov 2, 2020
1 parent e8f9689 commit ba18bc4
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 13 deletions.
37 changes: 24 additions & 13 deletions clang/lib/Sema/SemaChecking.cpp
Expand Up @@ -10107,19 +10107,9 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
}

namespace {
void CheckFreeArgumentsAddressof(Sema &S, const std::string &CalleeName,
const UnaryOperator *UnaryExpr) {
if (UnaryExpr->getOpcode() != UnaryOperator::Opcode::UO_AddrOf)
return;

const auto *Lvalue = dyn_cast<DeclRefExpr>(UnaryExpr->getSubExpr());
if (Lvalue == nullptr)
return;

const auto *Var = dyn_cast<VarDecl>(Lvalue->getDecl());
if (Var == nullptr)
return;

void CheckFreeArgumentsOnLvalue(Sema &S, const std::string &CalleeName,
const UnaryOperator *UnaryExpr,
const VarDecl *Var) {
StorageClass Class = Var->getStorageClass();
if (Class == StorageClass::SC_Extern ||
Class == StorageClass::SC_PrivateExtern ||
Expand All @@ -10130,6 +10120,27 @@ void CheckFreeArgumentsAddressof(Sema &S, const std::string &CalleeName,
<< CalleeName << Var;
}

void CheckFreeArgumentsOnLvalue(Sema &S, const std::string &CalleeName,
const UnaryOperator *UnaryExpr, const Decl *D) {
if (const auto *Field = dyn_cast<FieldDecl>(D))
S.Diag(UnaryExpr->getBeginLoc(), diag::warn_free_nonheap_object)
<< CalleeName << Field;
}

void CheckFreeArgumentsAddressof(Sema &S, const std::string &CalleeName,
const UnaryOperator *UnaryExpr) {
if (UnaryExpr->getOpcode() != UnaryOperator::Opcode::UO_AddrOf)
return;

if (const auto *Lvalue = dyn_cast<DeclRefExpr>(UnaryExpr->getSubExpr()))
if (const auto *Var = dyn_cast<VarDecl>(Lvalue->getDecl()))
return CheckFreeArgumentsOnLvalue(S, CalleeName, UnaryExpr, Var);

if (const auto *Lvalue = dyn_cast<MemberExpr>(UnaryExpr->getSubExpr()))
return CheckFreeArgumentsOnLvalue(S, CalleeName, UnaryExpr,
Lvalue->getMemberDecl());
}

void CheckFreeArgumentsStackArray(Sema &S, const std::string &CalleeName,
const DeclRefExpr *Lvalue) {
if (!Lvalue->getType()->isArrayType())
Expand Down
10 changes: 10 additions & 0 deletions clang/test/Sema/warn-free-nonheap-object.c
Expand Up @@ -4,6 +4,11 @@ typedef __SIZE_TYPE__ size_t;
void *malloc(size_t);
void free(void *);

struct S {
int I;
char *P;
};

int GI;
void test() {
{
Expand Down Expand Up @@ -31,4 +36,9 @@ void test() {
free(A); // expected-warning {{attempt to call free on non-heap object 'A'}}
free(&A); // expected-warning {{attempt to call free on non-heap object 'A'}}
}
{
struct S s;
free(&s.I); // expected-warning {{attempt to call free on non-heap object 'I'}}
free(s.P);
}
}
23 changes: 23 additions & 0 deletions clang/test/Sema/warn-free-nonheap-object.cpp
Expand Up @@ -13,10 +13,25 @@ int GI;
struct S {
operator char *() { return ptr; }

void CFree() {
::free(&ptr); // expected-warning {{attempt to call free on non-heap object 'ptr'}}
::free(&I); // expected-warning {{attempt to call free on non-heap object 'I'}}
::free(ptr);
}

void CXXFree() {
std::free(&ptr); // expected-warning {{attempt to call std::free on non-heap object 'ptr'}}
std::free(&I); // expected-warning {{attempt to call std::free on non-heap object 'I'}}
std::free(ptr);
}

private:
char *ptr = (char *)std::malloc(10);
static int I;
};

int S::I = 0;

void test1() {
{
free(&GI); // expected-warning {{attempt to call free on non-heap object 'GI'}}
Expand Down Expand Up @@ -51,6 +66,10 @@ void test1() {
free(s);
free(&s); // expected-warning {{attempt to call free on non-heap object 's'}}
}
{
S s;
s.CFree();
}
}

void test2() {
Expand Down Expand Up @@ -87,4 +106,8 @@ void test2() {
std::free(s);
std::free(&s); // expected-warning {{attempt to call std::free on non-heap object 's'}}
}
{
S s;
s.CXXFree();
}
}

0 comments on commit ba18bc4

Please sign in to comment.