static bool checkSelfIvarsForInvariantViolation(ProgramStateRef State, const LocationContext *LocCtxt) { auto *MD = dyn_cast<ObjCMethodDecl>(LocCtxt->getDecl()); if (!MD || !MD->isInstanceMethod()) return false; const ImplicitParamDecl *SelfDecl = LocCtxt->getSelfDecl(); if (!SelfDecl) return false; SVal SelfVal = State->getSVal(State->getRegion(SelfDecl, LocCtxt)); const ObjCObjectPointerType *SelfType = dyn_cast<ObjCObjectPointerType>(SelfDecl->getType()); if (!SelfType) return false; const ObjCInterfaceDecl *ID = SelfType->getInterfaceDecl(); if (!ID) return false; for (const auto *IvarDecl : ID->ivars()) { SVal LV = State->getLValue(IvarDecl, SelfVal); if (checkValueAtLValForInvariantViolation(State, LV, IvarDecl->getType())) { return true; } } return false; }
/// Returns true if LCtx is a call to -dealloc and false /// otherwise. If true, it also sets SelfValOut to the value of /// 'self'. bool ObjCDeallocChecker::isInInstanceDealloc(const CheckerContext &C, const LocationContext *LCtx, SVal &SelfValOut) const { auto *MD = dyn_cast<ObjCMethodDecl>(LCtx->getDecl()); if (!MD || !MD->isInstanceMethod() || MD->getSelector() != DeallocSel) return false; const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl(); assert(SelfDecl && "No self in -dealloc?"); ProgramStateRef State = C.getState(); SelfValOut = State->getSVal(State->getRegion(SelfDecl, LCtx)); return true; }
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; ProgramStateRef 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, LC); if (InitVal == state->getLValue(VD, LC) || (VD->getType()->isArrayType() && isa<CXXConstructExpr>(InitEx->IgnoreImplicit()))) { // We constructed the object directly in the variable. // No need to bind anything. B.generateNode(DS, N, 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() && 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()) { QualType Ty = InitEx->getType(); if (InitEx->isGLValue()) { Ty = getContext().getPointerType(Ty); } InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, LC, Ty, 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 VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { if (!DS->isSingleDecl()) return; const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); if (!VD) return; ASTContext &Ctx = C.getASTContext(); const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType()); if (!VLA) return; // FIXME: Handle multi-dimensional VLAs. const Expr *SE = VLA->getSizeExpr(); ProgramStateRef state = C.getState(); SVal sizeV = state->getSVal(SE, C.getLocationContext()); if (sizeV.isUndef()) { reportBug(VLA_Garbage, SE, state, C); return; } // See if the size value is known. It can't be undefined because we would have // warned about that already. if (sizeV.isUnknown()) return; // Check if the size is tainted. if (state->isTainted(sizeV)) { reportBug(VLA_Tainted, SE, nullptr, C); return; } // Check if the size is zero. DefinedSVal sizeD = sizeV.castAs<DefinedSVal>(); ProgramStateRef stateNotZero, stateZero; std::tie(stateNotZero, stateZero) = state->assume(sizeD); if (stateZero && !stateNotZero) { reportBug(VLA_Zero, SE, stateZero, C); return; } // From this point on, assume that the size is not zero. state = stateNotZero; // VLASizeChecker is responsible for defining the extent of the array being // declared. We do this by multiplying the array length by the element size, // then matching that with the array region's extent symbol. // Convert the array length to size_t. SValBuilder &svalBuilder = C.getSValBuilder(); QualType SizeTy = Ctx.getSizeType(); NonLoc ArrayLength = svalBuilder.evalCast(sizeD, SizeTy, SE->getType()).castAs<NonLoc>(); // Get the element size. CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType()); SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy); // Multiply the array length by the element size. SVal ArraySizeVal = svalBuilder.evalBinOpNN( state, BO_Mul, ArrayLength, EleSizeVal.castAs<NonLoc>(), SizeTy); // Finally, assume that the array's extent matches the given size. const LocationContext *LC = C.getLocationContext(); DefinedOrUnknownSVal Extent = state->getRegion(VD, LC)->getExtent(svalBuilder); DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs<DefinedOrUnknownSVal>(); DefinedOrUnknownSVal sizeIsKnown = svalBuilder.evalEQ(state, Extent, ArraySize); state = state->assume(sizeIsKnown, true); // Assume should not fail at this point. assert(state); // Remember our assumptions! C.addTransition(state); }
// handle assigning to an iterator ProgramStateRef IteratorsChecker::handleAssign(ProgramStateRef state, const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const { // Assume unknown until we find something definite. state = state->set<IteratorState>(MR, RefState::getUnknown()); if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(rexp)) rexp = M->GetTemporaryExpr(); if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(rexp)) rexp = ICE->getSubExpr(); // Need to handle three cases: MemberCall, copy, copy with addition. if (const CallExpr *CE = dyn_cast<CallExpr>(rexp)) { // Handle MemberCall. if (const MemberExpr *ME = dyn_cast<MemberExpr>(CE->getCallee())) { const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase()); if (!DRE) return state; // Verify that the type is std::vector<T>. if (getTemplateKind(DRE->getType()) != VectorKind) return state; // Now get the MemRegion associated with the instance. const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()); if (!VD) return state; const MemRegion *IMR = state->getRegion(VD, LC); if (!IMR) return state; // Finally, see if it is one of the calls that will create // a valid iterator and mark it if so, else mark as Unknown. StringRef mName = ME->getMemberDecl()->getName(); if (llvm::StringSwitch<bool>(mName) .Cases("begin", "insert", "erase", true).Default(false)) { return state->set<IteratorState>(MR, RefState::getBeginValid(IMR)); } if (mName == "end") return state->set<IteratorState>(MR, RefState::getEndValid(IMR)); return state->set<IteratorState>(MR, RefState::getUnknown()); } } // Handle straight copy from another iterator. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(rexp)) { if (getTemplateKind(DRE->getType()) != VectorIteratorKind) return state; // Now get the MemRegion associated with the instance. const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()); if (!VD) return state; const MemRegion *IMR = state->getRegion(VD, LC); if (!IMR) return state; // Get the RefState of the iterator being copied. const RefState *RS = state->get<IteratorState>(IMR); if (!RS) return state; // Use it to set the state of the LValue. return state->set<IteratorState>(MR, *RS); } // If we have operator+ or operator- ... if (const CXXOperatorCallExpr *OCE = dyn_cast<CXXOperatorCallExpr>(rexp)) { OverloadedOperatorKind Kind = OCE->getOperator(); if (Kind == OO_Plus || Kind == OO_Minus) { // Check left side of tree for a valid value. state = handleAssign( state, MR, OCE->getArg(0), LC); const RefState *RS = state->get<IteratorState>(MR); // If found, return it. if (!RS->isUnknown()) return state; // Otherwise return what we find in the right side. return handleAssign(state, MR, OCE->getArg(1), LC); } } // Fall through if nothing matched. return state; }