Example #1
0
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);
}
Example #2
0
/// 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);
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #6
0
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);
}
Example #7
0
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);
}
Example #8
0
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);
}
Example #9
0
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));
}
Example #10
0
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);
}