diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h index f01bad02c203..8fc4050c7e08 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h @@ -199,10 +199,16 @@ public: /// Check if the callee is declared in the system header. bool isInSystemHeader() const { - if (const Decl *FD = getDecl()) { + if (const Decl *D = getDecl()) { const SourceManager &SM = State->getStateManager().getContext().getSourceManager(); - return SM.isInSystemHeader(FD->getLocation()); + SourceLocation Loc = D->getLocation(); + // Be careful: the implicit declarations of operator new/delete have + // invalid source locations but should still count as system files. + if (Loc.isValid()) + return SM.isInSystemHeader(D->getLocation()); + else if (const FunctionDecl *FD = dyn_cast(D)) + return FD->isOverloadedOperator() && FD->isImplicit() && FD->isGlobal(); } return false; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 50d4273e48c0..1aa9b824e306 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1338,8 +1338,7 @@ bool MallocChecker::doesNotFreeMemory(const CallOrObjCMessage *Call, } // If it's not a system call, assume it frees memory. - SourceManager &SM = ASTC.getSourceManager(); - if (!SM.isInSystemHeader(D->getLocation())) + if (!Call->isInSystemHeader()) return false; // Process C/ObjC functions. diff --git a/clang/test/Analysis/new.cpp b/clang/test/Analysis/new.cpp index 8093eff3a1c2..723d033bc794 100644 --- a/clang/test/Analysis/new.cpp +++ b/clang/test/Analysis/new.cpp @@ -5,6 +5,21 @@ void clang_analyzer_eval(bool); typedef typeof(sizeof(int)) size_t; extern "C" void *malloc(size_t); +int someGlobal; +void testImplicitlyDeclaredGlobalNew() { + if (someGlobal != 0) + return; + + // This used to crash because the global operator new is being implicitly + // declared and it does not have a valid source location. (PR13090) + void *x = ::operator new(0); + ::operator delete(x); + + // Check that the new/delete did not invalidate someGlobal; + clang_analyzer_eval(someGlobal == 0); // expected-warning{{TRUE}} +} + + // This is the standard placement new. inline void* operator new(size_t, void* __p) throw() {