예제 #1
0
static bool AreTypesCompatible(QualType Derived, QualType Ancestor,
                               ASTContext& C) {

  // Right now don't compare the compatibility of pointers.  That involves
  // looking at subtyping relationships.  FIXME: Future patch.
  if (Derived->isAnyPointerType() &&  Ancestor->isAnyPointerType())
    return true;

  return C.typesAreCompatible(Derived, Ancestor);
}
예제 #2
0
/// Explicit casts are trusted. If there is a disagreement in the nullability
/// annotations in the destination and the source or '0' is casted to nonnull
/// track the value as having contraditory nullability. This will allow users to
/// suppress warnings.
void NullabilityChecker::checkPostStmt(const ExplicitCastExpr *CE,
                                       CheckerContext &C) const {
  QualType OriginType = CE->getSubExpr()->getType();
  QualType DestType = CE->getType();
  if (!OriginType->isAnyPointerType())
    return;
  if (!DestType->isAnyPointerType())
    return;

  ProgramStateRef State = C.getState();
  if (State->get<PreconditionViolated>())
    return;

  Nullability DestNullability = getNullabilityAnnotation(DestType);

  // No explicit nullability in the destination type, so this cast does not
  // change the nullability.
  if (DestNullability == Nullability::Unspecified)
    return;

  auto RegionSVal =
      State->getSVal(CE, C.getLocationContext()).getAs<DefinedOrUnknownSVal>();
  const MemRegion *Region = getTrackRegion(*RegionSVal);
  if (!Region)
    return;

  // When 0 is converted to nonnull mark it as contradicted.
  if (DestNullability == Nullability::Nonnull) {
    NullConstraint Nullness = getNullConstraint(*RegionSVal, State);
    if (Nullness == NullConstraint::IsNull) {
      State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
      C.addTransition(State);
      return;
    }
  }

  const NullabilityState *TrackedNullability =
      State->get<NullabilityMap>(Region);

  if (!TrackedNullability) {
    if (DestNullability != Nullability::Nullable)
      return;
    State = State->set<NullabilityMap>(Region,
                                       NullabilityState(DestNullability, CE));
    C.addTransition(State);
    return;
  }

  if (TrackedNullability->getValue() != DestNullability &&
      TrackedNullability->getValue() != Nullability::Contradicted) {
    State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
    C.addTransition(State);
  }
}
예제 #3
0
static bool isCallbackArg(SVal V, QualType T) {
  // If the parameter is 0, it's harmless.
  if (V.isZeroConstant())
    return false;

  // If a parameter is a block or a callback, assume it can modify pointer.
  if (T->isBlockPointerType() ||
      T->isFunctionPointerType() ||
      T->isObjCSelType())
    return true;

  // Check if a callback is passed inside a struct (for both, struct passed by
  // reference and by value). Dig just one level into the struct for now.

  if (T->isAnyPointerType() || T->isReferenceType())
    T = T->getPointeeType();

  if (const RecordType *RT = T->getAsStructureType()) {
    const RecordDecl *RD = RT->getDecl();
    for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
         I != E; ++I) {
      QualType FieldT = I->getType();
      if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType())
        return true;
    }
  }

  return false;
}
예제 #4
0
static bool isPointerToConst(const ParmVarDecl *ParamDecl) {
  QualType PointeeTy = ParamDecl->getOriginalType()->getPointeeType();
  if (PointeeTy != QualType() && PointeeTy.isConstQualified() &&
      !PointeeTy->isAnyPointerType() && !PointeeTy->isReferenceType()) {
    return true;
  }
  return false;
}
예제 #5
0
void MicrosoftCXXNameMangler::mangleType(QualType T) {
  // Only operate on the canonical type!
  T = getASTContext().getCanonicalType(T);
  
  Qualifiers Quals = T.getLocalQualifiers();
  if (Quals) {
    // We have to mangle these now, while we still have enough information.
    // <pointer-cvr-qualifiers> ::= P  # pointer
    //                          ::= Q  # const pointer
    //                          ::= R  # volatile pointer
    //                          ::= S  # const volatile pointer
    if (T->isAnyPointerType() || T->isMemberPointerType() ||
        T->isBlockPointerType()) {
      if (!Quals.hasVolatile())
        Out << 'Q';
      else {
        if (!Quals.hasConst())
          Out << 'R';
        else
          Out << 'S';
      }
    } else
      // Just emit qualifiers like normal.
      // NB: When we mangle a pointer/reference type, and the pointee
      // type has no qualifiers, the lack of qualifier gets mangled
      // in there.
      mangleQualifiers(Quals, false);
  } else if (T->isAnyPointerType() || T->isMemberPointerType() ||
             T->isBlockPointerType()) {
    Out << 'P';
  }
  switch (T->getTypeClass()) {
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT) \
case Type::CLASS: \
llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
return;
#define TYPE(CLASS, PARENT) \
case Type::CLASS: \
mangleType(static_cast<const CLASS##Type*>(T.getTypePtr())); \
break;
#include "clang/AST/TypeNodes.def"
  }
}
예제 #6
0
파일: Calls.cpp 프로젝트: CTSRD-TESLA/clang
/// \brief Returns true if a type is a pointer-to-const or reference-to-const
/// with no further indirection.
static bool isPointerToConst(QualType Ty) {
  QualType PointeeTy = Ty->getPointeeType();
  if (PointeeTy == QualType())
    return false;
  if (!PointeeTy.isConstQualified())
    return false;
  if (PointeeTy->isAnyPointerType())
    return false;
  return true;
}
예제 #7
0
PathDiagnosticPiece *
UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
                                  const ExplodedNode *PrevN,
                                  BugReporterContext &BRC,
                                  BugReport &BR) {

  ProgramStateRef State = N->getState();
  ProgramPoint ProgLoc = N->getLocation();

  // We are only interested in visiting CallEnter nodes.
  Optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>();
  if (!CEnter)
    return 0;

  // Check if one of the arguments is the region the visitor is tracking.
  CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
  CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State);
  unsigned Idx = 0;
  for (CallEvent::param_iterator I = Call->param_begin(),
                                 E = Call->param_end(); I != E; ++I, ++Idx) {
    const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion();

    // Are we tracking the argument or its subregion?
    if ( !ArgReg || (ArgReg != R && !R->isSubRegionOf(ArgReg->StripCasts())))
      continue;

    // Check the function parameter type.
    const ParmVarDecl *ParamDecl = *I;
    assert(ParamDecl && "Formal parameter has no decl?");
    QualType T = ParamDecl->getType();

    if (!(T->isAnyPointerType() || T->isReferenceType())) {
      // Function can only change the value passed in by address.
      continue;
    }
    
    // If it is a const pointer value, the function does not intend to
    // change the value.
    if (T->getPointeeType().isConstQualified())
      continue;

    // Mark the call site (LocationContext) as interesting if the value of the 
    // argument is undefined or '0'/'NULL'.
    SVal BoundVal = State->getSVal(R);
    if (BoundVal.isUndef() || BoundVal.isZeroConstant()) {
      BR.markInteresting(CEnter->getCalleeContext());
      return 0;
    }
  }
  return 0;
}
예제 #8
0
/// Suppress the nullability warnings for some functions.
void NullabilityChecker::checkPostCall(const CallEvent &Call,
                                       CheckerContext &C) const {
  auto Decl = Call.getDecl();
  if (!Decl)
    return;
  // ObjC Messages handles in a different callback.
  if (Call.getKind() == CE_ObjCMessage)
    return;
  const FunctionType *FuncType = Decl->getFunctionType();
  if (!FuncType)
    return;
  QualType ReturnType = FuncType->getReturnType();
  if (!ReturnType->isAnyPointerType())
    return;
  ProgramStateRef State = C.getState();
  if (State->get<PreconditionViolated>())
    return;

  const MemRegion *Region = getTrackRegion(Call.getReturnValue());
  if (!Region)
    return;

  // CG headers are misannotated. Do not warn for symbols that are the results
  // of CG calls.
  const SourceManager &SM = C.getSourceManager();
  StringRef FilePath = SM.getFilename(SM.getSpellingLoc(Decl->getLocStart()));
  if (llvm::sys::path::filename(FilePath).startswith("CG")) {
    State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
    C.addTransition(State);
    return;
  }

  const NullabilityState *TrackedNullability =
      State->get<NullabilityMap>(Region);

  if (!TrackedNullability &&
      getNullabilityAnnotation(ReturnType) == Nullability::Nullable) {
    State = State->set<NullabilityMap>(Region, Nullability::Nullable);
    C.addTransition(State);
  }
}
예제 #9
0
static bool isCallback(QualType T) {
  // If a parameter is a block or a callback, assume it can modify pointer.
  if (T->isBlockPointerType() ||
      T->isFunctionPointerType() ||
      T->isObjCSelType())
    return true;

  // Check if a callback is passed inside a struct (for both, struct passed by
  // reference and by value). Dig just one level into the struct for now.

  if (T->isAnyPointerType() || T->isReferenceType())
    T = T->getPointeeType();

  if (const RecordType *RT = T->getAsStructureType()) {
    const RecordDecl *RD = RT->getDecl();
    for (const auto *I : RD->fields()) {
      QualType FieldT = I->getType();
      if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType())
        return true;
    }
  }
  return false;
}
예제 #10
0
static bool isPointerToConst(const QualType &QT) {
  return QT->isAnyPointerType() && QT->getPointeeType().isConstQualified();
}
예제 #11
0
SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
                                  BinaryOperator::Opcode op,
                                  Loc lhs, NonLoc rhs, QualType resultTy) {
  if (op >= BO_PtrMemD && op <= BO_PtrMemI) {
    if (auto PTMSV = rhs.getAs<nonloc::PointerToMember>()) {
      if (PTMSV->isNullMemberPointer())
        return UndefinedVal();
      if (const FieldDecl *FD = PTMSV->getDeclAs<FieldDecl>()) {
        SVal Result = lhs;

        for (const auto &I : *PTMSV)
          Result = StateMgr.getStoreManager().evalDerivedToBase(
              Result, I->getType(),I->isVirtual());
        return state->getLValue(FD, Result);
      }
    }

    return rhs;
  }

  assert(!BinaryOperator::isComparisonOp(op) &&
         "arguments to comparison ops must be of the same type");

  // Special case: rhs is a zero constant.
  if (rhs.isZeroConstant())
    return lhs;

  // We are dealing with pointer arithmetic.

  // Handle pointer arithmetic on constant values.
  if (Optional<nonloc::ConcreteInt> rhsInt = rhs.getAs<nonloc::ConcreteInt>()) {
    if (Optional<loc::ConcreteInt> lhsInt = lhs.getAs<loc::ConcreteInt>()) {
      const llvm::APSInt &leftI = lhsInt->getValue();
      assert(leftI.isUnsigned());
      llvm::APSInt rightI(rhsInt->getValue(), /* isUnsigned */ true);

      // Convert the bitwidth of rightI.  This should deal with overflow
      // since we are dealing with concrete values.
      rightI = rightI.extOrTrunc(leftI.getBitWidth());

      // Offset the increment by the pointer size.
      llvm::APSInt Multiplicand(rightI.getBitWidth(), /* isUnsigned */ true);
      rightI *= Multiplicand;

      // Compute the adjusted pointer.
      switch (op) {
        case BO_Add:
          rightI = leftI + rightI;
          break;
        case BO_Sub:
          rightI = leftI - rightI;
          break;
        default:
          llvm_unreachable("Invalid pointer arithmetic operation");
      }
      return loc::ConcreteInt(getBasicValueFactory().getValue(rightI));
    }
  }

  // Handle cases where 'lhs' is a region.
  if (const MemRegion *region = lhs.getAsRegion()) {
    rhs = convertToArrayIndex(rhs).castAs<NonLoc>();
    SVal index = UnknownVal();
    const MemRegion *superR = nullptr;
    // We need to know the type of the pointer in order to add an integer to it.
    // Depending on the type, different amount of bytes is added.
    QualType elementType;

    if (const ElementRegion *elemReg = dyn_cast<ElementRegion>(region)) {
      assert(op == BO_Add || op == BO_Sub);
      index = evalBinOpNN(state, op, elemReg->getIndex(), rhs,
                          getArrayIndexType());
      superR = elemReg->getSuperRegion();
      elementType = elemReg->getElementType();
    }
    else if (isa<SubRegion>(region)) {
      assert(op == BO_Add || op == BO_Sub);
      index = (op == BO_Add) ? rhs : evalMinus(rhs);
      superR = region;
      // TODO: Is this actually reliable? Maybe improving our MemRegion
      // hierarchy to provide typed regions for all non-void pointers would be
      // better. For instance, we cannot extend this towards LocAsInteger
      // operations, where result type of the expression is integer.
      if (resultTy->isAnyPointerType())
        elementType = resultTy->getPointeeType();
    }

    if (Optional<NonLoc> indexV = index.getAs<NonLoc>()) {
      return loc::MemRegionVal(MemMgr.getElementRegion(elementType, *indexV,
                                                       superR, getContext()));
    }
  }
  return UnknownVal();
}
예제 #12
0
SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
                                  BinaryOperator::Opcode op,
                                  Loc lhs, NonLoc rhs, QualType resultTy) {
  assert(!BinaryOperator::isComparisonOp(op) &&
         "arguments to comparison ops must be of the same type");

  // Special case: rhs is a zero constant.
  if (rhs.isZeroConstant())
    return lhs;
  
  // We are dealing with pointer arithmetic.

  // Handle pointer arithmetic on constant values.
  if (Optional<nonloc::ConcreteInt> rhsInt = rhs.getAs<nonloc::ConcreteInt>()) {
    if (Optional<loc::ConcreteInt> lhsInt = lhs.getAs<loc::ConcreteInt>()) {
      const llvm::APSInt &leftI = lhsInt->getValue();
      assert(leftI.isUnsigned());
      llvm::APSInt rightI(rhsInt->getValue(), /* isUnsigned */ true);

      // Convert the bitwidth of rightI.  This should deal with overflow
      // since we are dealing with concrete values.
      rightI = rightI.extOrTrunc(leftI.getBitWidth());

      // Offset the increment by the pointer size.
      llvm::APSInt Multiplicand(rightI.getBitWidth(), /* isUnsigned */ true);
      rightI *= Multiplicand;
      
      // Compute the adjusted pointer.
      switch (op) {
        case BO_Add:
          rightI = leftI + rightI;
          break;
        case BO_Sub:
          rightI = leftI - rightI;
          break;
        default:
          llvm_unreachable("Invalid pointer arithmetic operation");
      }
      return loc::ConcreteInt(getBasicValueFactory().getValue(rightI));
    }
  }

  // Handle cases where 'lhs' is a region.
  if (const MemRegion *region = lhs.getAsRegion()) {
    rhs = convertToArrayIndex(rhs).castAs<NonLoc>();
    SVal index = UnknownVal();
    const MemRegion *superR = 0;
    QualType elementType;

    if (const ElementRegion *elemReg = dyn_cast<ElementRegion>(region)) {
      assert(op == BO_Add || op == BO_Sub);
      index = evalBinOpNN(state, op, elemReg->getIndex(), rhs,
                          getArrayIndexType());
      superR = elemReg->getSuperRegion();
      elementType = elemReg->getElementType();
    }
    else if (isa<SubRegion>(region)) {
      superR = region;
      index = rhs;
      if (resultTy->isAnyPointerType())
        elementType = resultTy->getPointeeType();
    }

    if (Optional<NonLoc> indexV = index.getAs<NonLoc>()) {
      return loc::MemRegionVal(MemMgr.getElementRegion(elementType, *indexV,
                                                       superR, getContext()));
    }
  }
  return UnknownVal();  
}
예제 #13
0
/// Propagate the nullability information through binds and warn when nullable
/// pointer or null symbol is assigned to a pointer with a nonnull type.
void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S,
                                   CheckerContext &C) const {
  const TypedValueRegion *TVR =
      dyn_cast_or_null<TypedValueRegion>(L.getAsRegion());
  if (!TVR)
    return;

  QualType LocType = TVR->getValueType();
  if (!LocType->isAnyPointerType())
    return;

  ProgramStateRef State = C.getState();
  if (State->get<PreconditionViolated>())
    return;

  auto ValDefOrUnknown = V.getAs<DefinedOrUnknownSVal>();
  if (!ValDefOrUnknown)
    return;

  NullConstraint RhsNullness = getNullConstraint(*ValDefOrUnknown, State);

  Nullability ValNullability = Nullability::Unspecified;
  if (SymbolRef Sym = ValDefOrUnknown->getAsSymbol())
    ValNullability = getNullabilityAnnotation(Sym->getType());

  Nullability LocNullability = getNullabilityAnnotation(LocType);
  if (Filter.CheckNullPassedToNonnull &&
      RhsNullness == NullConstraint::IsNull &&
      ValNullability != Nullability::Nonnull &&
      LocNullability == Nullability::Nonnull) {
    static CheckerProgramPointTag Tag(this, "NullPassedToNonnull");
    ExplodedNode *N = C.generateErrorNode(State, &Tag);
    if (!N)
      return;

    const Stmt *ValueExpr = matchValueExprForBind(S);
    if (!ValueExpr)
      ValueExpr = S;

    reportBugIfPreconditionHolds(ErrorKind::NilAssignedToNonnull, N, nullptr, C,
                                 ValueExpr);
    return;
  }
  // Intentionally missing case: '0' is bound to a reference. It is handled by
  // the DereferenceChecker.

  const MemRegion *ValueRegion = getTrackRegion(*ValDefOrUnknown);
  if (!ValueRegion)
    return;

  const NullabilityState *TrackedNullability =
      State->get<NullabilityMap>(ValueRegion);

  if (TrackedNullability) {
    if (RhsNullness == NullConstraint::IsNotNull ||
        TrackedNullability->getValue() != Nullability::Nullable)
      return;
    if (Filter.CheckNullablePassedToNonnull &&
        LocNullability == Nullability::Nonnull) {
      static CheckerProgramPointTag Tag(this, "NullablePassedToNonnull");
      ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
      reportBugIfPreconditionHolds(ErrorKind::NullableAssignedToNonnull, N,
                                   ValueRegion, C);
    }
    return;
  }

  const auto *BinOp = dyn_cast<BinaryOperator>(S);

  if (ValNullability == Nullability::Nullable) {
    // Trust the static information of the value more than the static
    // information on the location.
    const Stmt *NullabilitySource = BinOp ? BinOp->getRHS() : S;
    State = State->set<NullabilityMap>(
        ValueRegion, NullabilityState(ValNullability, NullabilitySource));
    C.addTransition(State);
    return;
  }

  if (LocNullability == Nullability::Nullable) {
    const Stmt *NullabilitySource = BinOp ? BinOp->getLHS() : S;
    State = State->set<NullabilityMap>(
        ValueRegion, NullabilityState(LocNullability, NullabilitySource));
    C.addTransition(State);
  }
}
  Expr* ValueExtractionSynthesizer::SynthesizeSVRInit(Expr* E) {
    if (!m_gClingVD)
      FindAndCacheRuntimeDecls();

    // Build a reference to gCling
    ExprResult gClingDRE
      = m_Sema->BuildDeclRefExpr(m_gClingVD, m_Context->VoidPtrTy,
                                 VK_RValue, SourceLocation());
    // We have the wrapper as Sema's CurContext
    FunctionDecl* FD = cast<FunctionDecl>(m_Sema->CurContext);

    ExprWithCleanups* Cleanups = 0;
    // In case of ExprWithCleanups we need to extend its 'scope' to the call.
    if (E && isa<ExprWithCleanups>(E)) {
      Cleanups = cast<ExprWithCleanups>(E);
      E = Cleanups->getSubExpr();
    }

    // Build a reference to Value* in the wrapper, should be
    // the only argument of the wrapper.
    SourceLocation locStart = (E) ? E->getLocStart() : FD->getLocStart();
    SourceLocation locEnd = (E) ? E->getLocEnd() : FD->getLocEnd();
    ExprResult wrapperSVRDRE
      = m_Sema->BuildDeclRefExpr(FD->getParamDecl(0), m_Context->VoidPtrTy,
                                 VK_RValue, locStart);
    QualType ETy = (E) ? E->getType() : m_Context->VoidTy;
    QualType desugaredTy = ETy.getDesugaredType(*m_Context);

    // The expr result is transported as reference, pointer, array, float etc
    // based on the desugared type. We should still expose the typedef'ed
    // (sugared) type to the cling::Value.
    if (desugaredTy->isRecordType() && E->getValueKind() == VK_LValue) {
      // returning a lvalue (not a temporary): the value should contain
      // a reference to the lvalue instead of copying it.
      desugaredTy = m_Context->getLValueReferenceType(desugaredTy);
      ETy = m_Context->getLValueReferenceType(ETy);
    }
    Expr* ETyVP
      = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy,
                                             (uintptr_t)ETy.getAsOpaquePtr());

    // Pass whether to Value::dump() or not:
    Expr* EVPOn
      = new (*m_Context) CharacterLiteral(getCompilationOpts().ValuePrinting,
                                          CharacterLiteral::Ascii,
                                          m_Context->CharTy,
                                          SourceLocation());

    llvm::SmallVector<Expr*, 6> CallArgs;
    CallArgs.push_back(gClingDRE.get());
    CallArgs.push_back(wrapperSVRDRE.get());
    CallArgs.push_back(ETyVP);
    CallArgs.push_back(EVPOn);

    ExprResult Call;
    SourceLocation noLoc = locStart;
    if (desugaredTy->isVoidType()) {
      // In cases where the cling::Value gets reused we need to reset the
      // previous settings to void.
      // We need to synthesize setValueNoAlloc(...), E, because we still need
      // to run E.

      // FIXME: Suboptimal: this discards the already created AST nodes.
      QualType vpQT = m_Context->VoidPtrTy;
      QualType vQT = m_Context->VoidTy;
      Expr* vpQTVP
        = utils::Synthesize::CStyleCastPtrExpr(m_Sema, vpQT,
                                               (uintptr_t)vQT.getAsOpaquePtr());
      CallArgs[2] = vpQTVP;


      Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc,
                                   locStart, CallArgs, locEnd);

      if (E)
        Call = m_Sema->CreateBuiltinBinOp(locStart, BO_Comma, Call.get(), E);

    }
    else if (desugaredTy->isRecordType() || desugaredTy->isConstantArrayType()
             || desugaredTy->isMemberPointerType()) {
      // 2) object types :
      // check existence of copy constructor before call
      if (!desugaredTy->isMemberPointerType()
          && !availableCopyConstructor(desugaredTy, m_Sema))
        return E;
      // call new (setValueWithAlloc(gCling, &SVR, ETy)) (E)
      Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedWithAlloc,
                                   locStart, CallArgs, locEnd);
      Expr* placement = Call.get();
      if (const ConstantArrayType* constArray
          = dyn_cast<ConstantArrayType>(desugaredTy.getTypePtr())) {
        CallArgs.clear();
        CallArgs.push_back(E);
        CallArgs.push_back(placement);
        size_t arrSize
          = m_Context->getConstantArrayElementCount(constArray);
        Expr* arrSizeExpr
          = utils::Synthesize::IntegerLiteralExpr(*m_Context, arrSize);

        CallArgs.push_back(arrSizeExpr);
        // 2.1) arrays:
        // call copyArray(T* src, void* placement, size_t size)
        Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedCopyArray,
                                     locStart, CallArgs, locEnd);

      }
      else {
        if (!E->getSourceRange().isValid()) {
          // We cannot do CXXNewExpr::CallInit (see Sema::BuildCXXNew) but
          // that's what we want. Fail...
          return E;
        }
        TypeSourceInfo* ETSI
          = m_Context->getTrivialTypeSourceInfo(ETy, noLoc);

        Call = m_Sema->BuildCXXNew(E->getSourceRange(),
                                   /*useGlobal ::*/true,
                                   /*placementLParen*/ noLoc,
                                   MultiExprArg(placement),
                                   /*placementRParen*/ noLoc,
                                   /*TypeIdParens*/ SourceRange(),
                                   /*allocType*/ ETSI->getType(),
                                   /*allocTypeInfo*/ETSI,
                                   /*arraySize*/0,
                                   /*directInitRange*/E->getSourceRange(),
                                   /*initializer*/E,
                                   /*mayContainAuto*/false
                                   );
        // Handle possible cleanups:
        Call = m_Sema->ActOnFinishFullExpr(Call.get());
      }
    }
    else {
      // Mark the current number of arguemnts
      const size_t nArgs = CallArgs.size();
      if (desugaredTy->isIntegralOrEnumerationType()) {
        // 1)  enum, integral, float, double, referece, pointer types :
        //      call to cling::internal::setValueNoAlloc(...);

        // If the type is enum or integral we need to force-cast it into
        // uint64 in order to pick up the correct overload.
        if (desugaredTy->isIntegralOrEnumerationType()) {
          QualType UInt64Ty = m_Context->UnsignedLongLongTy;
          TypeSourceInfo* TSI
            = m_Context->getTrivialTypeSourceInfo(UInt64Ty, noLoc);
          Expr* castedE
            = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).get();
          CallArgs.push_back(castedE);
        }
      }
      else if (desugaredTy->isReferenceType()) {
        // we need to get the address of the references
        Expr* AddrOfE = m_Sema->BuildUnaryOp(/*Scope*/0, noLoc, UO_AddrOf,
                                             E).get();
        CallArgs.push_back(AddrOfE);
      }
      else if (desugaredTy->isAnyPointerType()) {
        // function pointers need explicit void* cast.
        QualType VoidPtrTy = m_Context->VoidPtrTy;
        TypeSourceInfo* TSI
          = m_Context->getTrivialTypeSourceInfo(VoidPtrTy, noLoc);
        Expr* castedE
          = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).get();
        CallArgs.push_back(castedE);
      }
      else if (desugaredTy->isNullPtrType()) {
        // nullptr should decay to void* just fine.
        CallArgs.push_back(E);
      }
      else if (desugaredTy->isFloatingType()) {
        // floats and double will fall naturally in the correct
        // case, because of the overload resolution.
        CallArgs.push_back(E);
      }

      // Test CallArgs.size to make sure an additional argument (the value)
      // has been pushed on, if not than we didn't know how to handle the type
      if (CallArgs.size() > nArgs) {
        Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc,
                                   locStart, CallArgs, locEnd);
      }
      else {
        m_Sema->Diag(locStart, diag::err_unsupported_unknown_any_decl) <<
          utils::TypeName::GetFullyQualifiedName(desugaredTy, *m_Context) <<
          SourceRange(locStart, locEnd);
      }
    }


    assert(!Call.isInvalid() && "Invalid Call");

    // Extend the scope of the temporary cleaner if applicable.
    if (Cleanups) {
      Cleanups->setSubExpr(Call.get());
      Cleanups->setValueKind(Call.get()->getValueKind());
      Cleanups->setType(Call.get()->getType());
      return Cleanups;
    }
    return Call.get();
  }
/// Propagate the nullability information through binds and warn when nullable
/// pointer or null symbol is assigned to a pointer with a nonnull type.
void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S,
                                   CheckerContext &C) const {
  const TypedValueRegion *TVR =
      dyn_cast_or_null<TypedValueRegion>(L.getAsRegion());
  if (!TVR)
    return;

  QualType LocType = TVR->getValueType();
  if (!LocType->isAnyPointerType())
    return;

  ProgramStateRef State = C.getState();
  if (State->get<InvariantViolated>())
    return;

  auto ValDefOrUnknown = V.getAs<DefinedOrUnknownSVal>();
  if (!ValDefOrUnknown)
    return;

  NullConstraint RhsNullness = getNullConstraint(*ValDefOrUnknown, State);

  Nullability ValNullability = Nullability::Unspecified;
  if (SymbolRef Sym = ValDefOrUnknown->getAsSymbol())
    ValNullability = getNullabilityAnnotation(Sym->getType());

  Nullability LocNullability = getNullabilityAnnotation(LocType);

  // If the type of the RHS expression is nonnull, don't warn. This
  // enables explicit suppression with a cast to nonnull.
  Nullability ValueExprTypeLevelNullability = Nullability::Unspecified;
  const Expr *ValueExpr = matchValueExprForBind(S);
  if (ValueExpr) {
    ValueExprTypeLevelNullability =
      getNullabilityAnnotation(lookThroughImplicitCasts(ValueExpr)->getType());
  }

  bool NullAssignedToNonNull = (LocNullability == Nullability::Nonnull &&
                                RhsNullness == NullConstraint::IsNull);
  if (Filter.CheckNullPassedToNonnull &&
      NullAssignedToNonNull &&
      ValNullability != Nullability::Nonnull &&
      ValueExprTypeLevelNullability != Nullability::Nonnull &&
      !isARCNilInitializedLocal(C, S)) {
    static CheckerProgramPointTag Tag(this, "NullPassedToNonnull");
    ExplodedNode *N = C.generateErrorNode(State, &Tag);
    if (!N)
      return;


    const Stmt *ValueStmt = S;
    if (ValueExpr)
      ValueStmt = ValueExpr;

    SmallString<256> SBuf;
    llvm::raw_svector_ostream OS(SBuf);
    OS << (LocType->isObjCObjectPointerType() ? "nil" : "Null");
    OS << " assigned to a pointer which is expected to have non-null value";
    reportBugIfInvariantHolds(OS.str(),
                              ErrorKind::NilAssignedToNonnull, N, nullptr, C,
                              ValueStmt);
    return;
  }

  // If null was returned from a non-null function, mark the nullability
  // invariant as violated even if the diagnostic was suppressed.
  if (NullAssignedToNonNull) {
    State = State->set<InvariantViolated>(true);
    C.addTransition(State);
    return;
  }

  // Intentionally missing case: '0' is bound to a reference. It is handled by
  // the DereferenceChecker.

  const MemRegion *ValueRegion = getTrackRegion(*ValDefOrUnknown);
  if (!ValueRegion)
    return;

  const NullabilityState *TrackedNullability =
      State->get<NullabilityMap>(ValueRegion);

  if (TrackedNullability) {
    if (RhsNullness == NullConstraint::IsNotNull ||
        TrackedNullability->getValue() != Nullability::Nullable)
      return;
    if (Filter.CheckNullablePassedToNonnull &&
        LocNullability == Nullability::Nonnull) {
      static CheckerProgramPointTag Tag(this, "NullablePassedToNonnull");
      ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
      reportBugIfInvariantHolds("Nullable pointer is assigned to a pointer "
                                "which is expected to have non-null value",
                                ErrorKind::NullableAssignedToNonnull, N,
                                ValueRegion, C);
    }
    return;
  }

  const auto *BinOp = dyn_cast<BinaryOperator>(S);

  if (ValNullability == Nullability::Nullable) {
    // Trust the static information of the value more than the static
    // information on the location.
    const Stmt *NullabilitySource = BinOp ? BinOp->getRHS() : S;
    State = State->set<NullabilityMap>(
        ValueRegion, NullabilityState(ValNullability, NullabilitySource));
    C.addTransition(State);
    return;
  }

  if (LocNullability == Nullability::Nullable) {
    const Stmt *NullabilitySource = BinOp ? BinOp->getLHS() : S;
    State = State->set<NullabilityMap>(
        ValueRegion, NullabilityState(LocNullability, NullabilitySource));
    C.addTransition(State);
  }
}
예제 #16
0
bool CodeGenTypes::isPointerZeroInitializable(QualType T) {
  assert((T->isAnyPointerType() || T->isBlockPointerType()) && "Invalid type");
  return isZeroInitializable(T);
}
예제 #17
0
  ASTNodeInfo EvaluateTSynthesizer::VisitDeclStmt(DeclStmt* Node) {
    // Visit all the children, which are the contents of the DeclGroupRef
    for (Stmt::child_iterator
           I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
      if (*I) {
        Expr* E = cast_or_null<Expr>(*I);
        if (!E || !IsArtificiallyDependent(E))
          continue;
        //FIXME: don't assume there is only one decl.
        assert(Node->isSingleDecl() && "There is more that one decl in stmt");
        VarDecl* CuredDecl = cast_or_null<VarDecl>(Node->getSingleDecl());
        assert(CuredDecl && "Not a variable declaration!");
        QualType CuredDeclTy = CuredDecl->getType();
        // check if the case is sometype * somevar = init;
        // or some_builtin_type somevar = init;
        if (CuredDecl->hasInit() && (CuredDeclTy->isAnyPointerType()
                                     || !CuredDeclTy->isRecordType())) {
          *I = SubstituteUnknownSymbol(CuredDeclTy, CuredDecl->getInit());
          continue;
        }

        // 1. Check whether this is the case of MyClass A(dep->symbol())
        // 2. Insert the RuntimeUniverse's LifetimeHandler instance
        // 3. Change the A's initializer to *(MyClass*)instance.getMemory()
        // 4. Make A reference (&A)
        // 5. Set the new initializer of A
        if (CuredDeclTy->isLValueReferenceType())
          continue;

        // Set Sema's Current DeclContext to the one we need
        DeclContext* OldDC = m_Sema->CurContext;
        m_Sema->CurContext = CuredDecl->getDeclContext();

        ASTNodeInfo NewNode;
        // 2.1 Get unique name for the LifetimeHandler instance and
        // initialize it
        std::string UniqueName;
        createUniqueName(UniqueName);
        IdentifierInfo& II = m_Context->Idents.get(UniqueName);

        // Prepare the initialization Exprs.
        // We want to call LifetimeHandler(DynamicExprInfo* ExprInfo,
        //                                 DeclContext DC,
        //                                 const char* type)
        //                                 Interpreter* interp)
        llvm::SmallVector<Expr*, 4> Inits;
        // Add MyClass in LifetimeHandler unique(DynamicExprInfo* ExprInfo
        //                                       DC,
        //                                       "MyClass"
        //                                       Interpreter* Interp)
        // Build Arg0 DynamicExprInfo
        Inits.push_back(BuildDynamicExprInfo(E));
        // Build Arg1 DeclContext* DC
        QualType DCTy = m_Context->getTypeDeclType(m_DeclContextDecl);
        Inits.push_back(utils::Synthesize::CStyleCastPtrExpr(m_Sema, DCTy,
                                                     (uint64_t)m_CurDeclContext)
                        );
        // Build Arg2 llvm::StringRef
        // Get the type of the type without specifiers
        PrintingPolicy Policy(m_Context->getLangOpts());
        Policy.SuppressTagKeyword = 1;
        std::string Res;
        CuredDeclTy.getAsStringInternal(Res, Policy);
        Inits.push_back(ConstructConstCharPtrExpr(Res.c_str()));

        // Build Arg3 cling::Interpreter
        CXXScopeSpec CXXSS;
        DeclarationNameInfo NameInfo(m_gCling->getDeclName(), 
                                     m_gCling->getLocStart());
        Expr* gClingDRE 
          = m_Sema->BuildDeclarationNameExpr(CXXSS, NameInfo ,m_gCling).take();
        Inits.push_back(gClingDRE);
        
        // 2.3 Create a variable from LifetimeHandler.
        QualType HandlerTy = m_Context->getTypeDeclType(m_LifetimeHandlerDecl);
        TypeSourceInfo* TSI = m_Context->getTrivialTypeSourceInfo(HandlerTy,
                                                                  m_NoSLoc);
        VarDecl* HandlerInstance = VarDecl::Create(*m_Context,
                                                   CuredDecl->getDeclContext(),
                                                   m_NoSLoc,
                                                   m_NoSLoc,
                                                   &II,
                                                   HandlerTy,
                                                   TSI,
                                                   SC_None);
        
        // 2.4 Call the best-match constructor. The method does overload
        // resolution of the constructors and then initializes the new
        // variable with it
        ExprResult InitExprResult
          = m_Sema->ActOnParenListExpr(m_NoSLoc,
                                       m_NoELoc,
                                       Inits);
        m_Sema->AddInitializerToDecl(HandlerInstance,
                                     InitExprResult.take(),
                                     /*DirectInit*/ true,
                                     /*TypeMayContainAuto*/ false);
        
        // 2.5 Register the instance in the enclosing context
        CuredDecl->getDeclContext()->addDecl(HandlerInstance);
        NewNode.addNode(new (m_Context)
                        DeclStmt(DeclGroupRef(HandlerInstance),
                                 m_NoSLoc,
                                 m_NoELoc)
                        );
        
        // 3.1 Build a DeclRefExpr, which holds the object
        DeclRefExpr* MemberExprBase
          = m_Sema->BuildDeclRefExpr(HandlerInstance,
                                     HandlerTy,
                                     VK_LValue,
                                     m_NoSLoc
                                     ).takeAs<DeclRefExpr>();
        // 3.2 Create a MemberExpr to getMemory from its declaration.
        CXXScopeSpec SS;
        LookupResult MemberLookup(*m_Sema, m_LHgetMemoryDecl->getDeclName(),
                                  m_NoSLoc, Sema::LookupMemberName);
        // Add the declaration as if doesn't exist.
        // TODO: Check whether this is the most appropriate variant
        MemberLookup.addDecl(m_LHgetMemoryDecl, AS_public);
        MemberLookup.resolveKind();
        Expr* MemberExpr = m_Sema->BuildMemberReferenceExpr(MemberExprBase,
                                                            HandlerTy,
                                                            m_NoSLoc,
                                                            /*IsArrow=*/false,
                                                            SS,
                                                            m_NoSLoc,
                                                     /*FirstQualifierInScope=*/0,
                                                            MemberLookup,
                                                            /*TemplateArgs=*/0
                                                            ).take();
        // 3.3 Build the actual call
        Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext);
        Expr* theCall = m_Sema->ActOnCallExpr(S,
                                              MemberExpr,
                                              m_NoSLoc,
                                              MultiExprArg(),
                                              m_NoELoc).take();
        // Cast to the type LHS type
        Expr* Result 
          = utils::Synthesize::CStyleCastPtrExpr(m_Sema, CuredDeclTy, theCall);
        // Cast once more (dereference the cstyle cast)
        Result = m_Sema->BuildUnaryOp(S, m_NoSLoc, UO_Deref, Result).take();
        // 4.
        CuredDecl->setType(m_Context->getLValueReferenceType(CuredDeclTy));
        // 5.
        CuredDecl->setInit(Result);

        NewNode.addNode(Node);

        // Restore Sema's original DeclContext
        m_Sema->CurContext = OldDC;
        return NewNode;
      }
    }
    return ASTNodeInfo(Node, 0);
  }
예제 #18
0
SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
                                  BinaryOperator::Opcode op,
                                  Loc lhs, NonLoc rhs, QualType resultTy) {
  
  // Special case: rhs is a zero constant.
  if (rhs.isZeroConstant())
    return lhs;
  
  // Special case: 'rhs' is an integer that has the same width as a pointer and
  // we are using the integer location in a comparison.  Normally this cannot be
  // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
  // can generate comparisons that trigger this code.
  // FIXME: Are all locations guaranteed to have pointer width?
  if (BinaryOperator::isComparisonOp(op)) {
    if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) {
      const llvm::APSInt *x = &rhsInt->getValue();
      ASTContext &ctx = Context;
      if (ctx.getTypeSize(ctx.VoidPtrTy) == x->getBitWidth()) {
        // Convert the signedness of the integer (if necessary).
        if (x->isSigned())
          x = &getBasicValueFactory().getValue(*x, true);

        return evalBinOpLL(state, op, lhs, loc::ConcreteInt(*x), resultTy);
      }
    }
    return UnknownVal();
  }
  
  // We are dealing with pointer arithmetic.

  // Handle pointer arithmetic on constant values.
  if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) {
    if (loc::ConcreteInt *lhsInt = dyn_cast<loc::ConcreteInt>(&lhs)) {
      const llvm::APSInt &leftI = lhsInt->getValue();
      assert(leftI.isUnsigned());
      llvm::APSInt rightI(rhsInt->getValue(), /* isUnsigned */ true);

      // Convert the bitwidth of rightI.  This should deal with overflow
      // since we are dealing with concrete values.
      rightI = rightI.extOrTrunc(leftI.getBitWidth());

      // Offset the increment by the pointer size.
      llvm::APSInt Multiplicand(rightI.getBitWidth(), /* isUnsigned */ true);
      rightI *= Multiplicand;
      
      // Compute the adjusted pointer.
      switch (op) {
        case BO_Add:
          rightI = leftI + rightI;
          break;
        case BO_Sub:
          rightI = leftI - rightI;
          break;
        default:
          llvm_unreachable("Invalid pointer arithmetic operation");
      }
      return loc::ConcreteInt(getBasicValueFactory().getValue(rightI));
    }
  }

  // Handle cases where 'lhs' is a region.
  if (const MemRegion *region = lhs.getAsRegion()) {
    rhs = cast<NonLoc>(convertToArrayIndex(rhs));
    SVal index = UnknownVal();
    const MemRegion *superR = 0;
    QualType elementType;

    if (const ElementRegion *elemReg = dyn_cast<ElementRegion>(region)) {
      assert(op == BO_Add || op == BO_Sub);
      index = evalBinOpNN(state, op, elemReg->getIndex(), rhs,
                          getArrayIndexType());
      superR = elemReg->getSuperRegion();
      elementType = elemReg->getElementType();
    }
    else if (isa<SubRegion>(region)) {
      superR = region;
      index = rhs;
      if (resultTy->isAnyPointerType())
        elementType = resultTy->getPointeeType();
    }

    if (NonLoc *indexV = dyn_cast<NonLoc>(&index)) {
      return loc::MemRegionVal(MemMgr.getElementRegion(elementType, *indexV,
                                                       superR, getContext()));
    }
  }
  return UnknownVal();  
}
예제 #19
0
/// Calculate the nullability of the result of a message expr based on the
/// nullability of the receiver, the nullability of the return value, and the
/// constraints.
void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M,
                                              CheckerContext &C) const {
  auto Decl = M.getDecl();
  if (!Decl)
    return;
  QualType RetType = Decl->getReturnType();
  if (!RetType->isAnyPointerType())
    return;

  ProgramStateRef State = C.getState();
  if (State->get<PreconditionViolated>())
    return;

  const MemRegion *ReturnRegion = getTrackRegion(M.getReturnValue());
  if (!ReturnRegion)
    return;

  auto Interface = Decl->getClassInterface();
  auto Name = Interface ? Interface->getName() : "";
  // In order to reduce the noise in the diagnostics generated by this checker,
  // some framework and programming style based heuristics are used. These
  // heuristics are for Cocoa APIs which have NS prefix.
  if (Name.startswith("NS")) {
    // Developers rely on dynamic invariants such as an item should be available
    // in a collection, or a collection is not empty often. Those invariants can
    // not be inferred by any static analysis tool. To not to bother the users
    // with too many false positives, every item retrieval function should be
    // ignored for collections. The instance methods of dictionaries in Cocoa
    // are either item retrieval related or not interesting nullability wise.
    // Using this fact, to keep the code easier to read just ignore the return
    // value of every instance method of dictionaries.
    if (M.isInstanceMessage() && Name.find("Dictionary") != StringRef::npos) {
      State =
          State->set<NullabilityMap>(ReturnRegion, Nullability::Contradicted);
      C.addTransition(State);
      return;
    }
    // For similar reasons ignore some methods of Cocoa arrays.
    StringRef FirstSelectorSlot = M.getSelector().getNameForSlot(0);
    if (Name.find("Array") != StringRef::npos &&
        (FirstSelectorSlot == "firstObject" ||
         FirstSelectorSlot == "lastObject")) {
      State =
          State->set<NullabilityMap>(ReturnRegion, Nullability::Contradicted);
      C.addTransition(State);
      return;
    }

    // Encoding related methods of string should not fail when lossless
    // encodings are used. Using lossless encodings is so frequent that ignoring
    // this class of methods reduced the emitted diagnostics by about 30% on
    // some projects (and all of that was false positives).
    if (Name.find("String") != StringRef::npos) {
      for (auto Param : M.parameters()) {
        if (Param->getName() == "encoding") {
          State = State->set<NullabilityMap>(ReturnRegion,
                                             Nullability::Contradicted);
          C.addTransition(State);
          return;
        }
      }
    }
  }

  const ObjCMessageExpr *Message = M.getOriginExpr();
  Nullability SelfNullability = getReceiverNullability(M, State);

  const NullabilityState *NullabilityOfReturn =
      State->get<NullabilityMap>(ReturnRegion);

  if (NullabilityOfReturn) {
    // When we have a nullability tracked for the return value, the nullability
    // of the expression will be the most nullable of the receiver and the
    // return value.
    Nullability RetValTracked = NullabilityOfReturn->getValue();
    Nullability ComputedNullab =
        getMostNullable(RetValTracked, SelfNullability);
    if (ComputedNullab != RetValTracked &&
        ComputedNullab != Nullability::Unspecified) {
      const Stmt *NullabilitySource =
          ComputedNullab == RetValTracked
              ? NullabilityOfReturn->getNullabilitySource()
              : Message->getInstanceReceiver();
      State = State->set<NullabilityMap>(
          ReturnRegion, NullabilityState(ComputedNullab, NullabilitySource));
      C.addTransition(State);
    }
    return;
  }

  // No tracked information. Use static type information for return value.
  Nullability RetNullability = getNullabilityAnnotation(RetType);

  // Properties might be computed. For this reason the static analyzer creates a
  // new symbol each time an unknown property  is read. To avoid false pozitives
  // do not treat unknown properties as nullable, even when they explicitly
  // marked nullable.
  if (M.getMessageKind() == OCM_PropertyAccess && !C.wasInlined)
    RetNullability = Nullability::Nonnull;

  Nullability ComputedNullab = getMostNullable(RetNullability, SelfNullability);
  if (ComputedNullab == Nullability::Nullable) {
    const Stmt *NullabilitySource = ComputedNullab == RetNullability
                                        ? Message
                                        : Message->getInstanceReceiver();
    State = State->set<NullabilityMap>(
        ReturnRegion, NullabilityState(ComputedNullab, NullabilitySource));
    C.addTransition(State);
  }
}
예제 #20
0
bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R,
                                               FieldChainInfo LocalChain) {
  assert(R->getValueType()->isRecordType() &&
         !R->getValueType()->isUnionType() &&
         "This method only checks non-union record objects!");

  const RecordDecl *RD =
      R->getValueType()->getAs<RecordType>()->getDecl()->getDefinition();
  assert(RD && "Referred record has no definition");

  bool ContainsUninitField = false;

  // Are all of this non-union's fields initialized?
  for (const FieldDecl *I : RD->fields()) {

    const auto FieldVal =
        State->getLValue(I, loc::MemRegionVal(R)).castAs<loc::MemRegionVal>();
    const auto *FR = FieldVal.getRegionAs<FieldRegion>();
    QualType T = I->getType();

    // If LocalChain already contains FR, then we encountered a cyclic
    // reference. In this case, region FR is already under checking at an
    // earlier node in the directed tree.
    if (LocalChain.contains(FR))
      return false;

    if (T->isStructureOrClassType()) {
      if (isNonUnionUninit(FR, LocalChain.add(RegularField(FR))))
        ContainsUninitField = true;
      continue;
    }

    if (T->isUnionType()) {
      if (isUnionUninit(FR)) {
        if (addFieldToUninits(LocalChain.add(RegularField(FR))))
          ContainsUninitField = true;
      } else
        IsAnyFieldInitialized = true;
      continue;
    }

    if (T->isArrayType()) {
      IsAnyFieldInitialized = true;
      continue;
    }

    if (T->isAnyPointerType() || T->isReferenceType() || T->isBlockPointerType()) {
      if (isPointerOrReferenceUninit(FR, LocalChain))
        ContainsUninitField = true;
      continue;
    }

    if (isPrimitiveType(T)) {
      SVal V = State->getSVal(FieldVal);

      if (isPrimitiveUninit(V)) {
        if (addFieldToUninits(LocalChain.add(RegularField(FR))))
          ContainsUninitField = true;
      }
      continue;
    }

    llvm_unreachable("All cases are handled!");
  }

  // Checking bases.
  // FIXME: As of now, because of `willObjectBeAnalyzedLater`, objects whose
  // type is a descendant of another type will emit warnings for uninitalized
  // inherited members.
  // This is not the only way to analyze bases of an object -- if we didn't
  // filter them out, and didn't analyze the bases, this checker would run for
  // each base of the object in order of base initailization and in theory would
  // find every uninitalized field. This approach could also make handling
  // diamond inheritances more easily.
  //
  // This rule (that a descendant type's cunstructor is responsible for
  // initializing inherited data members) is not obvious, and should it should
  // be.
  const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
  if (!CXXRD)
    return ContainsUninitField;

  for (const CXXBaseSpecifier &BaseSpec : CXXRD->bases()) {
    const auto *BaseRegion = State->getLValue(BaseSpec, R)
                                 .castAs<loc::MemRegionVal>()
                                 .getRegionAs<TypedValueRegion>();

    if (isNonUnionUninit(BaseRegion, LocalChain))
      ContainsUninitField = true;
  }

  return ContainsUninitField;
}