void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, BranchNodeBuilder &Builder, ExprEngine &Eng) const { const GRState *state = Builder.getState(); SVal X = state->getSVal(Condition); if (X.isUndef()) { ExplodedNode *N = Builder.generateNode(state, true); if (N) { N->markAsSink(); if (!BT) BT.reset( new BuiltinBug("Branch condition evaluates to a garbage value")); // What's going on here: we want to highlight the subexpression of the // condition that is the most likely source of the "uninitialized // branch condition." We do a recursive walk of the condition's // subexpressions and roughly look for the most nested subexpression // that binds to Undefined. We then highlight that expression's range. BlockEdge B = cast<BlockEdge>(N->getLocation()); const Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition()); assert (Ex && "Block must have a terminator."); // Get the predecessor node and check if is a PostStmt with the Stmt // being the terminator condition. We want to inspect the state // of that node instead because it will contain main information about // the subexpressions. assert (!N->pred_empty()); // Note: any predecessor will do. They should have identical state, // since all the BlockEdge did was act as an error sink since the value // had to already be undefined. ExplodedNode *PrevN = *N->pred_begin(); ProgramPoint P = PrevN->getLocation(); const GRState* St = N->getState(); if (PostStmt* PS = dyn_cast<PostStmt>(&P)) if (PS->getStmt() == Ex) St = PrevN->getState(); FindUndefExpr FindIt(Eng.getStateManager(), St); Ex = FindIt.FindExpr(Ex); // Emit the bug report. EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(),N); R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex); R->addRange(Ex->getSourceRange()); Eng.getBugReporter().EmitReport(R); } Builder.markInfeasible(true); Builder.markInfeasible(false); } }
void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const { SVal X = Ctx.getState()->getSVal(Condition, Ctx.getLocationContext()); if (X.isUndef()) { // Generate a sink node, which implicitly marks both outgoing branches as // infeasible. ExplodedNode *N = Ctx.generateSink(); if (N) { if (!BT) BT.reset(new BuiltinBug( this, "Branch condition evaluates to a garbage value")); // What's going on here: we want to highlight the subexpression of the // condition that is the most likely source of the "uninitialized // branch condition." We do a recursive walk of the condition's // subexpressions and roughly look for the most nested subexpression // that binds to Undefined. We then highlight that expression's range. // Get the predecessor node and check if is a PostStmt with the Stmt // being the terminator condition. We want to inspect the state // of that node instead because it will contain main information about // the subexpressions. // Note: any predecessor will do. They should have identical state, // since all the BlockEdge did was act as an error sink since the value // had to already be undefined. assert (!N->pred_empty()); const Expr *Ex = cast<Expr>(Condition); ExplodedNode *PrevN = *N->pred_begin(); ProgramPoint P = PrevN->getLocation(); ProgramStateRef St = N->getState(); if (Optional<PostStmt> PS = P.getAs<PostStmt>()) if (PS->getStmt() == Ex) St = PrevN->getState(); FindUndefExpr FindIt(St, Ctx.getLocationContext()); Ex = FindIt.FindExpr(Ex); // Emit the bug report. BugReport *R = new BugReport(*BT, BT->getDescription(), N); bugreporter::trackNullOrUndefValue(N, Ex, *R); R->addRange(Ex->getSourceRange()); Ctx.emitReport(R); } } }
static const char *getArgumentValueString(const CallExpr *CE, CheckerContext &C) { if (CE->getNumArgs() == 0) return "Missing assertion argument"; ExplodedNode *N = C.getPredecessor(); const LocationContext *LC = N->getLocationContext(); ProgramStateRef State = N->getState(); const Expr *Assertion = CE->getArg(0); SVal AssertionVal = State->getSVal(Assertion, LC); if (AssertionVal.isUndef()) return "UNDEFINED"; ProgramStateRef StTrue, StFalse; llvm::tie(StTrue, StFalse) = State->assume(cast<DefinedOrUnknownSVal>(AssertionVal)); if (StTrue) { if (StFalse) return "UNKNOWN"; else return "TRUE"; } else { if (StFalse) return "FALSE"; else llvm_unreachable("Invalid constraint; neither true or false."); } }
void MPIChecker::checkDoubleNonblocking(const CallEvent &PreCallEvent, CheckerContext &Ctx) const { if (!FuncClassifier->isNonBlockingType(PreCallEvent.getCalleeIdentifier())) { return; } const MemRegion *const MR = PreCallEvent.getArgSVal(PreCallEvent.getNumArgs() - 1).getAsRegion(); if (!MR) return; const ElementRegion *const ER = dyn_cast<ElementRegion>(MR); // The region must be typed, in order to reason about it. if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion()))) return; ProgramStateRef State = Ctx.getState(); const Request *const Req = State->get<RequestMap>(MR); // double nonblocking detected if (Req && Req->CurrentState == Request::State::Nonblocking) { ExplodedNode *ErrorNode = Ctx.generateNonFatalErrorNode(); BReporter.reportDoubleNonblocking(PreCallEvent, *Req, MR, ErrorNode, Ctx.getBugReporter()); Ctx.addTransition(ErrorNode->getState(), ErrorNode); } // no error else { State = State->set<RequestMap>(MR, Request::State::Nonblocking); Ctx.addTransition(State); } }
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // FIXME: static variables may have an initializer, but the second // time a function is called those values may not be current. // This may need to be reflected in the CFG. // Assumption: The CFG has one DeclStmt per Decl. const Decl *D = *DS->decl_begin(); if (!D || !isa<VarDecl>(D)) { //TODO:AZ: remove explicit insertion after refactoring is done. Dst.insert(Pred); return; } // FIXME: all pre/post visits should eventually be handled by ::Visit(). ExplodedNodeSet dstPreVisit; getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this); StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext); const VarDecl *VD = dyn_cast<VarDecl>(D); for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); I!=E; ++I) { ExplodedNode *N = *I; const ProgramState *state = N->getState(); // Decls without InitExpr are not initialized explicitly. const LocationContext *LC = N->getLocationContext(); if (const Expr *InitEx = VD->getInit()) { SVal InitVal = state->getSVal(InitEx, Pred->getLocationContext()); // We bound the temp obj region to the CXXConstructExpr. Now recover // the lazy compound value when the variable is not a reference. if (AMgr.getLangOptions().CPlusPlus && VD->getType()->isRecordType() && !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){ InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion()); assert(isa<nonloc::LazyCompoundVal>(InitVal)); } // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. if (InitVal.isUnknown()) { InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, currentBuilderContext->getCurrentBlockCount()); } B.takeNodes(N); ExplodedNodeSet Dst2; evalBind(Dst2, DS, N, state->getLValue(VD, LC), InitVal, true); B.addNodes(Dst2); } else { B.generateNode(DS, N,state->bindDeclWithNoInit(state->getRegion(VD, LC))); } } }
void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, ExplodedNodeSet &Dst) { assert(B->getOpcode() == BO_LAnd || B->getOpcode() == BO_LOr); StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); ProgramStateRef state = Pred->getState(); ExplodedNode *N = Pred; while (!isa<BlockEntrance>(N->getLocation())) { ProgramPoint P = N->getLocation(); assert(isa<PreStmt>(P)|| isa<PreStmtPurgeDeadSymbols>(P)); (void) P; assert(N->pred_size() == 1); N = *N->pred_begin(); } assert(N->pred_size() == 1); N = *N->pred_begin(); BlockEdge BE = cast<BlockEdge>(N->getLocation()); SVal X; // Determine the value of the expression by introspecting how we // got this location in the CFG. This requires looking at the previous // block we were in and what kind of control-flow transfer was involved. const CFGBlock *SrcBlock = BE.getSrc(); // The only terminator (if there is one) that makes sense is a logical op. CFGTerminator T = SrcBlock->getTerminator(); if (const BinaryOperator *Term = cast_or_null<BinaryOperator>(T.getStmt())) { (void) Term; assert(Term->isLogicalOp()); assert(SrcBlock->succ_size() == 2); // Did we take the true or false branch? unsigned constant = (*SrcBlock->succ_begin() == BE.getDst()) ? 1 : 0; X = svalBuilder.makeIntVal(constant, B->getType()); } else { // If there is no terminator, by construction the last statement // in SrcBlock is the value of the enclosing expression. assert(!SrcBlock->empty()); CFGStmt Elem = cast<CFGStmt>(*SrcBlock->rbegin()); const Stmt *S = Elem.getStmt(); X = N->getState()->getSVal(S, Pred->getLocationContext()); } Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getLocationContext(), X)); }
bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE) { // Not enough arguments to match OSAtomicCompareAndSwap? if (CE->getNumArgs() != 3) return false; ASTContext &Ctx = C.getASTContext(); const Expr *oldValueExpr = CE->getArg(0); QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType()); const Expr *newValueExpr = CE->getArg(1); QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType()); // Do the types of 'oldValue' and 'newValue' match? if (oldValueType != newValueType) return false; const Expr *theValueExpr = CE->getArg(2); const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>(); // theValueType not a pointer? if (!theValueType) return false; QualType theValueTypePointee = Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType(); // The pointee must match newValueType and oldValueType. if (theValueTypePointee != newValueType) return false; static SimpleProgramPointTag OSAtomicLoadTag("OSAtomicChecker : Load"); static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store"); // Load 'theValue'. ExprEngine &Engine = C.getEngine(); const ProgramState *state = C.getState(); ExplodedNodeSet Tmp; SVal location = state->getSVal(theValueExpr); // Here we should use the value type of the region as the load type, because // we are simulating the semantics of the function, not the semantics of // passing argument. So the type of theValue expr is not we are loading. // But usually the type of the varregion is not the type we want either, // we still need to do a CastRetrievedVal in store manager. So actually this // LoadTy specifying can be omitted. But we put it here to emphasize the // semantics. QualType LoadTy; if (const TypedValueRegion *TR = dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) { LoadTy = TR->getValueType(); } Engine.evalLoad(Tmp, theValueExpr, C.getPredecessor(), state, location, &OSAtomicLoadTag, LoadTy); if (Tmp.empty()) { // If no nodes were generated, other checkers must generated sinks. But // since the builder state was restored, we set it manually to prevent // auto transition. // FIXME: there should be a better approach. C.getNodeBuilder().BuildSinks = true; return true; } for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { ExplodedNode *N = *I; const ProgramState *stateLoad = N->getState(); // Use direct bindings from the environment since we are forcing a load // from a location that the Environment would typically not be used // to bind a value. SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, true); SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr); // FIXME: Issue an error. if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) { return false; } DefinedOrUnknownSVal theValueVal = cast<DefinedOrUnknownSVal>(theValueVal_untested); DefinedOrUnknownSVal oldValueVal = cast<DefinedOrUnknownSVal>(oldValueVal_untested); SValBuilder &svalBuilder = Engine.getSValBuilder(); // Perform the comparison. DefinedOrUnknownSVal Cmp = svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal); const ProgramState *stateEqual = stateLoad->assume(Cmp, true); // Were they equal? if (stateEqual) { // Perform the store. ExplodedNodeSet TmpStore; SVal val = stateEqual->getSVal(newValueExpr); // Handle implicit value casts. if (const TypedValueRegion *R = dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) { val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType()); } Engine.evalStore(TmpStore, NULL, theValueExpr, N, stateEqual, location, val, &OSAtomicStoreTag); if (TmpStore.empty()) { // If no nodes were generated, other checkers must generated sinks. But // since the builder state was restored, we set it manually to prevent // auto transition. // FIXME: there should be a better approach. C.getNodeBuilder().BuildSinks = true; return true; } // Now bind the result of the comparison. for (ExplodedNodeSet::iterator I2 = TmpStore.begin(), E2 = TmpStore.end(); I2 != E2; ++I2) { ExplodedNode *predNew = *I2; const ProgramState *stateNew = predNew->getState(); // Check for 'void' return type if we have a bogus function prototype. SVal Res = UnknownVal(); QualType T = CE->getType(); if (!T->isVoidType()) Res = Engine.getSValBuilder().makeTruthVal(true, T); C.generateNode(stateNew->BindExpr(CE, Res), predNew); } } // Were they not equal? if (const ProgramState *stateNotEqual = stateLoad->assume(Cmp, false)) { // Check for 'void' return type if we have a bogus function prototype. SVal Res = UnknownVal(); QualType T = CE->getType(); if (!T->isVoidType()) Res = Engine.getSValBuilder().makeTruthVal(false, CE->getType()); C.generateNode(stateNotEqual->BindExpr(CE, Res), N); } } return true; }
void ExplodedGraph::reclaimRecentlyAllocatedNodes() { if (!recentlyAllocatedNodes) return; NodeList &nl = *getNodeList(recentlyAllocatedNodes); // Reclaimn all nodes that match *all* the following criteria: // // (1) 1 predecessor (that has one successor) // (2) 1 successor (that has one predecessor) // (3) The ProgramPoint is for a PostStmt. // (4) There is no 'tag' for the ProgramPoint. // (5) The 'store' is the same as the predecessor. // (6) The 'GDM' is the same as the predecessor. // (7) The LocationContext is the same as the predecessor. // (8) The PostStmt is for a non-CFGElement expression. for (NodeList::iterator i = nl.begin(), e = nl.end() ; i != e; ++i) { ExplodedNode *node = *i; // Conditions 1 and 2. if (node->pred_size() != 1 || node->succ_size() != 1) continue; ExplodedNode *pred = *(node->pred_begin()); if (pred->succ_size() != 1) continue; ExplodedNode *succ = *(node->succ_begin()); if (succ->pred_size() != 1) continue; // Condition 3. ProgramPoint progPoint = node->getLocation(); if (!isa<PostStmt>(progPoint)) continue; // Condition 4. PostStmt ps = cast<PostStmt>(progPoint); if (ps.getTag()) continue; if (isa<BinaryOperator>(ps.getStmt())) continue; // Conditions 5, 6, and 7. const ProgramState *state = node->getState(); const ProgramState *pred_state = pred->getState(); if (state->store != pred_state->store || state->GDM != pred_state->GDM || progPoint.getLocationContext() != pred->getLocationContext()) continue; // Condition 8. if (node->getCFG().isBlkExpr(ps.getStmt())) continue; // If we reach here, we can remove the node. This means: // (a) changing the predecessors successor to the successor of this node // (b) changing the successors predecessor to the predecessor of this node // (c) Putting 'node' onto freeNodes. pred->replaceSuccessor(succ); succ->replacePredecessor(pred); if (!freeNodes) freeNodes = new NodeList(); getNodeList(freeNodes)->push_back(node); Nodes.RemoveNode(node); --NumNodes; node->~ExplodedNode(); } nl.clear(); }
void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, ExplodedNodeSet &Dst) { assert(B->getOpcode() == BO_LAnd || B->getOpcode() == BO_LOr); StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); ExplodedNode *N = Pred; while (!N->getLocation().getAs<BlockEntrance>()) { ProgramPoint P = N->getLocation(); assert(P.getAs<PreStmt>()|| P.getAs<PreStmtPurgeDeadSymbols>()); (void) P; assert(N->pred_size() == 1); N = *N->pred_begin(); } assert(N->pred_size() == 1); N = *N->pred_begin(); BlockEdge BE = N->getLocation().castAs<BlockEdge>(); SVal X; // Determine the value of the expression by introspecting how we // got this location in the CFG. This requires looking at the previous // block we were in and what kind of control-flow transfer was involved. const CFGBlock *SrcBlock = BE.getSrc(); // The only terminator (if there is one) that makes sense is a logical op. CFGTerminator T = SrcBlock->getTerminator(); if (const BinaryOperator *Term = cast_or_null<BinaryOperator>(T.getStmt())) { (void) Term; assert(Term->isLogicalOp()); assert(SrcBlock->succ_size() == 2); // Did we take the true or false branch? unsigned constant = (*SrcBlock->succ_begin() == BE.getDst()) ? 1 : 0; X = svalBuilder.makeIntVal(constant, B->getType()); } else { // If there is no terminator, by construction the last statement // in SrcBlock is the value of the enclosing expression. // However, we still need to constrain that value to be 0 or 1. assert(!SrcBlock->empty()); CFGStmt Elem = SrcBlock->rbegin()->castAs<CFGStmt>(); const Expr *RHS = cast<Expr>(Elem.getStmt()); SVal RHSVal = N->getState()->getSVal(RHS, Pred->getLocationContext()); if (RHSVal.isUndef()) { X = RHSVal; } else { DefinedOrUnknownSVal DefinedRHS = RHSVal.castAs<DefinedOrUnknownSVal>(); ProgramStateRef StTrue, StFalse; llvm::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS); if (StTrue) { if (StFalse) { // We can't constrain the value to 0 or 1. // The best we can do is a cast. X = getSValBuilder().evalCast(RHSVal, B->getType(), RHS->getType()); } else { // The value is known to be true. X = getSValBuilder().makeIntVal(1, B->getType()); } } else { // The value is known to be false. assert(StFalse && "Infeasible path!"); X = getSValBuilder().makeIntVal(0, B->getType()); } } } Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getLocationContext(), X)); }
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // Assumption: The CFG has one DeclStmt per Decl. const VarDecl *VD = dyn_cast_or_null<VarDecl>(*DS->decl_begin()); if (!VD) { //TODO:AZ: remove explicit insertion after refactoring is done. Dst.insert(Pred); return; } // FIXME: all pre/post visits should eventually be handled by ::Visit(). ExplodedNodeSet dstPreVisit; getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this); StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx); for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); I!=E; ++I) { ExplodedNode *N = *I; ProgramStateRef state = N->getState(); const LocationContext *LC = N->getLocationContext(); // Decls without InitExpr are not initialized explicitly. if (const Expr *InitEx = VD->getInit()) { // Note in the state that the initialization has occurred. ExplodedNode *UpdatedN = N; SVal InitVal = state->getSVal(InitEx, LC); if (isa<CXXConstructExpr>(InitEx->IgnoreImplicit())) { // We constructed the object directly in the variable. // No need to bind anything. B.generateNode(DS, UpdatedN, state); } else { // We bound the temp obj region to the CXXConstructExpr. Now recover // the lazy compound value when the variable is not a reference. if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() && !VD->getType()->isReferenceType()) { if (Optional<loc::MemRegionVal> M = InitVal.getAs<loc::MemRegionVal>()) { InitVal = state->getSVal(M->getRegion()); assert(InitVal.getAs<nonloc::LazyCompoundVal>()); } } // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. if (InitVal.isUnknown()) { QualType Ty = InitEx->getType(); if (InitEx->isGLValue()) { Ty = getContext().getPointerType(Ty); } InitVal = svalBuilder.conjureSymbolVal(0, InitEx, LC, Ty, currBldrCtx->blockCount()); } B.takeNodes(UpdatedN); ExplodedNodeSet Dst2; evalBind(Dst2, DS, UpdatedN, state->getLValue(VD, LC), InitVal, true); B.addNodes(Dst2); } } else { B.generateNode(DS, N, state); } } }
void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet dstPreStmt; getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this); if (CastE->getCastKind() == CK_LValueToRValue) { for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); I!=E; ++I) { ExplodedNode *subExprNode = *I; ProgramStateRef state = subExprNode->getState(); const LocationContext *LCtx = subExprNode->getLocationContext(); evalLoad(Dst, CastE, CastE, subExprNode, state, state->getSVal(Ex, LCtx)); } return; } // All other casts. QualType T = CastE->getType(); QualType ExTy = Ex->getType(); if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) T = ExCast->getTypeAsWritten(); StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx); for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); I != E; ++I) { Pred = *I; ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); switch (CastE->getCastKind()) { case CK_LValueToRValue: llvm_unreachable("LValueToRValue casts handled earlier."); case CK_ToVoid: continue; // The analyzer doesn't do anything special with these casts, // since it understands retain/release semantics already. case CK_ARCProduceObject: case CK_ARCConsumeObject: case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: // Fall-through. case CK_CopyAndAutoreleaseBlockObject: // The analyser can ignore atomic casts for now, although some future // checkers may want to make certain that you're not modifying the same // value through atomic and nonatomic pointers. case CK_AtomicToNonAtomic: case CK_NonAtomicToAtomic: // True no-ops. case CK_NoOp: case CK_ConstructorConversion: case CK_UserDefinedConversion: case CK_FunctionToPointerDecay: case CK_BuiltinFnToFnPtr: { // Copy the SVal of Ex to CastE. ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); SVal V = state->getSVal(Ex, LCtx); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; } case CK_MemberPointerToBoolean: // FIXME: For now, member pointers are represented by void *. // FALLTHROUGH case CK_Dependent: case CK_ArrayToPointerDecay: case CK_BitCast: case CK_IntegralCast: case CK_NullToPointer: case CK_IntegralToPointer: case CK_PointerToIntegral: case CK_PointerToBoolean: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: case CK_FloatingRealToComplex: case CK_FloatingComplexToReal: case CK_FloatingComplexToBoolean: case CK_FloatingComplexCast: case CK_FloatingComplexToIntegralComplex: case CK_IntegralRealToComplex: case CK_IntegralComplexToReal: case CK_IntegralComplexToBoolean: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_ZeroToOCLEvent: { // Delegate to SValBuilder to process. SVal V = state->getSVal(Ex, LCtx); V = svalBuilder.evalCast(V, T, ExTy); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; } case CK_DerivedToBase: case CK_UncheckedDerivedToBase: { // For DerivedToBase cast, delegate to the store manager. SVal val = state->getSVal(Ex, LCtx); val = getStoreManager().evalDerivedToBase(val, CastE); state = state->BindExpr(CastE, LCtx, val); Bldr.generateNode(CastE, Pred, state); continue; } // Handle C++ dyn_cast. case CK_Dynamic: { SVal val = state->getSVal(Ex, LCtx); // Compute the type of the result. QualType resultType = CastE->getType(); if (CastE->isGLValue()) resultType = getContext().getPointerType(resultType); bool Failed = false; // Check if the value being cast evaluates to 0. if (val.isZeroConstant()) Failed = true; // Else, evaluate the cast. else val = getStoreManager().evalDynamicCast(val, T, Failed); if (Failed) { if (T->isReferenceType()) { // A bad_cast exception is thrown if input value is a reference. // Currently, we model this, by generating a sink. Bldr.generateSink(CastE, Pred, state); continue; } else { // If the cast fails on a pointer, bind to 0. state = state->BindExpr(CastE, LCtx, svalBuilder.makeNull()); } } else { // If we don't know if the cast succeeded, conjure a new symbol. if (val.isUnknown()) { DefinedOrUnknownSVal NewSym = svalBuilder.conjureSymbolVal(0, CastE, LCtx, resultType, currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, NewSym); } else // Else, bind to the derived region value. state = state->BindExpr(CastE, LCtx, val); } Bldr.generateNode(CastE, Pred, state); continue; } case CK_NullToMemberPointer: { // FIXME: For now, member pointers are represented by void *. SVal V = svalBuilder.makeIntValWithPtrWidth(0, true); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; } // Various C++ casts that are not handled yet. case CK_ToUnion: case CK_BaseToDerived: case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_ReinterpretMemberPointer: case CK_VectorSplat: case CK_LValueBitCast: { // Recover some path-sensitivty by conjuring a new value. QualType resultType = CastE->getType(); if (CastE->isGLValue()) resultType = getContext().getPointerType(resultType); SVal result = svalBuilder.conjureSymbolVal(0, CastE, LCtx, resultType, currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, result); Bldr.generateNode(CastE, Pred, state); continue; } } } }
void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, ExplodedNodeSet &Dst) { assert(B->getOpcode() == BO_LAnd || B->getOpcode() == BO_LOr); StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); if (B->getType()->isVectorType()) { // FIXME: We do not model vector arithmetic yet. When adding support for // that, note that the CFG-based reasoning below does not apply, because // logical operators on vectors are not short-circuit. Currently they are // modeled as short-circuit in Clang CFG but this is incorrect. // Do not set the value for the expression. It'd be UnknownVal by default. Bldr.generateNode(B, Pred, state); return; } ExplodedNode *N = Pred; while (!N->getLocation().getAs<BlockEntrance>()) { ProgramPoint P = N->getLocation(); assert(P.getAs<PreStmt>()|| P.getAs<PreStmtPurgeDeadSymbols>()); (void) P; assert(N->pred_size() == 1); N = *N->pred_begin(); } assert(N->pred_size() == 1); N = *N->pred_begin(); BlockEdge BE = N->getLocation().castAs<BlockEdge>(); SVal X; // Determine the value of the expression by introspecting how we // got this location in the CFG. This requires looking at the previous // block we were in and what kind of control-flow transfer was involved. const CFGBlock *SrcBlock = BE.getSrc(); // The only terminator (if there is one) that makes sense is a logical op. CFGTerminator T = SrcBlock->getTerminator(); if (const BinaryOperator *Term = cast_or_null<BinaryOperator>(T.getStmt())) { (void) Term; assert(Term->isLogicalOp()); assert(SrcBlock->succ_size() == 2); // Did we take the true or false branch? unsigned constant = (*SrcBlock->succ_begin() == BE.getDst()) ? 1 : 0; X = svalBuilder.makeIntVal(constant, B->getType()); } else { // If there is no terminator, by construction the last statement // in SrcBlock is the value of the enclosing expression. // However, we still need to constrain that value to be 0 or 1. assert(!SrcBlock->empty()); CFGStmt Elem = SrcBlock->rbegin()->castAs<CFGStmt>(); const Expr *RHS = cast<Expr>(Elem.getStmt()); SVal RHSVal = N->getState()->getSVal(RHS, Pred->getLocationContext()); if (RHSVal.isUndef()) { X = RHSVal; } else { // We evaluate "RHSVal != 0" expression which result in 0 if the value is // known to be false, 1 if the value is known to be true and a new symbol // when the assumption is unknown. nonloc::ConcreteInt Zero(getBasicVals().getValue(0, B->getType())); X = evalBinOp(N->getState(), BO_NE, svalBuilder.evalCast(RHSVal, B->getType(), RHS->getType()), Zero, B->getType()); } } Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getLocationContext(), X)); }
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, const MemRegion *Dest, ExplodedNode *Pred, ExplodedNodeSet &destNodes) { const CXXConstructorDecl *CD = E->getConstructor(); assert(CD); #if 0 if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) // FIXME: invalidate the object. return; #endif // Evaluate other arguments. ExplodedNodeSet argsEvaluated; const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>(); evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated); #if 0 // Is the constructor elidable? if (E->isElidable()) { VisitAggExpr(E->getArg(0), destNodes, Pred, Dst); // FIXME: this is here to force propagation if VisitAggExpr doesn't if (destNodes.empty()) destNodes.Add(Pred); return; } #endif // Perform the previsit of the constructor. ExplodedNodeSet destPreVisit; getCheckerManager().runCheckersForPreStmt(destPreVisit, argsEvaluated, E, *this); // Evaluate the constructor. Currently we don't now allow checker-specific // implementations of specific constructors (as we do with ordinary // function calls. We can re-evaluate this in the future. #if 0 // Inlining currently isn't fully implemented. if (AMgr.shouldInlineCall()) { if (!Dest) Dest = svalBuilder.getRegionManager().getCXXTempObjectRegion(E, Pred->getLocationContext()); // The callee stack frame context used to create the 'this' // parameter region. const StackFrameContext *SFC = AMgr.getStackFrame(CD, Pred->getLocationContext(), E, currentBuilderContext->getBlock(), currentStmtIdx); // Create the 'this' region. const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor()->getParent(), SFC); CallEnter Loc(E, SFC, Pred->getLocationContext()); StmtNodeBuilder Bldr(argsEvaluated, destNodes, *currentBuilderContext); for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(), NE = argsEvaluated.end(); NI != NE; ++NI) { const ProgramState *state = (*NI)->getState(); // Setup 'this' region, so that the ctor is evaluated on the object pointed // by 'Dest'. state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); Bldr.generateNode(Loc, *NI, state); } } #endif // Default semantics: invalidate all regions passed as arguments. ExplodedNodeSet destCall; { StmtNodeBuilder Bldr(destPreVisit, destCall, *currentBuilderContext); for (ExplodedNodeSet::iterator i = destPreVisit.begin(), e = destPreVisit.end(); i != e; ++i) { ExplodedNode *Pred = *i; const LocationContext *LC = Pred->getLocationContext(); const ProgramState *state = Pred->getState(); state = invalidateArguments(state, CallOrObjCMessage(E, state, LC), LC); Bldr.generateNode(E, Pred, state); } } // Do the post visit. getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this); }
void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<ObjCMethodCall> Msg = CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext()); // Handle the previsits checks. ExplodedNodeSet dstPrevisit; getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred, *Msg, *this); ExplodedNodeSet dstGenericPrevisit; getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit, *Msg, *this); // Proceed with evaluate the message expression. ExplodedNodeSet dstEval; StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currentBuilderContext); for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(), DE = dstGenericPrevisit.end(); DI != DE; ++DI) { ExplodedNode *Pred = *DI; ProgramStateRef State = Pred->getState(); CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State); if (UpdatedMsg->isInstanceMessage()) { SVal recVal = UpdatedMsg->getReceiverSVal(); if (!recVal.isUndef()) { // Bifurcate the state into nil and non-nil ones. DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal); ProgramStateRef notNilState, nilState; llvm::tie(notNilState, nilState) = State->assume(receiverVal); // There are three cases: can be nil or non-nil, must be nil, must be // non-nil. We ignore must be nil, and merge the rest two into non-nil. // FIXME: This ignores many potential bugs (<rdar://problem/11733396>). // Revisit once we have lazier constraints. if (nilState && !notNilState) { continue; } // Check if the "raise" message was sent. assert(notNilState); if (Msg->getSelector() == RaiseSel) { // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. Bldr.generateNode(currentStmt, Pred, State, true); continue; } // Generate a transition to non-Nil state. if (notNilState != State) Pred = Bldr.generateNode(currentStmt, Pred, notNilState); } } else { // Check for special class methods. if (const ObjCInterfaceDecl *Iface = Msg->getReceiverInterface()) { if (!NSExceptionII) { ASTContext &Ctx = getContext(); NSExceptionII = &Ctx.Idents.get("NSException"); } if (isSubclass(Iface, NSExceptionII)) { enum { NUM_RAISE_SELECTORS = 2 }; // Lazily create a cache of the selectors. if (!NSExceptionInstanceRaiseSelectors) { ASTContext &Ctx = getContext(); NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS]; SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II; unsigned idx = 0; // raise:format: II.push_back(&Ctx.Idents.get("raise")); II.push_back(&Ctx.Idents.get("format")); NSExceptionInstanceRaiseSelectors[idx++] = Ctx.Selectors.getSelector(II.size(), &II[0]); // raise:format:arguments: II.push_back(&Ctx.Idents.get("arguments")); NSExceptionInstanceRaiseSelectors[idx++] = Ctx.Selectors.getSelector(II.size(), &II[0]); } Selector S = Msg->getSelector(); bool RaisesException = false; for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) { if (S == NSExceptionInstanceRaiseSelectors[i]) { RaisesException = true; break; } } if (RaisesException) { // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. Bldr.generateNode(currentStmt, Pred, Pred->getState(), true); continue; } } } } // Evaluate the call. defaultEvalCall(Bldr, Pred, *UpdatedMsg); } ExplodedNodeSet dstPostvisit; getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval, *Msg, *this); // Finally, perform the post-condition check of the ObjCMessageExpr and store // the created nodes in 'Dst'. getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit, *Msg, *this); }
void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<ObjCMethodCall> Msg = CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext()); // Handle the previsits checks. ExplodedNodeSet dstPrevisit; getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred, *Msg, *this); ExplodedNodeSet dstGenericPrevisit; getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit, *Msg, *this); // Proceed with evaluate the message expression. ExplodedNodeSet dstEval; StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currBldrCtx); for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(), DE = dstGenericPrevisit.end(); DI != DE; ++DI) { ExplodedNode *Pred = *DI; ProgramStateRef State = Pred->getState(); CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State); if (UpdatedMsg->isInstanceMessage()) { SVal recVal = UpdatedMsg->getReceiverSVal(); if (!recVal.isUndef()) { // Bifurcate the state into nil and non-nil ones. DefinedOrUnknownSVal receiverVal = recVal.castAs<DefinedOrUnknownSVal>(); ProgramStateRef notNilState, nilState; std::tie(notNilState, nilState) = State->assume(receiverVal); // There are three cases: can be nil or non-nil, must be nil, must be // non-nil. We ignore must be nil, and merge the rest two into non-nil. // FIXME: This ignores many potential bugs (<rdar://problem/11733396>). // Revisit once we have lazier constraints. if (nilState && !notNilState) { continue; } // Check if the "raise" message was sent. assert(notNilState); if (ObjCNoRet.isImplicitNoReturn(ME)) { // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. Bldr.generateSink(ME, Pred, State); continue; } // Generate a transition to non-Nil state. if (notNilState != State) { Pred = Bldr.generateNode(ME, Pred, notNilState); assert(Pred && "Should have cached out already!"); } } } else { // Check for special class methods that are known to not return // and that we should treat as a sink. if (ObjCNoRet.isImplicitNoReturn(ME)) { // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. Bldr.generateSink(ME, Pred, Pred->getState()); continue; } } defaultEvalCall(Bldr, Pred, *UpdatedMsg); } ExplodedNodeSet dstPostvisit; getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval, *Msg, *this); // Finally, perform the post-condition check of the ObjCMessageExpr and store // the created nodes in 'Dst'. getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit, *Msg, *this); }
void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet dstPreStmt; getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this); if (CastE->getCastKind() == CK_LValueToRValue) { for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); I!=E; ++I) { ExplodedNode *subExprNode = *I; const ProgramState *state = subExprNode->getState(); const LocationContext *LCtx = subExprNode->getLocationContext(); evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex, LCtx)); } return; } // All other casts. QualType T = CastE->getType(); QualType ExTy = Ex->getType(); if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) T = ExCast->getTypeAsWritten(); StmtNodeBuilder Bldr(dstPreStmt, Dst, *currentBuilderContext); for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); I != E; ++I) { Pred = *I; switch (CastE->getCastKind()) { case CK_LValueToRValue: llvm_unreachable("LValueToRValue casts handled earlier."); case CK_ToVoid: continue; // The analyzer doesn't do anything special with these casts, // since it understands retain/release semantics already. case CK_ARCProduceObject: case CK_ARCConsumeObject: case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: // Fall-through. // The analyser can ignore atomic casts for now, although some future // checkers may want to make certain that you're not modifying the same // value through atomic and nonatomic pointers. case CK_AtomicToNonAtomic: case CK_NonAtomicToAtomic: // True no-ops. case CK_NoOp: case CK_FunctionToPointerDecay: { // Copy the SVal of Ex to CastE. const ProgramState *state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); SVal V = state->getSVal(Ex, LCtx); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; } case CK_Dependent: case CK_ArrayToPointerDecay: case CK_BitCast: case CK_LValueBitCast: case CK_IntegralCast: case CK_NullToPointer: case CK_IntegralToPointer: case CK_PointerToIntegral: case CK_PointerToBoolean: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: case CK_FloatingRealToComplex: case CK_FloatingComplexToReal: case CK_FloatingComplexToBoolean: case CK_FloatingComplexCast: case CK_FloatingComplexToIntegralComplex: case CK_IntegralRealToComplex: case CK_IntegralComplexToReal: case CK_IntegralComplexToBoolean: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: { // Delegate to SValBuilder to process. const ProgramState *state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); SVal V = state->getSVal(Ex, LCtx); V = svalBuilder.evalCast(V, T, ExTy); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; } case CK_DerivedToBase: case CK_UncheckedDerivedToBase: { // For DerivedToBase cast, delegate to the store manager. const ProgramState *state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); SVal val = state->getSVal(Ex, LCtx); val = getStoreManager().evalDerivedToBase(val, T); state = state->BindExpr(CastE, LCtx, val); Bldr.generateNode(CastE, Pred, state); continue; } // Various C++ casts that are not handled yet. case CK_Dynamic: case CK_ToUnion: case CK_BaseToDerived: case CK_NullToMemberPointer: case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_UserDefinedConversion: case CK_ConstructorConversion: case CK_VectorSplat: case CK_MemberPointerToBoolean: { // Recover some path-sensitivty by conjuring a new value. QualType resultType = CastE->getType(); if (CastE->isLValue()) resultType = getContext().getPointerType(resultType); SVal result = svalBuilder.getConjuredSymbolVal(NULL, CastE, resultType, currentBuilderContext->getCurrentBlockCount()); const LocationContext *LCtx = Pred->getLocationContext(); const ProgramState *state = Pred->getState()->BindExpr(CastE, LCtx, result); Bldr.generateNode(CastE, Pred, state); continue; } } } }