[cfe-commits] r161357 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h lib/StaticAnalyzer/Checkers/CMakeLists.txt lib/StaticAnalyzer/Checkers/Checkers.td lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp lib/StaticAnalyzer/Core/CallEvent.cpp lib/StaticAnalyzer/Core/ExprEngineC.cpp lib/StaticAnalyzer/Core/ProgramState.cpp test/Analysis/inlining/InlineObjCInstanceMethod.m test/Analysis/inlining/ObjCDynTypePopagation.m
Anna Zaks
ganna at apple.com
Mon Aug 6 16:25:40 PDT 2012
Author: zaks
Date: Mon Aug 6 18:25:39 2012
New Revision: 161357
URL: http://llvm.org/viewvc/llvm-project?rev=161357&view=rev
Log:
[analyzer] Add a checker to manage dynamic type propagation.
Instead of sprinkling dynamic type info propagation throughout
ExprEngine, the added checker would add the more precise type
information on known APIs (Ex: ObjC alloc, new) and propagate
the type info in other cases (ex: ObjC init method, casts (the second is
not implemented yet)).
Add handling of ObjC alloc, new and init to the checker.
Added:
cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
cfe/trunk/test/Analysis/inlining/ObjCDynTypePopagation.m
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td
cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp
cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.m
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h?rev=161357&r1=161356&r2=161357&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h Mon Aug 6 18:25:39 2012
@@ -92,6 +92,10 @@
return Pred->getLocationContext();
}
+ const StackFrameContext *getCurrentStackFrame() const {
+ return getLocationContext()->getCurrentStackFrame();
+ }
+
BugReporter &getBugReporter() {
return Eng.getBugReporter();
}
@@ -132,6 +136,11 @@
return 0;
}
+ /// \brief Get the value of arbitrary expressions at this point in the path.
+ SVal getSVal(const Stmt *S) const {
+ return getState()->getSVal(S, getLocationContext());
+ }
+
/// \brief Generates a new transition in the program state graph
/// (ExplodedGraph). Uses the default CheckerContext predecessor node.
///
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h?rev=161357&r1=161356&r2=161357&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h Mon Aug 6 18:25:39 2012
@@ -331,10 +331,18 @@
bool isTainted(SymbolRef Sym, TaintTagType Kind = TaintTagGeneric) const;
bool isTainted(const MemRegion *Reg, TaintTagType Kind=TaintTagGeneric) const;
- /// Get dynamic type information for a region.
+ /// \brief Get dynamic type information for a region.
DynamicTypeInfo getDynamicTypeInfo(const MemRegion *Reg) const;
- /// Add dynamic type information to the region and return the new state.
- ProgramStateRef addDynamicTypeInfo(const MemRegion *Reg, QualType NewTy)const;
+
+ /// \brief Add dynamic type information to the region; return the new state.
+ ProgramStateRef addDynamicTypeInfo(const MemRegion *Reg,
+ DynamicTypeInfo NewTy) const;
+
+ /// \brief Add dynamic type information to the region; return the new state.
+ ProgramStateRef addDynamicTypeInfo(const MemRegion *Reg,
+ QualType NewTy) const {
+ return addDynamicTypeInfo(Reg, DynamicTypeInfo(NewTy));
+ }
//==---------------------------------------------------------------------==//
// Accessing the Generic Data Map (GDM).
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt?rev=161357&r1=161356&r2=161357&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt Mon Aug 6 18:25:39 2012
@@ -29,6 +29,7 @@
DebugCheckers.cpp
DereferenceChecker.cpp
DivZeroChecker.cpp
+ DynamicTypePropagation.cpp
ExprInspectionChecker.cpp
FixedAddressChecker.cpp
GenericTaintChecker.cpp
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td?rev=161357&r1=161356&r2=161357&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td Mon Aug 6 18:25:39 2012
@@ -84,6 +84,10 @@
HelpText<"Check that addresses to stack memory do not escape the function">,
DescFile<"StackAddrEscapeChecker.cpp">;
+def DynamicTypePropagation : Checker<"DynamicTypePropagation">,
+ HelpText<"Generate dynamic type information">,
+ DescFile<"DynamicTypePropagation.cpp">;
+
} // end "core"
let ParentPackage = CoreExperimental in {
Added: cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp?rev=161357&view=auto
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp (added)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp Mon Aug 6 18:25:39 2012
@@ -0,0 +1,116 @@
+//== DynamicTypePropagation.cpp ----------------------------------- -*- C++ -*--=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker defines the rules for dynamic type gathering and propagation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/Basic/Builtins.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class DynamicTypePropagation : public Checker< check::PostCall > {
+ const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
+ CheckerContext &C) const;
+public:
+ void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
+};
+}
+
+void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ // We can obtain perfect type info for return values from some calls.
+ if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
+
+ // Get the returned value if it's a region.
+ SVal Result = C.getSVal(Call.getOriginExpr());
+ const MemRegion *RetReg = Result.getAsRegion();
+ if (!RetReg)
+ return;
+
+ ProgramStateRef State = C.getState();
+
+ switch (Msg->getMethodFamily()) {
+ default:
+ break;
+
+ // We assume that the type of the object returned by alloc and new are the
+ // pointer to the object of the class specified in the receiver of the
+ // message.
+ case OMF_alloc:
+ case OMF_new: {
+ // Get the type of object that will get created.
+ const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
+ const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
+ if (!ObjTy)
+ return;
+ QualType DynResTy =
+ C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
+ C.addTransition(State->addDynamicTypeInfo(RetReg, DynResTy));
+ break;
+ }
+ case OMF_init: {
+ // Assume, the result of the init method has the same dynamic type as
+ // the receiver and propagate the dynamic type info.
+ const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
+ assert(RecReg);
+ DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg);
+ C.addTransition(State->addDynamicTypeInfo(RetReg, RecDynType));
+ break;
+ }
+ }
+ }
+}
+
+const ObjCObjectType *
+DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
+ CheckerContext &C) const {
+ if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) {
+ if (const ObjCObjectType *ObjTy
+ = MsgE->getClassReceiver()->getAs<ObjCObjectType>())
+ return ObjTy;
+ }
+
+ if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) {
+ if (const ObjCObjectType *ObjTy
+ = MsgE->getSuperType()->getAs<ObjCObjectType>())
+ return ObjTy;
+ }
+
+ const Expr *RecE = MsgE->getInstanceReceiver();
+ if (!RecE)
+ return 0;
+
+ RecE= RecE->IgnoreParenImpCasts();
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) {
+ const StackFrameContext *SFCtx = C.getCurrentStackFrame();
+ // Are we calling [self alloc]? If this is self, get the type of the
+ // enclosing ObjC class.
+ if (DRE->getDecl() == SFCtx->getSelfDecl()) {
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl()))
+ if (const ObjCObjectType *ObjTy =
+ dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl()))
+ return ObjTy;
+ }
+ }
+ return 0;
+}
+
+void ento::registerDynamicTypePropagation(CheckerManager &mgr) {
+ mgr.registerChecker<DynamicTypePropagation>();
+}
Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp?rev=161357&r1=161356&r2=161357&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Mon Aug 6 18:25:39 2012
@@ -583,8 +583,8 @@
if (!isInstanceMessage())
return UnknownVal();
- if (const Expr *Base = getOriginExpr()->getInstanceReceiver())
- return getSVal(Base);
+ if (const Expr *RecE = getOriginExpr()->getInstanceReceiver())
+ return getSVal(RecE);
// An instance message with no expression means we are sending to super.
// In this case the object reference is the same as 'self'.
@@ -676,8 +676,8 @@
if (!Receiver)
return 0;
- DynamicTypeInfo TI = getState()->getDynamicTypeInfo(Receiver);
- ReceiverT = dyn_cast<ObjCObjectPointerType>(TI.getType().getTypePtr());
+ QualType DynType = getState()->getDynamicTypeInfo(Receiver).getType();
+ ReceiverT = dyn_cast<ObjCObjectPointerType>(DynType.getTypePtr());
}
// Lookup the method implementation.
@@ -715,7 +715,6 @@
}
}
-
CallEventRef<SimpleCall>
CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
const LocationContext *LCtx) {
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp?rev=161357&r1=161356&r2=161357&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp Mon Aug 6 18:25:39 2012
@@ -308,9 +308,6 @@
const LocationContext *LCtx = Pred->getLocationContext();
SVal V = state->getSVal(Ex, LCtx);
V = svalBuilder.evalCast(V, T, ExTy);
- if (const MemRegion *R = V.getAsRegion()) {
- state = state->addDynamicTypeInfo(R, T);
- }
state = state->BindExpr(CastE, LCtx, V);
Bldr.generateNode(CastE, Pred, state);
continue;
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp?rev=161357&r1=161356&r2=161357&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp Mon Aug 6 18:25:39 2012
@@ -762,12 +762,12 @@
}
ProgramStateRef ProgramState::addDynamicTypeInfo(const MemRegion *Reg,
- QualType NewTy) const {
+ DynamicTypeInfo NewTy) const {
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg)) {
SymbolRef Sym = SR->getSymbol();
// TODO: Instead of resetting the type info, check the old type info and
// merge and pick the most precise type.
- ProgramStateRef NewState = set<DynamicTypeMap>(Sym, DynamicTypeInfo(NewTy));
+ ProgramStateRef NewState = set<DynamicTypeMap>(Sym, NewTy);
assert(NewState);
return NewState;
}
Modified: cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.m?rev=161357&r1=161356&r2=161357&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.m (original)
+++ cfe/trunk/test/Analysis/inlining/InlineObjCInstanceMethod.m Mon Aug 6 18:25:39 2012
@@ -29,7 +29,7 @@
// Method is called on inited object.
+ (int)testAllocInit2 {
MyClass *a = [[MyClass alloc] init];
- return 5/[a getInt]; // todo
+ return 5/[a getInt]; // expected-warning {{Division by zero}}
}
// Method is called on a parameter.
Added: cfe/trunk/test/Analysis/inlining/ObjCDynTypePopagation.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/ObjCDynTypePopagation.m?rev=161357&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/inlining/ObjCDynTypePopagation.m (added)
+++ cfe/trunk/test/Analysis/inlining/ObjCDynTypePopagation.m Mon Aug 6 18:25:39 2012
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=dynamic -verify %s
+
+typedef signed char BOOL;
+
+void clang_analyzer_eval(BOOL);
+
+ at protocol NSObject - (BOOL)isEqual:(id)object; @end
+ at interface NSObject <NSObject> {}
++(id)alloc;
+-(id)init;
++(id)new;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+ at end
+
+ at interface MyParent : NSObject
+- (int)getZeroOverridden;
+ at end
+ at implementation MyParent
+- (int) getZeroOverridden {
+ return 1;
+}
+- (int) getZero {
+ return 0;
+}
+ at end
+
+ at interface MyClass : MyParent
+- (int) getZeroOverridden;
+ at end
+
+MyClass *getObj();
+
+ at implementation MyClass
+- (int) getZeroOverridden {
+ return 0;
+}
+
+/* Test that we get the right type from call to alloc. */
+
++ (void) testAllocSelf {
+ id a = [self alloc];
+ clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
+}
+
+
++ (void) testAllocClass {
+ id a = [MyClass alloc];
+ clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
+}
+
++ (void) testAllocSuperOverriden {
+ id a = [super alloc];
+ // Evaluates to 1 in the parent.
+ clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{FALSE}}
+}
+
++ (void) testAllocSuper {
+ id a = [super alloc];
+ clang_analyzer_eval([a getZero] == 0); // expected-warning{{TRUE}}
+}
+
++ (void) testAllocInit {
+ id a = [[self alloc] init];
+ clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
+}
+
++ (void) testNewSelf {
+ id a = [self new];
+ clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
+}
+
+ at end
\ No newline at end of file
More information about the cfe-commits
mailing list