From 1614e35408275478b24b45621395e2d9a2e9aa68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirst=C3=B3f=20Umann?= Date: Fri, 12 Jun 2020 18:15:20 +0200 Subject: [PATCH] [analyzer][MallocChecker] PR46253: Correctly recognize standard realloc https://bugs.llvm.org/show_bug.cgi?id=46253 This is an obvious hack because realloc isn't any more affected than other functions modeled by MallocChecker (or any user of CallDescription really), but the nice solution will take some time to implement. Differential Revision: https://reviews.llvm.org/D81745 --- .../StaticAnalyzer/Checkers/MallocChecker.cpp | 40 ++++++++++++++++++- clang/test/Analysis/malloc.cpp | 18 +++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index fb6d02b9ed60..d5b0a5b2220f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -47,6 +47,7 @@ #include "AllocationState.h" #include "InterCheckerAPI.h" #include "clang/AST/Attr.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ParentMap.h" @@ -1037,9 +1038,44 @@ void MallocChecker::checkKernelMalloc(const CallEvent &Call, C.addTransition(State); } -void MallocChecker::checkRealloc(const CallEvent &Call, - CheckerContext &C, +static bool isStandardRealloc(const CallEvent &Call) { + const FunctionDecl *FD = dyn_cast(Call.getDecl()); + assert(FD); + ASTContext &AC = FD->getASTContext(); + + if (isa(FD)) + return false; + + return FD->getDeclaredReturnType().getDesugaredType(AC) == AC.VoidPtrTy && + FD->getParamDecl(0)->getType().getDesugaredType(AC) == AC.VoidPtrTy && + FD->getParamDecl(1)->getType().getDesugaredType(AC) == + AC.getSizeType(); +} + +static bool isGRealloc(const CallEvent &Call) { + const FunctionDecl *FD = dyn_cast(Call.getDecl()); + assert(FD); + ASTContext &AC = FD->getASTContext(); + + if (isa(FD)) + return false; + + return FD->getDeclaredReturnType().getDesugaredType(AC) == AC.VoidPtrTy && + FD->getParamDecl(0)->getType().getDesugaredType(AC) == AC.VoidPtrTy && + FD->getParamDecl(1)->getType().getDesugaredType(AC) == + AC.UnsignedLongTy; +} + +void MallocChecker::checkRealloc(const CallEvent &Call, CheckerContext &C, bool ShouldFreeOnFail) const { + // HACK: CallDescription currently recognizes non-standard realloc functions + // as standard because it doesn't check the type, or wether its a non-method + // function. This should be solved by making CallDescription smarter. + // Mind that this came from a bug report, and all other functions suffer from + // this. + // https://bugs.llvm.org/show_bug.cgi?id=46253 + if (!isStandardRealloc(Call) && !isGRealloc(Call)) + return; ProgramStateRef State = C.getState(); State = ReallocMemAux(C, Call, ShouldFreeOnFail, State, AF_Malloc); State = ProcessZeroAllocCheck(Call, 1, State); diff --git a/clang/test/Analysis/malloc.cpp b/clang/test/Analysis/malloc.cpp index cc7fefe23d75..21e8e79e1a89 100644 --- a/clang/test/Analysis/malloc.cpp +++ b/clang/test/Analysis/malloc.cpp @@ -172,3 +172,21 @@ void test_delete_ZERO_SIZE_PTR() { // ZERO_SIZE_PTR is specially handled but only for malloc family delete Ptr; // expected-warning{{Argument to 'delete' is a constant address (16)}} } + +namespace pr46253_class { +class a { + void *realloc(int, bool = false) { realloc(1); } // no-crash +}; +} // namespace pr46253_class + +namespace pr46253_retty{ +void realloc(void *ptr, size_t size) { realloc(ptr, size); } // no-crash +} // namespace pr46253_retty + +namespace pr46253_paramty{ +void *realloc(void **ptr, size_t size) { realloc(ptr, size); } // no-crash +} // namespace pr46253_paramty + +namespace pr46253_paramty2{ +void *realloc(void *ptr, int size) { realloc(ptr, size); } // no-crash +} // namespace pr46253_paramty2