Index: lib/StaticAnalyzer/Checkers/IteratorChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/IteratorChecker.cpp +++ lib/StaticAnalyzer/Checkers/IteratorChecker.cpp @@ -134,8 +134,6 @@ } }; -typedef llvm::PointerUnion RegionOrSymbol; - // Structure to record the symbolic begin and end position of a container struct ContainerData { private: @@ -173,27 +171,31 @@ } }; -// Structure fo recording iterator comparisons. We needed to retrieve the -// original comparison expression in assumptions. -struct IteratorComparison { +// Structure fo recording symbol comparisons. We need to retrieve the original +// comparison expression in assumptions. +struct SymbolComparison { private: - RegionOrSymbol Left, Right; + SymbolRef Left, Right; bool Equality; public: - IteratorComparison(RegionOrSymbol L, RegionOrSymbol R, bool Eq) + SymbolComparison(SymbolRef L, SymbolRef R, bool Eq) : Left(L), Right(R), Equality(Eq) {} - RegionOrSymbol getLeft() const { return Left; } - RegionOrSymbol getRight() const { return Right; } + SymbolRef getLeft() const { return Left; } + SymbolRef getRight() const { return Right; } bool isEquality() const { return Equality; } - bool operator==(const IteratorComparison &X) const { + bool operator==(const SymbolComparison &X) const { return Left == X.Left && Right == X.Right && Equality == X.Equality; } - bool operator!=(const IteratorComparison &X) const { + bool operator!=(const SymbolComparison &X) const { return Left != X.Left || Right != X.Right || Equality != X.Equality; } - void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Equality); } + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.Add(Left); + ID.Add(Right); + ID.AddInteger(Equality); + } }; class IteratorChecker @@ -206,8 +208,12 @@ std::unique_ptr MismatchedBugType; std::unique_ptr InvalidatedBugType; - void handleComparison(CheckerContext &C, const SVal &RetVal, const SVal &LVal, - const SVal &RVal, OverloadedOperatorKind Op) const; + void handleComparison(CheckerContext &C, const Expr *CE, const SVal &RetVal, + const SVal &LVal, const SVal &RVal, + OverloadedOperatorKind Op) const; + void processComparison(CheckerContext &C, ProgramStateRef State, + SymbolRef Sym1, SymbolRef Sym2, const SVal &RetVal, + OverloadedOperatorKind Op) const; void verifyAccess(CheckerContext &C, const SVal &Val) const; void verifyDereference(CheckerContext &C, const SVal &Val) const; void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter, @@ -290,8 +296,8 @@ REGISTER_MAP_WITH_PROGRAMSTATE(ContainerMap, const MemRegion *, ContainerData) -REGISTER_MAP_WITH_PROGRAMSTATE(IteratorComparisonMap, const SymExpr *, - IteratorComparison) +REGISTER_MAP_WITH_PROGRAMSTATE(SymbolComparisonMap, const SymExpr *, + SymbolComparison) namespace { @@ -323,15 +329,10 @@ bool frontModifiable(ProgramStateRef State, const MemRegion *Reg); bool backModifiable(ProgramStateRef State, const MemRegion *Reg); BinaryOperator::Opcode getOpcode(const SymExpr *SE); -const RegionOrSymbol getRegionOrSymbol(const SVal &Val); -const ProgramStateRef processComparison(ProgramStateRef State, - RegionOrSymbol LVal, - RegionOrSymbol RVal, bool Equal); -const ProgramStateRef saveComparison(ProgramStateRef State, - const SymExpr *Condition, const SVal &LVal, - const SVal &RVal, bool Eq); -const IteratorComparison *loadComparison(ProgramStateRef State, - const SymExpr *Condition); +const ProgramStateRef saveComparison(ProgramStateRef State, SymbolRef Condition, + SymbolRef LSym, SymbolRef RSym, bool Eq); +const SymbolComparison *loadComparison(ProgramStateRef State, + const SymExpr *Condition); SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont); SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont); ProgramStateRef createContainerBegin(ProgramStateRef State, @@ -341,21 +342,9 @@ const SymbolRef Sym); const IteratorPosition *getIteratorPosition(ProgramStateRef State, const SVal &Val); -const IteratorPosition *getIteratorPosition(ProgramStateRef State, - RegionOrSymbol RegOrSym); ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val, const IteratorPosition &Pos); -ProgramStateRef setIteratorPosition(ProgramStateRef State, - RegionOrSymbol RegOrSym, - const IteratorPosition &Pos); ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val); -ProgramStateRef adjustIteratorPosition(ProgramStateRef State, - RegionOrSymbol RegOrSym, - const IteratorPosition &Pos, bool Equal); -ProgramStateRef relateIteratorPositions(ProgramStateRef State, - const IteratorPosition &Pos1, - const IteratorPosition &Pos2, - bool Equal); ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State, const MemRegion *Cont); ProgramStateRef @@ -381,6 +370,8 @@ ProgramStateRef rebaseSymbolInIteratorPositionsIf( ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym, SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc); +ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1, + SymbolRef Sym2, bool Equal); const ContainerData *getContainerData(ProgramStateRef State, const MemRegion *Cont); ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, @@ -594,11 +585,15 @@ handleAssign(C, InstCall->getCXXThisVal()); } } else if (isSimpleComparisonOperator(Op)) { + const auto *OrigExpr = Call.getOriginExpr(); + if (!OrigExpr) + return; + if (const auto *InstCall = dyn_cast(&Call)) { - handleComparison(C, Call.getReturnValue(), InstCall->getCXXThisVal(), - Call.getArgSVal(0), Op); + handleComparison(C, OrigExpr, Call.getReturnValue(), + InstCall->getCXXThisVal(), Call.getArgSVal(0), Op); } else { - handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0), + handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0), Call.getArgSVal(1), Op); } } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) { @@ -817,10 +812,10 @@ } } - auto ComparisonMap = State->get(); + auto ComparisonMap = State->get(); for (const auto Comp : ComparisonMap) { if (!SR.isLive(Comp.first)) { - State = State->remove(Comp.first); + State = State->remove(Comp.first); } } @@ -861,29 +856,54 @@ return State; } - return processComparison(State, Comp->getLeft(), Comp->getRight(), - (Comp->isEquality() == Assumption) != Negated); + return relateSymbols(State, Comp->getLeft(), Comp->getRight(), + (Comp->isEquality() == Assumption) != Negated); } -void IteratorChecker::handleComparison(CheckerContext &C, const SVal &RetVal, - const SVal &LVal, const SVal &RVal, +void IteratorChecker::handleComparison(CheckerContext &C, const Expr *CE, + const SVal &RetVal, const SVal &LVal, + const SVal &RVal, OverloadedOperatorKind Op) const { // Record the operands and the operator of the comparison for the next // evalAssume, if the result is a symbolic expression. If it is a concrete // value (only one branch is possible), then transfer the state between // the operands according to the operator and the result - auto State = C.getState(); - if (const auto *Condition = RetVal.getAsSymbolicExpression()) { - const auto *LPos = getIteratorPosition(State, LVal); - const auto *RPos = getIteratorPosition(State, RVal); - if (!LPos && !RPos) + auto State = C.getState(); + const auto *LPos = getIteratorPosition(State, LVal); + const auto *RPos = getIteratorPosition(State, RVal); + const MemRegion *Cont = nullptr; + if (LPos) { + Cont = LPos->getContainer(); + } else if (RPos) { + Cont = RPos->getContainer(); + } + if (!Cont) + return; + + if (!LPos) { + assignToContainer(C, CE, LVal, Cont); + if (!(LPos = getIteratorPosition(State, LVal))) + return; + } else if (!RPos) { + assignToContainer(C, CE, RVal, Cont); + if (!(RPos = getIteratorPosition(State, RVal))) return; - State = saveComparison(State, Condition, LVal, RVal, Op == OO_EqualEqual); + } + + processComparison(C, State, LPos->getOffset(), RPos->getOffset(), RetVal, Op); +} + +void IteratorChecker::processComparison(CheckerContext &C, + ProgramStateRef State, SymbolRef Sym1, + SymbolRef Sym2, const SVal &RetVal, + OverloadedOperatorKind Op) const { + if (const auto *Condition = RetVal.getAsSymbolicExpression()) { + State = saveComparison(State, Condition, Sym1, Sym2, Op == OO_EqualEqual); C.addTransition(State); } else if (const auto TruthVal = RetVal.getAs()) { - if ((State = processComparison( - State, getRegionOrSymbol(LVal), getRegionOrSymbol(RVal), - (Op == OO_EqualEqual) == (TruthVal->getValue() != 0)))) { + if (State = relateSymbols(State, Sym1, Sym2, + (Op == OO_EqualEqual) == + (TruthVal->getValue() != 0))) { C.addTransition(State); } else { C.generateSink(State, C.getPredecessor()); @@ -1914,46 +1934,15 @@ return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl(); } -const RegionOrSymbol getRegionOrSymbol(const SVal &Val) { - if (const auto Reg = Val.getAsRegion()) { - return Reg; - } else if (const auto Sym = Val.getAsSymbol()) { - return Sym; - } else if (const auto LCVal = Val.getAs()) { - return LCVal->getRegion(); - } - return RegionOrSymbol(); -} - -const ProgramStateRef processComparison(ProgramStateRef State, - RegionOrSymbol LVal, - RegionOrSymbol RVal, bool Equal) { - const auto *LPos = getIteratorPosition(State, LVal); - const auto *RPos = getIteratorPosition(State, RVal); - if (LPos && !RPos) { - State = adjustIteratorPosition(State, RVal, *LPos, Equal); - } else if (!LPos && RPos) { - State = adjustIteratorPosition(State, LVal, *RPos, Equal); - } else if (LPos && RPos) { - State = relateIteratorPositions(State, *LPos, *RPos, Equal); - } - return State; +const ProgramStateRef saveComparison(ProgramStateRef State, SymbolRef Condition, + SymbolRef LSym, SymbolRef RSym, bool Eq) { + return State->set(Condition, + SymbolComparison(LSym, RSym, Eq)); } -const ProgramStateRef saveComparison(ProgramStateRef State, - const SymExpr *Condition, const SVal &LVal, - const SVal &RVal, bool Eq) { - const auto Left = getRegionOrSymbol(LVal); - const auto Right = getRegionOrSymbol(RVal); - if (!Left || !Right) - return State; - return State->set(Condition, - IteratorComparison(Left, Right, Eq)); -} - -const IteratorComparison *loadComparison(ProgramStateRef State, - const SymExpr *Condition) { - return State->get(Condition); +const SymbolComparison *loadComparison(ProgramStateRef State, + SymbolRef Condition) { + return State->get(Condition); } SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) { @@ -2025,16 +2014,6 @@ return nullptr; } -const IteratorPosition *getIteratorPosition(ProgramStateRef State, - RegionOrSymbol RegOrSym) { - if (RegOrSym.is()) { - return State->get(RegOrSym.get()); - } else if (RegOrSym.is()) { - return State->get(RegOrSym.get()); - } - return nullptr; -} - ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val, const IteratorPosition &Pos) { if (const auto Reg = Val.getAsRegion()) { @@ -2047,18 +2026,6 @@ return nullptr; } -ProgramStateRef setIteratorPosition(ProgramStateRef State, - RegionOrSymbol RegOrSym, - const IteratorPosition &Pos) { - if (RegOrSym.is()) { - return State->set(RegOrSym.get(), - Pos); - } else if (RegOrSym.is()) { - return State->set(RegOrSym.get(), Pos); - } - return nullptr; -} - ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) { if (const auto Reg = Val.getAsRegion()) { return State->remove(Reg); @@ -2070,21 +2037,8 @@ return nullptr; } -ProgramStateRef adjustIteratorPosition(ProgramStateRef State, - RegionOrSymbol RegOrSym, - const IteratorPosition &Pos, - bool Equal) { - if (Equal) { - return setIteratorPosition(State, RegOrSym, Pos); - } else { - return State; - } -} - -ProgramStateRef relateIteratorPositions(ProgramStateRef State, - const IteratorPosition &Pos1, - const IteratorPosition &Pos2, - bool Equal) { +ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1, + SymbolRef Sym2, bool Equal) { auto &SVB = State->getStateManager().getSValBuilder(); // FIXME: This code should be reworked as follows: @@ -2093,14 +2047,16 @@ // 3. Compare the result to 0. // 4. Assume the result of the comparison. const auto comparison = - SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Pos1.getOffset()), - nonloc::SymbolVal(Pos2.getOffset()), - SVB.getConditionType()); + SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Sym1), + nonloc::SymbolVal(Sym2), SVB.getConditionType()); assert(comparison.getAs() && "Symbol comparison must be a `DefinedSVal`"); auto NewState = State->assume(comparison.castAs(), Equal); + if (!NewState) + return nullptr; + if (const auto CompSym = comparison.getAsSymbol()) { assert(isa(CompSym) && "Symbol comparison must be a `SymIntExpr`");