void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B) { BinaryOperator::Opcode Op = B->getOpcode(); if (Op != BO_Div && Op != BO_Rem && Op != BO_DivAssign && Op != BO_RemAssign) return; if (!B->getRHS()->getType()->isIntegerType() || !B->getRHS()->getType()->isScalarType()) return; SVal Denom = C.getState()->getSVal(B->getRHS()); const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom); // Divide-by-undefined handled in the generic checking for uses of // undefined values. if (!DV) return; // Check for divide by zero. ConstraintManager &CM = C.getConstraintManager(); const GRState *stateNotZero, *stateZero; llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV); if (stateZero && !stateNotZero) { if (ExplodedNode *N = C.GenerateSink(stateZero)) { if (!BT) BT = new BuiltinBug("Division by zero"); EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(), N); R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, bugreporter::GetDenomExpr(N)); C.EmitReport(R); } return; } // If we get here, then the denom should not be zero. We abandon the implicit // zero denom case for now. C.addTransition(stateNotZero); }
/// Constrain the passed-in state to assume two values are equal. ProgramStateRef GTestChecker::assumeValuesEqual(SVal Val1, SVal Val2, ProgramStateRef State, CheckerContext &C) { if (!Val1.getAs<DefinedOrUnknownSVal>() || !Val2.getAs<DefinedOrUnknownSVal>()) return State; auto ValuesEqual = C.getSValBuilder().evalEQ(State, Val1.castAs<DefinedOrUnknownSVal>(), Val2.castAs<DefinedOrUnknownSVal>()); if (!ValuesEqual.getAs<DefinedSVal>()) return State; State = C.getConstraintManager().assume( State, ValuesEqual.castAs<DefinedSVal>(), true); return State; }
void DivZeroChecker::checkPreStmt(const BinaryOperator *B, CheckerContext &C) const { BinaryOperator::Opcode Op = B->getOpcode(); if (Op != BO_Div && Op != BO_Rem && Op != BO_DivAssign && Op != BO_RemAssign) return; if (!B->getRHS()->getType()->isScalarType()) return; SVal Denom = C.getSVal(B->getRHS()); Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>(); // Divide-by-undefined handled in the generic checking for uses of // undefined values. if (!DV) return; // Check for divide by zero. ConstraintManager &CM = C.getConstraintManager(); ProgramStateRef stateNotZero, stateZero; std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV); if (!stateNotZero) { assert(stateZero); reportBug("Division by zero", stateZero, C); return; } bool TaintedD = C.getState()->isTainted(*DV); if ((stateNotZero && stateZero && TaintedD)) { reportBug("Division by a tainted value, possibly zero", stateZero, C, llvm::make_unique<TaintBugVisitor>(*DV)); return; } // If we get here, then the denom should not be zero. We abandon the implicit // zero denom case for now. C.addTransition(stateNotZero); }
ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state, CheckerContext &C) const { Optional<DefinedSVal> DV = SV.getAs<DefinedSVal>(); if (!DV) return nullptr; ConstraintManager &CM = C.getConstraintManager(); ProgramStateRef stateNotNull, stateNull; std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); if (!stateNotNull && stateNull) { if (ExplodedNode *N = C.generateErrorNode(stateNull)) { if (!BT_nullfp) BT_nullfp.reset(new BuiltinBug(this, "NULL stream pointer", "Stream pointer might be NULL.")); C.emitReport(llvm::make_unique<BugReport>( *BT_nullfp, BT_nullfp->getDescription(), N)); } return nullptr; } return stateNotNull; }
ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state, CheckerContext &C) const { const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV); if (!DV) return 0; ConstraintManager &CM = C.getConstraintManager(); ProgramStateRef stateNotNull, stateNull; llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); if (!stateNotNull && stateNull) { if (ExplodedNode *N = C.generateSink(stateNull)) { if (!BT_nullfp) BT_nullfp.reset(new BuiltinBug("NULL stream pointer", "Stream pointer might be NULL.")); BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N); C.emitReport(R); } return 0; } return stateNotNull; }
void NonNullParamChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { const Decl *FD = Call.getDecl(); if (!FD) return; const NonNullAttr *Att = FD->getAttr<NonNullAttr>(); ProgramStateRef state = C.getState(); CallEvent::param_type_iterator TyI = Call.param_type_begin(), TyE = Call.param_type_end(); for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx){ // Check if the parameter is a reference. We want to report when reference // to a null pointer is passed as a paramter. bool haveRefTypeParam = false; if (TyI != TyE) { haveRefTypeParam = (*TyI)->isReferenceType(); TyI++; } bool haveAttrNonNull = Att && Att->isNonNull(idx); if (!haveAttrNonNull) { // Check if the parameter is also marked 'nonnull'. ArrayRef<ParmVarDecl*> parms = Call.parameters(); if (idx < parms.size()) haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>(); } if (!haveRefTypeParam && !haveAttrNonNull) continue; // If the value is unknown or undefined, we can't perform this check. const Expr *ArgE = Call.getArgExpr(idx); SVal V = Call.getArgSVal(idx); Optional<DefinedSVal> DV = V.getAs<DefinedSVal>(); if (!DV) continue; // Process the case when the argument is not a location. assert(!haveRefTypeParam || DV->getAs<Loc>()); if (haveAttrNonNull && !DV->getAs<Loc>()) { // If the argument is a union type, we want to handle a potential // transparent_union GCC extension. if (!ArgE) continue; QualType T = ArgE->getType(); const RecordType *UT = T->getAsUnionType(); if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>()) continue; if (Optional<nonloc::CompoundVal> CSV = DV->getAs<nonloc::CompoundVal>()) { nonloc::CompoundVal::iterator CSV_I = CSV->begin(); assert(CSV_I != CSV->end()); V = *CSV_I; DV = V.getAs<DefinedSVal>(); assert(++CSV_I == CSV->end()); // FIXME: Handle (some_union){ some_other_union_val }, which turns into // a LazyCompoundVal inside a CompoundVal. if (!V.getAs<Loc>()) continue; // Retrieve the corresponding expression. if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE)) if (const InitListExpr *IE = dyn_cast<InitListExpr>(CE->getInitializer())) ArgE = dyn_cast<Expr>(*(IE->begin())); } else { // FIXME: Handle LazyCompoundVals? continue; } } ConstraintManager &CM = C.getConstraintManager(); ProgramStateRef stateNotNull, stateNull; std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); if (stateNull && !stateNotNull) { // Generate an error node. Check for a null node in case // we cache out. if (ExplodedNode *errorNode = C.generateSink(stateNull)) { BugReport *R = 0; if (haveAttrNonNull) R = genReportNullAttrNonNull(errorNode, ArgE); else if (haveRefTypeParam) R = genReportReferenceToNullPointer(errorNode, ArgE); // Highlight the range of the argument that was null. R->addRange(Call.getArgSourceRange(idx)); // Emit the bug report. C.emitReport(R); } // Always return. Either we cached out or we just emitted an error. return; } // If a pointer value passed the check we should assume that it is // indeed not null from this point forward. assert(stateNotNull); state = stateNotNull; } // If we reach here all of the arguments passed the nonnull check. // If 'state' has been updated generated a new node. C.addTransition(state); }
void AttrNonNullChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { const Decl *FD = Call.getDecl(); if (!FD) return; const NonNullAttr *Att = FD->getAttr<NonNullAttr>(); if (!Att) return; ProgramStateRef state = C.getState(); // Iterate through the arguments of CE and check them for null. for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx) { if (!Att->isNonNull(idx)) continue; SVal V = Call.getArgSVal(idx); DefinedSVal *DV = dyn_cast<DefinedSVal>(&V); // If the value is unknown or undefined, we can't perform this check. if (!DV) continue; if (!isa<Loc>(*DV)) { // If the argument is a union type, we want to handle a potential // transparent_union GCC extension. const Expr *ArgE = Call.getArgExpr(idx); if (!ArgE) continue; QualType T = ArgE->getType(); const RecordType *UT = T->getAsUnionType(); if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>()) continue; if (nonloc::CompoundVal *CSV = dyn_cast<nonloc::CompoundVal>(DV)) { nonloc::CompoundVal::iterator CSV_I = CSV->begin(); assert(CSV_I != CSV->end()); V = *CSV_I; DV = dyn_cast<DefinedSVal>(&V); assert(++CSV_I == CSV->end()); if (!DV) continue; } else { // FIXME: Handle LazyCompoundVals? continue; } } ConstraintManager &CM = C.getConstraintManager(); ProgramStateRef stateNotNull, stateNull; llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); if (stateNull && !stateNotNull) { // Generate an error node. Check for a null node in case // we cache out. if (ExplodedNode *errorNode = C.generateSink(stateNull)) { // Lazily allocate the BugType object if it hasn't already been // created. Ownership is transferred to the BugReporter object once // the BugReport is passed to 'EmitWarning'. if (!BT) BT.reset(new BugType("Argument with 'nonnull' attribute passed null", "API")); BugReport *R = new BugReport(*BT, "Null pointer passed as an argument to a " "'nonnull' parameter", errorNode); // Highlight the range of the argument that was null. R->addRange(Call.getArgSourceRange(idx)); if (const Expr *ArgE = Call.getArgExpr(idx)) bugreporter::addTrackNullOrUndefValueVisitor(errorNode, ArgE, R); // Emit the bug report. C.EmitReport(R); } // Always return. Either we cached out or we just emitted an error. return; } // If a pointer value passed the check we should assume that it is // indeed not null from this point forward. assert(stateNotNull); state = stateNotNull; } // If we reach here all of the arguments passed the nonnull check. // If 'state' has been updated generated a new node. C.addTransition(state); }
void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const { // We are only interested in stores into Booleans. const TypedValueRegion *TR = dyn_cast_or_null<TypedValueRegion>(loc.getAsRegion()); if (!TR) return; QualType valTy = TR->getValueType(); if (!isBooleanType(valTy)) return; // Get the value of the right-hand side. We only care about values // that are defined (UnknownVals and UndefinedVals are handled by other // checkers). Optional<DefinedSVal> DV = val.getAs<DefinedSVal>(); if (!DV) return; // Check if the assigned value meets our criteria for correctness. It must // be a value that is either 0 or 1. One way to check this is to see if // the value is possibly < 0 (for a negative value) or greater than 1. ProgramStateRef state = C.getState(); SValBuilder &svalBuilder = C.getSValBuilder(); ConstraintManager &CM = C.getConstraintManager(); // First, ensure that the value is >= 0. DefinedSVal zeroVal = svalBuilder.makeIntVal(0, valTy); SVal greaterThanOrEqualToZeroVal = svalBuilder.evalBinOp(state, BO_GE, *DV, zeroVal, svalBuilder.getConditionType()); Optional<DefinedSVal> greaterThanEqualToZero = greaterThanOrEqualToZeroVal.getAs<DefinedSVal>(); if (!greaterThanEqualToZero) { // The SValBuilder cannot construct a valid SVal for this condition. // This means we cannot properly reason about it. return; } ProgramStateRef stateLT, stateGE; std::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero); // Is it possible for the value to be less than zero? if (stateLT) { // It is possible for the value to be less than zero. We only // want to emit a warning, however, if that value is fully constrained. // If it it possible for the value to be >= 0, then essentially the // value is underconstrained and there is nothing left to be done. if (!stateGE) emitReport(stateLT, C); // In either case, we are done. return; } // If we reach here, it must be the case that the value is constrained // to only be >= 0. assert(stateGE == state); // At this point we know that the value is >= 0. // Now check to ensure that the value is <= 1. DefinedSVal OneVal = svalBuilder.makeIntVal(1, valTy); SVal lessThanEqToOneVal = svalBuilder.evalBinOp(state, BO_LE, *DV, OneVal, svalBuilder.getConditionType()); Optional<DefinedSVal> lessThanEqToOne = lessThanEqToOneVal.getAs<DefinedSVal>(); if (!lessThanEqToOne) { // The SValBuilder cannot construct a valid SVal for this condition. // This means we cannot properly reason about it. return; } ProgramStateRef stateGT, stateLE; std::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne); // Is it possible for the value to be greater than one? if (stateGT) { // It is possible for the value to be greater than one. We only // want to emit a warning, however, if that value is fully constrained. // If it is possible for the value to be <= 1, then essentially the // value is underconstrained and there is nothing left to be done. if (!stateLE) emitReport(stateGT, C); // In either case, we are done. return; } // If we reach here, it must be the case that the value is constrained // to only be <= 1. assert(stateLE == state); }
void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { const GRState *state = C.getState(); const GRState *originalState = state; // Check if the callee has a 'nonnull' attribute. SVal X = state->getSVal(CE->getCallee()); const FunctionDecl* FD = X.getAsFunctionDecl(); if (!FD) return; const NonNullAttr* Att = FD->getAttr<NonNullAttr>(); if (!Att) return; // Iterate through the arguments of CE and check them for null. unsigned idx = 0; for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E; ++I, ++idx) { if (!Att->isNonNull(idx)) continue; const SVal &V = state->getSVal(*I); const DefinedSVal *DV = dyn_cast<DefinedSVal>(&V); if (!DV) continue; ConstraintManager &CM = C.getConstraintManager(); const GRState *stateNotNull, *stateNull; llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV); if (stateNull && !stateNotNull) { // Generate an error node. Check for a null node in case // we cache out. if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) { // Lazily allocate the BugType object if it hasn't already been // created. Ownership is transferred to the BugReporter object once // the BugReport is passed to 'EmitWarning'. if (!BT) BT = new BugType("Argument with 'nonnull' attribute passed null", "API"); EnhancedBugReport *R = new EnhancedBugReport(*BT, "Null pointer passed as an argument to a " "'nonnull' parameter", errorNode); // Highlight the range of the argument that was null. const Expr *arg = *I; R->addRange(arg->getSourceRange()); R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg); // Emit the bug report. C.EmitReport(R); } // Always return. Either we cached out or we just emitted an error. return; } // If a pointer value passed the check we should assume that it is // indeed not null from this point forward. assert(stateNotNull); state = stateNotNull; } // If we reach here all of the arguments passed the nonnull check. // If 'state' has been updated generated a new node. if (state != originalState) C.addTransition(C.GenerateNode(CE, state)); }
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. // Check if the size is negative. SValBuilder &svalBuilder = C.getSValBuilder(); QualType Ty = SE->getType(); DefinedOrUnknownSVal Zero = svalBuilder.makeZeroVal(Ty); SVal LessThanZeroVal = svalBuilder.evalBinOp(state, BO_LT, sizeD, Zero, Ty); if (Optional<DefinedSVal> LessThanZeroDVal = LessThanZeroVal.getAs<DefinedSVal>()) { ConstraintManager &CM = C.getConstraintManager(); ProgramStateRef StatePos, StateNeg; std::tie(StateNeg, StatePos) = CM.assumeDual(state, *LessThanZeroDVal); if (StateNeg && !StatePos) { reportBug(VLA_Negative, SE, state, C); return; } state = StatePos; } // Convert the array length to size_t. 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); }
void NonNullParamChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { if (!Call.getDecl()) return; llvm::SmallBitVector AttrNonNull = getNonNullAttrs(Call); unsigned NumArgs = Call.getNumArgs(); ProgramStateRef state = C.getState(); ArrayRef<ParmVarDecl*> parms = Call.parameters(); for (unsigned idx = 0; idx < NumArgs; ++idx) { // For vararg functions, a corresponding parameter decl may not exist. bool HasParam = idx < parms.size(); // Check if the parameter is a reference. We want to report when reference // to a null pointer is passed as a parameter. bool haveRefTypeParam = HasParam ? parms[idx]->getType()->isReferenceType() : false; bool haveAttrNonNull = AttrNonNull[idx]; // Check if the parameter is also marked 'nonnull'. if (!haveAttrNonNull && HasParam) haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>(); if (!haveAttrNonNull && !haveRefTypeParam) continue; // If the value is unknown or undefined, we can't perform this check. const Expr *ArgE = Call.getArgExpr(idx); SVal V = Call.getArgSVal(idx); auto DV = V.getAs<DefinedSVal>(); if (!DV) continue; assert(!haveRefTypeParam || DV->getAs<Loc>()); // Process the case when the argument is not a location. if (haveAttrNonNull && !DV->getAs<Loc>()) { // If the argument is a union type, we want to handle a potential // transparent_union GCC extension. if (!ArgE) continue; QualType T = ArgE->getType(); const RecordType *UT = T->getAsUnionType(); if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>()) continue; auto CSV = DV->getAs<nonloc::CompoundVal>(); // FIXME: Handle LazyCompoundVals? if (!CSV) continue; V = *(CSV->begin()); DV = V.getAs<DefinedSVal>(); assert(++CSV->begin() == CSV->end()); // FIXME: Handle (some_union){ some_other_union_val }, which turns into // a LazyCompoundVal inside a CompoundVal. if (!V.getAs<Loc>()) continue; // Retrieve the corresponding expression. if (const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE)) if (const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer())) ArgE = dyn_cast<Expr>(*(IE->begin())); } ConstraintManager &CM = C.getConstraintManager(); ProgramStateRef stateNotNull, stateNull; std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); // Generate an error node. Check for a null node in case // we cache out. if (stateNull && !stateNotNull) { if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) { std::unique_ptr<BugReport> R; if (haveAttrNonNull) R = genReportNullAttrNonNull(errorNode, ArgE); else if (haveRefTypeParam) R = genReportReferenceToNullPointer(errorNode, ArgE); // Highlight the range of the argument that was null. R->addRange(Call.getArgSourceRange(idx)); // Emit the bug report. C.emitReport(std::move(R)); } // Always return. Either we cached out or we just emitted an error. return; } if (stateNull) { if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) { ImplicitNullDerefEvent event = { V, false, N, &C.getBugReporter(), /*IsDirectDereference=*/haveRefTypeParam}; dispatchEvent(event); } } // If a pointer value passed the check we should assume that it is // indeed not null from this point forward. state = stateNotNull; } // If we reach here all of the arguments passed the nonnull check. // If 'state' has been updated generated a new node. C.addTransition(state); }