diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h @@ -23,11 +23,16 @@ namespace ento { class BugReport; +class PathDiagnosticLocation; class BugSuppression { public: /// Return true if the given bug report was explicitly suppressed by the user. bool isSuppressed(const BugReport &); + /// Return true if the bug reported at the given location was explicitly + /// suppressed by the user. + bool isSuppressed(const PathDiagnosticLocation &Location, + const Decl *DeclWithIssue); private: // Overly pessimistic number, to be honest. diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -2386,11 +2386,10 @@ return Ranges; } -PathDiagnosticLocation -PathSensitiveBugReport::getLocation() const { +PathDiagnosticLocation PathSensitiveBugReport::getLocation() const { assert(ErrorNode && "Cannot create a location with a null node."); const Stmt *S = ErrorNode->getStmtForDiagnostics(); - ProgramPoint P = ErrorNode->getLocation(); + ProgramPoint P = ErrorNode->getLocation(); const LocationContext *LC = P.getLocationContext(); SourceManager &SM = ErrorNode->getState()->getStateManager().getContext().getSourceManager(); @@ -2407,6 +2406,12 @@ } if (S) { + // Attributed statements usually have corrupted begin locations, + // it's OK to ignore attributes for our purposes and deal with + // the actual annotated statement. + if (const auto *AS = dyn_cast(S)) + S = AS->getSubStmt(); + // For member expressions, return the location of the '.' or '->'. if (const auto *ME = dyn_cast(S)) return PathDiagnosticLocation::createMemberLoc(ME, SM); diff --git a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp --- a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp @@ -132,8 +132,15 @@ // (i.e. removing the whole function from the analysis). bool BugSuppression::isSuppressed(const BugReport &R) { PathDiagnosticLocation Location = R.getLocation(); + PathDiagnosticLocation UniqueingLocation = R.getUniqueingLocation(); const Decl *DeclWithIssue = R.getDeclWithIssue(); + return isSuppressed(Location, DeclWithIssue) || + isSuppressed(UniqueingLocation, DeclWithIssue); +} + +bool BugSuppression::isSuppressed(const PathDiagnosticLocation &Location, + const Decl *DeclWithIssue) { if (!Location.isValid() || DeclWithIssue == nullptr) return false; diff --git a/clang/test/Analysis/suppression-attr.m b/clang/test/Analysis/suppression-attr.m --- a/clang/test/Analysis/suppression-attr.m +++ b/clang/test/Analysis/suppression-attr.m @@ -4,6 +4,7 @@ // RUN: -analyzer-checker=osx.cocoa.NSError \ // RUN: -analyzer-checker=osx.ObjCProperty \ // RUN: -analyzer-checker=osx.cocoa.RetainCount \ +// RUN: -analyzer-checker=unix.Malloc \ // RUN: -analyzer-checker=alpha.core.CastToStruct \ // RUN: -Wno-unused-value -Wno-objc-root-class -verify %s @@ -37,6 +38,10 @@ @interface NSMutableString : NSObject @end +typedef unsigned long size_t; +void *malloc(size_t); +void free(void *); + void dereference_1() { int *x = 0; *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} @@ -83,6 +88,50 @@ SUPPRESS int y = *x; // no-warning } +int malloc_leak_1() { + int *x = (int *)malloc(sizeof(int)); + *x = 42; + return *x; // expected-warning{{Potential leak of memory pointed to by 'x'}} +} + +int malloc_leak_suppression_1_1() { + SUPPRESS int *x = (int *)malloc(sizeof(int)); + *x = 42; + return *x; +} + +int malloc_leak_suppression_1_2() { + int *x = (int *)malloc(sizeof(int)); + *x = 42; + SUPPRESS return *x; +} + +void malloc_leak_2() { + int *x = (int *)malloc(sizeof(int)); + *x = 42; +} // expected-warning{{Potential leak of memory pointed to by 'x'}} + +void malloc_leak_suppression_2_1() { + SUPPRESS int *x = (int *)malloc(sizeof(int)); + *x = 42; +} + +void malloc_leak_suppression_2_2() SUPPRESS { + int *x = (int *)malloc(sizeof(int)); + *x = 42; +} + +SUPPRESS void malloc_leak_suppression_2_3() { + int *x = (int *)malloc(sizeof(int)); + *x = 42; +} + +void malloc_leak_suppression_2_4(int cond) { + int *x = (int *)malloc(sizeof(int)); + *x = 42; + SUPPRESS; +} + void retain_release_leak_1() { [[NSMutableString alloc] init]; // expected-warning{{Potential leak of an object of type 'NSMutableString *'}} }