diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-09-22 01:25:06 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-09-22 01:25:06 +0000 |
commit | b9d4e5e3bb235f1149e99d3c833ff7cb3474c9f1 (patch) | |
tree | 99fbff9f24fa7164b0bde76e7a0c3c5af4cb0475 /test/Analysis/inlining | |
parent | 53221da865144db0ba6bd89ab30bcf81de0fe5d2 (diff) |
[analyzer] Suppress bugs whose paths go through the return of a null pointer.
This is a heuristic intended to greatly reduce the number of false
positives resulting from inlining, particularly inlining of generic,
defensive C++ methods that live in header files. The suppression is
triggered in the cases where we ask to track where a null pointer came
from, and it turns out that the source of the null pointer was an inlined
function call.
This change brings the number of bug reports in LLVM from ~1500 down to
around ~300, a much more manageable number. Yes, some true positives may
be hidden as well, but from what I looked at the vast majority of silenced
reports are false positives, and many of the true issues found by the
analyzer are still reported.
I'm hoping to improve this heuristic further by adding some exceptions
next week (cases in which a bug should still be reported).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164449 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Analysis/inlining')
-rw-r--r-- | test/Analysis/inlining/false-positive-suppression.c | 95 | ||||
-rw-r--r-- | test/Analysis/inlining/path-notes.c | 4 | ||||
-rw-r--r-- | test/Analysis/inlining/path-notes.m | 4 |
3 files changed, 99 insertions, 4 deletions
diff --git a/test/Analysis/inlining/false-positive-suppression.c b/test/Analysis/inlining/false-positive-suppression.c new file mode 100644 index 0000000000..be485e0c1c --- /dev/null +++ b/test/Analysis/inlining/false-positive-suppression.c @@ -0,0 +1,95 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -DSUPPRESSED %s + +int opaquePropertyCheck(void *object); +int coin(); + +int *dynCastToInt(void *ptr) { + if (opaquePropertyCheck(ptr)) + return (int *)ptr; + return 0; +} + +int *dynCastOrNull(void *ptr) { + if (!ptr) + return 0; + if (opaquePropertyCheck(ptr)) + return (int *)ptr; + return 0; +} + + +void testDynCast(void *p) { + int *casted = dynCastToInt(p); + *casted = 1; +#ifndef SUPPRESSED + // expected-warning@-2 {{Dereference of null pointer}} +#endif +} + +void testDynCastOrNull(void *p) { + int *casted = dynCastOrNull(p); + *casted = 1; +#ifndef SUPPRESSED + // expected-warning@-2 {{Dereference of null pointer}} +#endif +} + + +void testBranch(void *p) { + int *casted; + + // Although the report will be suppressed on one branch, it should still be + // valid on the other. + if (coin()) { + casted = dynCastToInt(p); + } else { + if (p) + return; + casted = (int *)p; + } + + *casted = 1; // expected-warning {{Dereference of null pointer}} +} + +void testBranchReversed(void *p) { + int *casted; + + // Although the report will be suppressed on one branch, it should still be + // valid on the other. + if (coin()) { + if (p) + return; + casted = (int *)p; + } else { + casted = dynCastToInt(p); + } + + *casted = 1; // expected-warning {{Dereference of null pointer}} +} + + +// --------------------------------------- +// FALSE NEGATIVES (over-suppression) +// --------------------------------------- + +void testDynCastOrNullOfNull() { + // In this case we have a known value for the argument, and thus the path + // through the function doesn't ever split. + int *casted = dynCastOrNull(0); + *casted = 1; +#ifndef SUPPRESSED + // expected-warning@-2 {{Dereference of null pointer}} +#endif +} + +void testDynCastOfNull() { + // In this case all paths out of the function return 0, but they are all + // dominated by a branch whose condition we don't know! + int *casted = dynCastToInt(0); + *casted = 1; +#ifndef SUPPRESSED + // expected-warning@-2 {{Dereference of null pointer}} +#endif +} + diff --git a/test/Analysis/inlining/path-notes.c b/test/Analysis/inlining/path-notes.c index bd44f0c895..763614d9aa 100644 --- a/test/Analysis/inlining/path-notes.c +++ b/test/Analysis/inlining/path-notes.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s -// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file %s -o %t.plist +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config suppress-null-return-paths=false -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false %s -o %t.plist // RUN: FileCheck --input-file=%t.plist %s void zero(int **p) { diff --git a/test/Analysis/inlining/path-notes.m b/test/Analysis/inlining/path-notes.m index 1b67051bfa..b15b869682 100644 --- a/test/Analysis/inlining/path-notes.m +++ b/test/Analysis/inlining/path-notes.m @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s -// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file %s -o %t.plist +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config suppress-null-return-paths=false -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false %s -o %t.plist // RUN: FileCheck --input-file=%t.plist %s @interface Test |