Hi,
I've extended the check that warns for uninitialized arguments to:
- warn for pointer arguments that point to uninitialized local (stack)
variables.
- warn for function calls with uninitialized arguments, when the corresponding
function parameter is a const reference.
void doStuff(const int *p);
void doStuffRef(const int& c);
void f(void) {
int x;
doStuff(&x); // warning
}
void g(void) {
int x;
doStuffRef(x); // warning
I've also parameterize the CallAndMessageChecker in a similar way as
CheckSecuritySyntaxOnly.
that is:
// only check if arguments are uninitialized (the old functionality only)
clang -cc1 -analyze -analyzer-checker=core.callandmessage uninit-const.cpp
// with extended functionality, i.e. "check if const pointer arguments are
uninitialized" (also performs the old check).
clang -cc1 -analyze
-analyzer-checker=alpha.core.CallAndMessageUnInitRefArgChecker uninit-const.cpp
/Per
.......................................................................................................................
Per Viberg Senior Engineer
Evidente ES East AB Warfvinges väg 34 SE-112 51 Stockholm Sweden
Phone: +46 (0)8 402 79 00
Mobile: +46 (0)70 912 42 52
E-mail: [email protected]<mailto:[email protected]>
www.evidente.se<http://www.evidente.se>
This e-mail, which might contain confidential information, is addressed to the
above stated person/company. If you are not the correct addressee, employee or
in any other way the person concerned, please notify the sender immediately. At
the same time, please delete this e-mail and destroy any prints. Thank You.
Index: lib/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- lib/StaticAnalyzer/Checkers/Checkers.td (revision 201572)
+++ lib/StaticAnalyzer/Checkers/Checkers.td (working copy)
@@ -18,6 +18,7 @@
def Core : Package<"core">;
def CoreBuiltin : Package<"builtin">, InPackage<Core>;
def CoreUninitialized : Package<"uninitialized">, InPackage<Core>;
+def CoreCallAndMessage : Package<"callandmessage">, InPackage<Core>;
def CoreAlpha : Package<"core">, InPackage<Alpha>, Hidden;
def Cplusplus : Package<"cplusplus">;
@@ -56,10 +57,6 @@
HelpText<"Check for dereferences of null pointers">,
DescFile<"DereferenceChecker.cpp">;
-def CallAndMessageChecker : Checker<"CallAndMessage">,
- HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)">,
- DescFile<"CallAndMessageChecker.cpp">;
-
def NonNullParamChecker : Checker<"NonNullParamChecker">,
HelpText<"Check for null pointers passed as arguments to a function whose arguments are references or marked with the 'nonnull' attribute">,
DescFile<"NonNullParamChecker.cpp">;
@@ -119,6 +116,10 @@
def SizeofPointerChecker : Checker<"SizeofPtr">,
HelpText<"Warn about unintended use of sizeof() on pointer expressions">,
DescFile<"CheckSizeofPointer.cpp">;
+
+def CallAndMessageUnInitRefArgChecker : Checker<"CallAndMessageUnInitRefArgChecker">,
+ HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers, and pointer to undefined variables)">,
+ DescFile<"CallAndMessageChecker.cpp">;
} // end "alpha.core"
@@ -167,6 +168,16 @@
} // end "core.uninitialized"
//===----------------------------------------------------------------------===//
+// CallAndMessage checker.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = CoreCallAndMessage in {
+def CallAndMessageChecker : Checker<"CallAndMessageChecker">,
+ HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)">,
+ DescFile<"CallAndMessageChecker.cpp">;
+}
+
+//===----------------------------------------------------------------------===//
// C++ checkers.
//===----------------------------------------------------------------------===//
Index: lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp (revision 201572)
+++ lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp (working copy)
@@ -27,6 +27,16 @@
using namespace ento;
namespace {
+
+struct ChecksFilter {
+ DefaultBool check_CallAndMessageUnInitRefArgChecker;
+ DefaultBool check_CallAndMessageChecker;
+
+ CheckName checkName_CallAndMessageUnInitRefArgChecker;
+ CheckName checkName_CallAndMessageChecker;
+};
+
+
class CallAndMessageChecker
: public Checker< check::PreStmt<CallExpr>,
check::PreStmt<CXXDeleteExpr>,
@@ -44,8 +54,13 @@
mutable OwningPtr<BugType> BT_msg_arg;
mutable OwningPtr<BugType> BT_msg_ret;
mutable OwningPtr<BugType> BT_call_few_args;
+
public:
+ ChecksFilter filter;
+ CallAndMessageChecker()
+ : filter() {}
+
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
@@ -55,7 +70,7 @@
bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange,
const Expr *argEx, bool IsFirstArgument,
bool checkUninitFields, const CallEvent &Call,
- OwningPtr<BugType> &BT) const;
+ OwningPtr<BugType> &BT, const ParmVarDecl* ParamDecl) const;
static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
@@ -114,12 +129,53 @@
}
bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
- SVal V, SourceRange argRange,
+ SVal V,
+ SourceRange argRange,
const Expr *argEx,
bool IsFirstArgument,
bool checkUninitFields,
const CallEvent &Call,
- OwningPtr<BugType> &BT) const {
+ OwningPtr<BugType> &BT,
+ const ParmVarDecl *ParamDecl
+ ) const {
+ if (filter.check_CallAndMessageUnInitRefArgChecker) {
+ // If parameter is declared as pointer to const in function declaration,
+ // then check if corresponding argument in function call is
+ // pointing to undefined symbol value (uninitialized memory).
+ bool ParamIsPointerToConst = false;
+ bool ParamIsReferenceToConst = false;
+ StringRef Message;
+
+ //ParamIsPointer
+ //ParamIsReference
+ if (ParamDecl->getType().getTypePtr()->isPointerType()) {
+ ParamIsPointerToConst = ParamDecl->getType().getTypePtr()
+ ->getPointeeType().isConstQualified();
+ Message = "Function call argument is a pointer to uninitialized value";
+ } else if (ParamDecl->getType().getTypePtr()->isReferenceType()) {
+ ParamIsReferenceToConst = ParamDecl->getType().getTypePtr()
+ ->getPointeeType().isConstQualified();
+ Message = "Function call argument is an uninitialized value";
+ }
+ if (ParamIsPointerToConst || ParamIsReferenceToConst) {
+ if (const MemRegion *SValMemRegion = V.getAsRegion()) {
+ const ProgramStateRef State = C.getState();
+ const SVal PSV = State->getSVal(SValMemRegion);
+ if (PSV.isUndef()) {
+ if (ExplodedNode *N = C.generateSink()) {
+ LazyInit_BT("Uninitialized argument value", BT);
+ BugReport *R = new BugReport(*BT,Message,N);
+ R->addRange(argRange);
+ if (argEx)
+ bugreporter::trackNullOrUndefValue(N, argEx, *R);
+ C.emitReport(R);
+ }
+ return true;
+ }
+ }
+ }
+ }
+
if (V.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
LazyInit_BT("Uninitialized argument value", BT);
@@ -311,8 +367,10 @@
State = StNonNull;
}
+
const Decl *D = Call.getDecl();
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
+ if (FD) {
// If we have a declaration, we can make sure we pass enough parameters to
// the function.
unsigned Params = FD->getNumParams();
@@ -347,11 +405,13 @@
else
BT = &BT_call_arg;
- for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i)
+ for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
+ const ParmVarDecl* ParamDecl = FD->getParamDecl(i);
if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
- checkUninitFields, Call, *BT))
+ checkUninitFields, Call, *BT, ParamDecl))
return;
+ }
// If we make it here, record our assumptions about the callee.
C.addTransition(State);
@@ -511,6 +571,14 @@
C.addTransition(state);
}
-void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
- mgr.registerChecker<CallAndMessageChecker>();
-}
+#define REGISTER_CHECKER(name) \
+ void ento::register##name(CheckerManager &mgr) { \
+ CallAndMessageChecker *checker = \
+ mgr.registerChecker<CallAndMessageChecker>(); \
+ checker->filter.check_##name = true; \
+ checker->filter.checkName_##name = mgr.getCurrentCheckName(); \
+ }
+
+REGISTER_CHECKER(CallAndMessageUnInitRefArgChecker)
+REGISTER_CHECKER(CallAndMessageChecker)
+
Index: test/Analysis/uninit-const.c
===================================================================
--- test/Analysis/uninit-const.c (revision 0)
+++ test/Analysis/uninit-const.c (working copy)
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.CallAndMessageUnInitRefArgChecker uninit-const.c -verify %s
+// Passing uninitialized const data to function
+
+
+void doStuff3(const int y){}
+void doStuff2(int g){}
+void doStuff_uninit(const int *u){};
+
+void f5(void) {
+ int t;
+ int* tp = &t;
+ doStuff_uninit(tp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
+}
+
+
+void f4(void) {
+ int y;
+ doStuff3(y); // expected-warning {{Function call argument is an uninitialized value}}
+}
+
+void f3(void) {
+ int g;
+ doStuff2(g); // expected-warning {{Function call argument is an uninitialized value}}
+}
+
+int z;
+void f2(void) {
+ doStuff_uninit(&z); // no warning
+}
+
+void f1(void) {
+ int x_=5;
+ doStuff_uninit(&x_); // no warning
+}
+
+void f_uninit(void) {
+ int x;
+ doStuff_uninit(&x); // expected-warning {{Function call argument is a pointer to uninitialized value}}
+}
Index: test/Analysis/uninit-const.cpp
===================================================================
--- test/Analysis/uninit-const.cpp (revision 0)
+++ test/Analysis/uninit-const.cpp (working copy)
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.CallAndMessageUnInitRefArgChecker uninit-const.cpp -verify %s
+// Passing uninitialized const data to unknown function
+
+void doStuff6(const int& c);
+void doStuff4(const int y);
+void doStuff3(int& g);
+void doStuff_uninit(const int *u);
+
+
+void f7(void) {
+ int m = 3;
+ doStuff6(m); // no warning
+}
+
+void f6(void) {
+ int k;
+ doStuff6(k); // expected-warning {{Function call argument is an uninitialized value}}
+}
+
+void f5(void) {
+ int t;
+ int* tp = &t;
+ doStuff_uninit(tp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
+}
+
+
+void f4(void) {
+ int y;
+ doStuff4(y); // expected-warning {{Function call argument is an uninitialized value}}
+}
+
+void f3(void) {
+ int g;
+ doStuff3(g); // no warning
+}
+
+int z;
+void f2(void) {
+ doStuff_uninit(&z); // no warning
+}
+
+void f1(void) {
+ int x_=5;
+ doStuff_uninit(&x_); // no warning
+}
+
+void f_uninit(void) {
+ int x;
+ doStuff_uninit(&x); // expected-warning {{Function call argument is a pointer to uninitialized value}}
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits