This diff attempts to address a crash (triggered assert) on the newly-added test case.
The assert being discussed is inside SValBuilder::evalBinOp
if (Optional<Loc> RV = rhs.getAs<Loc>()) { // Support pointer arithmetic where the addend is on the left // and the pointer on the right. assert(op == BO_Add);
but the root cause seems to be in a different place
(if I'm not missing smth).
The method simplifySVal appears to be doing the wrong thing for SVal "(char*)End - (char*)Begin".
Call stack: evalIntegralCast -> evalBinOpNN -> simplifySVal -> ... -> simplifySVal -> Simplifier::VisitSymSymExpr -> ...
Inside Simplifier::VisitSymSymExpr the call Visit(S->getLHS()) returns a NonLoc
(where S->getLHS() represents char* End) while the call Visit(S->getRHS()) returns a Loc.
For Visit(S->getRHS()) this happens because in VisitSymbolData(const SymbolData *S) the "if" condition
if (const llvm::APSInt *I = SVB.getKnownValue(State, nonloc::SymbolVal(S)))
is satisfied and Loc is correctly chosen.
For Visit(S->getLHS()) nonloc::SymbolVal(S) is used instead.
Next those values will passed to SValBuilder::evalBinOp and the code path
if (Optional<Loc> RV = rhs.getAs<Loc>()) { // Support pointer arithmetic where the addend is on the left // and the pointer on the right. assert(op == BO_Add); // Commute the operands. return evalBinOpLN(state, op, *RV, lhs.castAs<NonLoc>(), type); }
will be executed instead of the correct one
if (Optional<Loc> LV = lhs.getAs<Loc>()) { if (Optional<Loc> RV = rhs.getAs<Loc>()) return evalBinOpLL(state, op, *LV, *RV, type); return evalBinOpLN(state, op, *LV, rhs.castAs<NonLoc>(), type); }
Test plan: make check-all (green)