================ @@ -379,6 +386,111 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, C.addTransition(State, this); } +void DereferenceChecker::checkPreStmt(const BinaryOperator *Op, + CheckerContext &C) const { + if (!Op->isAdditiveOp()) + return; + const Expr *E1 = Op->getLHS(); + const Expr *E2 = Op->getRHS(); + QualType T1 = E1->getType().getCanonicalType(); + QualType T2 = E2->getType().getCanonicalType(); + if (T1->isIntegerType() && T2->isIntegerType()) + return; + if (!T1->isPointerType() && !T1->isIntegerType() && !T2->isPointerType() && + !T2->isIntegerType()) + return; + + ProgramStateRef State = C.getState(); + SVal V1 = State->getSVal(E1, C.getLocationContext()); + SVal V2 = State->getSVal(E2, C.getLocationContext()); + if (V1.isUndef() || V2.isUndef()) + return; + + ConditionTruthVal V1IsNull = State->isNull(V1); + ConditionTruthVal V2IsNull = State->isNull(V2); + bool IsConstrained = true; + + // Check cases 'NULL + x' and 'NULL - x' + if (T1->isPointerType() && T2->isIntegerType()) { + if (!V1IsNull.isConstrainedTrue() || V2IsNull.isConstrainedTrue()) + return; + IsConstrained = V2IsNull.isConstrainedFalse(); + } + + // Check case 'x + NULL' + if (T1->isIntegerType() && T2->isPointerType()) { + if (V1IsNull.isConstrainedTrue() || !V2IsNull.isConstrainedTrue()) + return; + IsConstrained = V1IsNull.isConstrainedFalse(); + } + + // Check case 'NULL - p' or 'p - NULL' + if (T1->isPointerType() && T2->isPointerType()) { + if (!V1IsNull.isConstrainedTrue() && !V2IsNull.isConstrainedTrue()) + return; + if (V1IsNull.isConstrainedTrue() && V2IsNull.isConstrainedTrue()) + return; + IsConstrained = + V1IsNull.isConstrainedFalse() || V2IsNull.isConstrainedFalse(); + } + + SmallString<100> Buf; + llvm::raw_svector_ostream Out(Buf); + SmallVector<SourceRange, 2> Ranges; + + auto AddSubExprStr = [&](const Expr *E, bool IsPointer, + ConditionTruthVal IsNull) { + if (IsNull.isConstrainedTrue()) { + if (IsPointer) + Out << "null pointer"; + else + Out << "zero"; + } else { + if (!IsNull.isConstrainedFalse()) + Out << "probably "; + if (IsPointer) + Out << "non-null pointer"; + else + Out << "nonzero integer value"; + } + if (IsPointer) + AddDerefSource(Out, Ranges, E, State.get(), C.getLocationContext(), + false); + }; + + if (Op->getOpcode() == BO_Add) + Out << "Addition of a "; + else + Out << "Subtraction of a "; + AddSubExprStr(E1, T1->isPointerType(), V1IsNull); + Out << " and a "; + AddSubExprStr(E2, T2->isPointerType(), V2IsNull); + + if (IsConstrained) + Out << " results "; + else + Out << " may result "; + Out << "in undefined behavior"; ---------------- steakhal wrote:
I really wish we could simplify this. It's generally hard to predict the possible result string patterns due to the control-flow and stateful nature of such code. I'd recommend thinking about how to make it more declarative. For example, having ternaries usually makes the code terser, hence easier to put together the pieces. Even better, having a string table, and just selecting the relevant pattern and filling the details using llvm::formatv. Or something along the way. https://github.com/llvm/llvm-project/pull/157129 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits