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); }
/// 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); } }
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; }
static bool isPointerToConst(const ParmVarDecl *ParamDecl) { QualType PointeeTy = ParamDecl->getOriginalType()->getPointeeType(); if (PointeeTy != QualType() && PointeeTy.isConstQualified() && !PointeeTy->isAnyPointerType() && !PointeeTy->isReferenceType()) { return true; } return false; }
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" } }
/// \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; }
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; }
/// 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); } }
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; }
static bool isPointerToConst(const QualType &QT) { return QT->isAnyPointerType() && QT->getPointeeType().isConstQualified(); }
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(); }
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(); }
/// 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); } }
bool CodeGenTypes::isPointerZeroInitializable(QualType T) { assert((T->isAnyPointerType() || T->isBlockPointerType()) && "Invalid type"); return isZeroInitializable(T); }
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); }
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(); }
/// 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); } }
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; }