diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 3a4c15f0d20d..de48769d7852 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -44,7 +44,10 @@ private: static void PreVisitProcessArgs(CheckerContext &C,CallOrObjCMessage callOrMsg, const char *BT_desc, OwningPtr &BT); static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange, - const Expr *argEx, const char *BT_desc, OwningPtr &BT); + const Expr *argEx, + const bool checkUninitFields, + const char *BT_desc, + OwningPtr &BT); static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg, @@ -77,9 +80,19 @@ void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg, const char *BT_desc, OwningPtr &BT) { + // Don't check for uninitialized field values in arguments if the + // caller has a body that is available and we have the chance to inline it. + // This is a hack, but is a reasonable compromise betweens sometimes warning + // and sometimes not depending on if we decide to inline a function. + const Decl *D = callOrMsg.getDecl(); + const bool checkUninitFields = + !(C.getAnalysisManager().shouldInlineCall() && + (D && D->getBody())); + for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i) if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i), callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i), + checkUninitFields, BT_desc, BT)) return; } @@ -87,9 +100,9 @@ void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C, bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange, const Expr *argEx, + const bool checkUninitFields, const char *BT_desc, OwningPtr &BT) { - if (V.isUndef()) { if (ExplodedNode *N = C.generateSink()) { LazyInit_BT(BT_desc, BT); @@ -104,6 +117,9 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, return true; } + if (!checkUninitFields) + return false; + if (const nonloc::LazyCompoundVal *LV = dyn_cast(&V)) { diff --git a/clang/test/Analysis/inline.c b/clang/test/Analysis/inline.c index 9e64d33690d1..6acbeb959ac6 100644 --- a/clang/test/Analysis/inline.c +++ b/clang/test/Analysis/inline.c @@ -77,3 +77,16 @@ char *test_return_stack_memory_bad() { return x; // expected-warning {{stack memory associated}} } +// Test that passing a struct value with an uninitialized field does +// not trigger a warning if we are inlining and the body is available. +struct rdar10977037 { int x, y; }; +int test_rdar10977037_aux(struct rdar10977037 v) { return v.y; } +int test_rdar10977037_aux_2(struct rdar10977037 v); +int test_rdar10977037() { + struct rdar10977037 v; + v.y = 1; + v. y += test_rdar10977037_aux(v); // no-warning + return test_rdar10977037_aux_2(v); // expected-warning {{Passed-by-value struct argument contains uninitialized data}} +} + +