From ab4f3cb21c8624913d7b7f676f66a86ce3dae1de Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Mon, 13 Oct 2014 19:38:02 +0000 Subject: [PATCH] [analyzer] Check all 'nonnull' attributes, not just the first one. Patch by Daniel Fahlgren! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219625 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Checkers/NonNullParamChecker.cpp | 21 +++- test/Analysis/nonnull.m | 98 +++++++++++++++++++ 2 files changed, 114 insertions(+), 5 deletions(-) diff --git a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp index 650aa8b875..cb2d46b583 100644 --- a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp @@ -49,16 +49,27 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call, if (!FD) return; - // FIXME: This is wrong; there can be multiple attributes with different sets - // of non-null parameter indices. - const NonNullAttr *Att = FD->getAttr(); + // Merge all non-null attributes + unsigned NumArgs = Call.getNumArgs(); + llvm::SmallBitVector AttrNonNull(NumArgs); + for (const auto *NonNull : FD->specific_attrs()) { + if (!NonNull->args_size()) { + AttrNonNull.set(0, NumArgs); + break; + } + for (unsigned Val : NonNull->args()) { + if (Val >= NumArgs) + continue; + AttrNonNull.set(Val); + } + } ProgramStateRef state = C.getState(); CallEvent::param_type_iterator TyI = Call.param_type_begin(), TyE = Call.param_type_end(); - for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx){ + for (unsigned idx = 0; idx < NumArgs; ++idx) { // Check if the parameter is a reference. We want to report when reference // to a null pointer is passed as a paramter. @@ -68,7 +79,7 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call, TyI++; } - bool haveAttrNonNull = Att && Att->isNonNull(idx); + bool haveAttrNonNull = AttrNonNull[idx]; if (!haveAttrNonNull) { // Check if the parameter is also marked 'nonnull'. ArrayRef parms = Call.parameters(); diff --git a/test/Analysis/nonnull.m b/test/Analysis/nonnull.m index 3de87fbdcb..c21360ded8 100644 --- a/test/Analysis/nonnull.m +++ b/test/Analysis/nonnull.m @@ -76,6 +76,104 @@ int rdar16153464(union rdar16153464_full_ctx_t inner) rdar16153464_check(0); // expected-warning{{nonnull}} } +// Multiple attributes, the basic case +void multipleAttributes_1(char *p, char *q) __attribute((nonnull(1))) __attribute((nonnull(2))); + +void testMultiple_1(void) { + char c; + multipleAttributes_1(&c, &c); // no-warning +} + +void testMultiple_2(void) { + char c; + multipleAttributes_1(0, &c); // expected-warning{{nonnull}} +} + +void testMultiple_3(void) { + char c; + multipleAttributes_1(&c, 0); // expected-warning{{nonnull}} +} + +void testMultiple_4(void) { + multipleAttributes_1(0, 0);// expected-warning{{nonnull}} +} + +// Multiple attributes, multiple prototypes +void multipleAttributes_2(char *p, char *q) __attribute((nonnull(1))); +void multipleAttributes_2(char *p, char *q) __attribute((nonnull(2))); + +void testMultiple_5(void) { + char c; + multipleAttributes_2(0, &c);// expected-warning{{nonnull}} +} + +void testMultiple_6(void) { + char c; + multipleAttributes_2(&c, 0);// expected-warning{{nonnull}} +} + +void testMultiple_7(void) { + multipleAttributes_2(0, 0);// expected-warning{{nonnull}} +} + +// Multiple attributes, same index +void multipleAttributes_3(char *p, char *q) __attribute((nonnull(1))) __attribute((nonnull(1))); + +void testMultiple_8(void) { + char c; + multipleAttributes_3(0, &c); // expected-warning{{nonnull}} +} + +void testMultiple_9(void) { + char c; + multipleAttributes_3(&c, 0); // no-warning +} + +// Multiple attributes, the middle argument is missing an attribute +void multipleAttributes_4(char *p, char *q, char *r) __attribute((nonnull(1))) __attribute((nonnull(3))); + +void testMultiple_10(void) { + char c; + multipleAttributes_4(0, &c, &c); // expected-warning{{nonnull}} +} + +void testMultiple_11(void) { + char c; + multipleAttributes_4(&c, 0, &c); // no-warning +} + +void testMultiple_12(void) { + char c; + multipleAttributes_4(&c, &c, 0); // expected-warning{{nonnull}} +} + + +// Multiple attributes, when the last is without index +void multipleAttributes_all_1(char *p, char *q) __attribute((nonnull(1))) __attribute((nonnull)); + +void testMultiple_13(void) { + char c; + multipleAttributes_all_1(0, &c); // expected-warning{{nonnull}} +} + +void testMultiple_14(void) { + char c; + multipleAttributes_all_1(&c, 0); // expected-warning{{nonnull}} +} + +// Multiple attributes, when the first is without index +void multipleAttributes_all_2(char *p, char *q) __attribute((nonnull)) __attribute((nonnull(2))); + +void testMultiple_15(void) { + char c; + multipleAttributes_all_2(0, &c); // expected-warning{{nonnull}} +} + +void testMultiple_16(void) { + char c; + multipleAttributes_all_2(&c, 0); // expected-warning{{nonnull}} +} + void testVararg(int k, void *p) { extern void testVararg_check(int, ...) __attribute__((nonnull)); void *n = 0; -- 2.50.1