Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ clang/lib/Sema/SemaChecking.cpp @@ -10264,9 +10264,17 @@ void CheckFreeArgumentsOnLvalue(Sema &S, const std::string &CalleeName, const UnaryOperator *UnaryExpr, const Decl *D) { - if (const auto *Field = dyn_cast(D)) + if (const auto *Field = dyn_cast(D)) { S.Diag(UnaryExpr->getBeginLoc(), diag::warn_free_nonheap_object) << CalleeName << Field; + return; + } + + if (const auto *Func = dyn_cast(D)) { + S.Diag(UnaryExpr->getBeginLoc(), diag::warn_free_nonheap_object) + << CalleeName << Func; + return; + } } void CheckFreeArgumentsAddressof(Sema &S, const std::string &CalleeName, @@ -10274,9 +10282,12 @@ if (UnaryExpr->getOpcode() != UnaryOperator::Opcode::UO_AddrOf) return; - if (const auto *Lvalue = dyn_cast(UnaryExpr->getSubExpr())) + if (const auto *Lvalue = dyn_cast(UnaryExpr->getSubExpr())) { if (const auto *Var = dyn_cast(Lvalue->getDecl())) return CheckFreeArgumentsOnLvalue(S, CalleeName, UnaryExpr, Var); + if (const auto *Var = dyn_cast(Lvalue->getDecl())) + return CheckFreeArgumentsOnLvalue(S, CalleeName, UnaryExpr, Var); + } if (const auto *Lvalue = dyn_cast(UnaryExpr->getSubExpr())) return CheckFreeArgumentsOnLvalue(S, CalleeName, UnaryExpr, @@ -10295,19 +10306,57 @@ S.Diag(Lvalue->getBeginLoc(), diag::warn_free_nonheap_object) << CalleeName << Var; } + +void CheckFreeArgumentsCast(Sema &S, const std::string &CalleeName, + const CastExpr *Cast) { + auto const kind = Cast->getCastKind(); + switch (kind) { + case clang::CK_IntegralToPointer: // [[fallthrough]]; + case clang::CK_FunctionToPointerDecay: { + SmallString<128> SizeString; + llvm::raw_svector_ostream OS(SizeString); + OS << '\''; + Cast->printPretty(OS, nullptr, S.getPrintingPolicy()); + OS << '\''; + S.Diag(Cast->getBeginLoc(), diag::warn_free_nonheap_object) + << CalleeName << OS.str(); + return; + } + default: + return; + } +} } // namespace /// Alerts the user that they are attempting to free a non-malloc'd object. void Sema::CheckFreeArguments(const CallExpr *E) { - const Expr *Arg = E->getArg(0)->IgnoreParenCasts(); const std::string CalleeName = dyn_cast(E->getCalleeDecl())->getQualifiedNameAsString(); - if (const auto *UnaryExpr = dyn_cast(Arg)) - return CheckFreeArgumentsAddressof(*this, CalleeName, UnaryExpr); + // Prefer something that doesn't involve a cast to make things simpler. + { + const Expr *Arg = E->getArg(0)->IgnoreParenCasts(); + if (const auto *UnaryExpr = dyn_cast(Arg)) + return CheckFreeArgumentsAddressof(*this, CalleeName, UnaryExpr); + + if (const auto *Lvalue = dyn_cast(Arg)) + return CheckFreeArgumentsStackArray(*this, CalleeName, Lvalue); - if (const auto *Lvalue = dyn_cast(Arg)) - return CheckFreeArgumentsStackArray(*this, CalleeName, Lvalue); + if (const auto *Label = dyn_cast(Arg)) { + Diag(Label->getBeginLoc(), diag::warn_free_nonheap_object) + << CalleeName << Label->getLabel()->getIdentifier(); + return; + } + + if (const auto *Block = dyn_cast(Arg)) { + Diag(Block->getBeginLoc(), diag::warn_free_nonheap_object) + << CalleeName << ": block expression"; + return; + } + } + // Maybe the cast was important, check after the other cases. + if (const auto *Cast = dyn_cast(E->getArg(0))) + return CheckFreeArgumentsCast(*this, CalleeName, Cast); } void Index: clang/test/Analysis/free.c =================================================================== --- clang/test/Analysis/free.c +++ clang/test/Analysis/free.c @@ -41,7 +41,9 @@ } void t6 () { - free((void*)1000); // expected-warning {{Argument to free() is a constant address (1000), which is not memory allocated by malloc()}} + free((void*)1000); + // expected-warning@-1{{Argument to free() is a constant address (1000), which is not memory allocated by malloc()}} + // expected-warning@-2{{attempt to call free on non-heap object '(void *)1000'}} } void t7 (char **x) { @@ -55,11 +57,15 @@ void t9 () { label: - free(&&label); // expected-warning {{Argument to free() is the address of the label 'label', which is not memory allocated by malloc()}} + free(&&label); + // expected-warning@-1{{Argument to free() is the address of the label 'label', which is not memory allocated by malloc()}} + // expected-warning@-2{{attempt to call free on non-heap object 'label'}} } void t10 () { - free((void*)&t10); // expected-warning {{Argument to free() is the address of the function 't10', which is not memory allocated by malloc()}} + free((void*)&t10); + // expected-warning@-1{{Argument to free() is the address of the function 't10', which is not memory allocated by malloc()}} + // expected-warning@-2{{attempt to call free on non-heap object 't10'}} } void t11 () { @@ -73,7 +79,9 @@ } void t13 () { - free(^{return;}); // expected-warning {{Argument to free() is a block, which is not memory allocated by malloc()}} + free(^{return;}); + // expected-warning@-1{{Argument to free() is a block, which is not memory allocated by malloc()}} + // expected-warning@-2{{attempt to call free on non-heap object : block expression}} } void t14 (char a) { Index: clang/test/Analysis/weak-functions.c =================================================================== --- clang/test/Analysis/weak-functions.c +++ clang/test/Analysis/weak-functions.c @@ -71,7 +71,9 @@ void free(void *) __attribute__((weak_import)); void t10 () { - free((void*)&t10); // expected-warning {{Argument to free() is the address of the function 't10', which is not memory allocated by malloc()}} + free((void*)&t10); + // expected-warning@-1{{Argument to free() is the address of the function 't10', which is not memory allocated by malloc()}} + // expected-warning@-2{{attempt to call free on non-heap object 't10'}} } //===----------------------------------------------------------------------===