PathDiagnosticPiece * ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, const bool tookTrue, BugReporterContext &BRC, const LocationContext *LC) { const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); if (!VD) return 0; llvm::SmallString<256> Buf; llvm::raw_svector_ostream Out(Buf); Out << "Assuming '"; VD->getDeclName().printName(Out); Out << "' is "; QualType VDTy = VD->getType(); if (VDTy->isPointerType()) Out << (tookTrue ? "non-null" : "null"); else if (VDTy->isObjCObjectPointerType()) Out << (tookTrue ? "non-nil" : "nil"); else if (VDTy->isScalarType()) Out << (tookTrue ? "not equal to 0" : "0"); else return 0; PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC); return new PathDiagnosticEventPiece(Loc, Out.str()); }
static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) { if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() && !vd->isExceptionVariable() && vd->getDeclContext() == dc) { QualType ty = vd->getType(); return ty->isScalarType() || ty->isVectorType(); } return false; }
bool SymbolManager::canSymbolicate(QualType T) { if (Loc::IsLocType(T)) return true; if (T->isIntegerType()) return T->isScalarType(); if (T->isRecordType()) return true; return false; }
bool ExprTypeAnalyser::checkExplicitCast(const ExplicitCastExpr* expr, QualType DestType, QualType SrcType) { // C99 6.5.4p2: the cast type needs to be void or scalar and the expression if (!DestType.isScalarType()) { // Dont allow any cast to non-scalar StringBuilder buf1(MAX_LEN_TYPENAME); StringBuilder buf2(MAX_LEN_TYPENAME); DestType.DiagName(buf1); SrcType.DiagName(buf2); Diags.Report(expr->getLocation(), diag::err_typecheck_cond_expect_scalar) << buf1 << buf2 << expr->getSourceRange(); return false; } // If either type is a pointer, the other type has to be either an // integer or a pointer // TODO decide if Enums are arithmatic types or not (they are in C99, not is C++0x) if (DestType.isPointerType()) { if (SrcType.isPointerType()) { // allow all pointer casts return true; } else { // only allow cast to pointer from uint32/64 (pointer size) const BuiltinType* BT = dyncast<BuiltinType>(SrcType.getCanonicalType()); // TODO use TargetInfo to check if 32-bit if (BT && BT->getKind() == BuiltinType::UInt64) return true; QualType expected = Type::UInt64(); StringBuilder buf1(MAX_LEN_TYPENAME); expected.DiagName(buf1); Diags.Report(expr->getLocation(), diag::err_cast_nonword_to_pointer) << buf1; } } else { if (SrcType.isPointerType()) { // only allow cast to uint32/64 (pointer size) const BuiltinType* BT = dyncast<BuiltinType>(DestType.getCanonicalType()); // TODO use TargetInfo to check if 32-bit if (BT && BT->getKind() == BuiltinType::UInt64) return true; QualType expected = Type::UInt64(); StringBuilder buf1(MAX_LEN_TYPENAME); expected.DiagName(buf1); Diags.Report(expr->getLocation(), diag::err_cast_pointer_to_nonword) << buf1; } else { // check non-pointer to non-pointer type // TODO make this top level function? (switch on src-type) return checkNonPointerCast(expr, DestType, SrcType); } } return false; }
bool SymbolManager::canSymbolicate(QualType T) { T = T.getCanonicalType(); if (Loc::isLocType(T)) return true; if (T->isIntegerType()) return T->isScalarType(); if (T->isRecordType() && !T->isUnionType()) return true; return false; }
PathDiagnosticPiece * ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, const bool tookTrue, BugReporterContext &BRC, BugReport &report, const ExplodedNode *N) { const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); if (!VD) return 0; SmallString<256> Buf; llvm::raw_svector_ostream Out(Buf); Out << "Assuming '"; VD->getDeclName().printName(Out); Out << "' is "; QualType VDTy = VD->getType(); if (VDTy->isPointerType()) Out << (tookTrue ? "non-null" : "null"); else if (VDTy->isObjCObjectPointerType()) Out << (tookTrue ? "non-nil" : "nil"); else if (VDTy->isScalarType()) Out << (tookTrue ? "not equal to 0" : "0"); else return 0; const LocationContext *LCtx = N->getLocationContext(); PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); PathDiagnosticEventPiece *event = new PathDiagnosticEventPiece(Loc, Out.str()); const ProgramState *state = N->getState().getPtr(); if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { if (report.isInteresting(R)) event->setPrunable(false); else { SVal V = state->getSVal(R); if (report.isInteresting(V)) event->setPrunable(false); } } return event; }
// Based on QualType::isTrivial. bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) { if (Type.isNull()) return false; if (Type->isArrayType()) return isTriviallyDefaultConstructible(Context.getBaseElementType(Type), Context); // Return false for incomplete types after skipping any incomplete array // types which are expressly allowed by the standard and thus our API. if (Type->isIncompleteType()) return false; if (Context.getLangOpts().ObjCAutoRefCount) { switch (Type.getObjCLifetime()) { case Qualifiers::OCL_ExplicitNone: return true; case Qualifiers::OCL_Strong: case Qualifiers::OCL_Weak: case Qualifiers::OCL_Autoreleasing: return false; case Qualifiers::OCL_None: if (Type->isObjCLifetimeType()) return false; break; } } QualType CanonicalType = Type.getCanonicalType(); if (CanonicalType->isDependentType()) return false; // As an extension, Clang treats vector types as Scalar types. if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; if (const auto *RT = CanonicalType->getAs<RecordType>()) { return recordIsTriviallyDefaultConstructible(*RT->getDecl(), Context); } // No other types can match. return false; }
SVal BasicStoreManager::LazyRetrieve(Store store, const TypedRegion *R) { const VarRegion *VR = dyn_cast<VarRegion>(R); if (!VR) return UnknownVal(); const VarDecl *VD = VR->getDecl(); QualType T = VD->getType(); // Only handle simple types that we can symbolicate. if (!SymbolManager::canSymbolicate(T) || !T->isScalarType()) return UnknownVal(); // Globals and parameters start with symbolic values. // Local variables initially are undefined. if (VR->hasGlobalsOrParametersStorage()) return ValMgr.getRegionValueSymbolVal(R); return UndefinedVal(); }
SVal ValueManager::getConjuredSymbolVal(const Expr* E, unsigned Count) { QualType T = E->getType(); SymbolRef sym = SymMgr.getConjuredSymbol(E, Count); // If T is of function pointer type, create a CodeTextRegion wrapping a // symbol. if (T->isFunctionPointerType()) { return Loc::MakeVal(MemMgr.getCodeTextRegion(sym, T)); } if (Loc::IsLocType(T)) return Loc::MakeVal(MemMgr.getSymbolicRegion(sym)); if (T->isIntegerType() && T->isScalarType()) return makeNonLoc(sym); return UnknownVal(); }
SVal ValueManager::getRegionValueSymbolVal(const MemRegion* R) { SymbolRef sym = SymMgr.getRegionValueSymbol(R); if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) { QualType T = TR->getValueType(SymMgr.getContext()); // If T is of function pointer type, create a CodeTextRegion wrapping a // symbol. if (T->isFunctionPointerType()) { return Loc::MakeVal(MemMgr.getCodeTextRegion(sym, T)); } if (Loc::IsLocType(T)) return Loc::MakeVal(MemMgr.getSymbolicRegion(sym)); // Only handle integers for now. if (T->isIntegerType() && T->isScalarType()) return makeNonLoc(sym); } return UnknownVal(); }
static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) { // Don't issue a fixit if there is already an initializer. if (VD->getInit()) return; // Suggest possible initialization (if any). const char *initialization = 0; QualType VariableTy = VD->getType().getCanonicalType(); if (VariableTy->isObjCObjectPointerType() || VariableTy->isBlockPointerType()) { // Check if 'nil' is defined. if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) initialization = " = nil"; else initialization = " = 0"; } else if (VariableTy->isRealFloatingType()) initialization = " = 0.0"; else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) initialization = " = false"; else if (VariableTy->isEnumeralType()) return; else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) { // Check if 'NULL' is defined. if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL"))) initialization = " = NULL"; else initialization = " = 0"; } else if (VariableTy->isScalarType()) initialization = " = 0"; if (initialization) { SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd()); S.Diag(loc, diag::note_var_fixit_add_initialization) << FixItHint::CreateInsertion(loc, initialization); } }
void GRSimpleVals::EvalCall(ExplodedNodeSet<GRState>& Dst, GRExprEngine& Eng, GRStmtNodeBuilder<GRState>& Builder, CallExpr* CE, SVal L, ExplodedNode<GRState>* Pred) { GRStateManager& StateMgr = Eng.getStateManager(); const GRState* St = Builder.GetState(Pred); // Invalidate all arguments passed in by reference (Locs). for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { SVal V = StateMgr.GetSVal(St, *I); if (isa<loc::MemRegionVal>(V)) St = StateMgr.BindLoc(St, cast<Loc>(V), UnknownVal()); else if (isa<nonloc::LocAsInteger>(V)) St = StateMgr.BindLoc(St, cast<nonloc::LocAsInteger>(V).getLoc(), UnknownVal()); } // Make up a symbol for the return value of this function. // FIXME: We eventually should handle structs and other compound types // that are returned by value. QualType T = CE->getType(); if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) { unsigned Count = Builder.getCurrentBlockCount(); SVal X = Eng.getValueManager().getConjuredSymbolVal(CE, Count); St = StateMgr.BindExpr(St, CE, X, Eng.getCFG().isBlkExpr(CE), false); } Builder.MakeNode(Dst, CE, Pred, St); }
bool SymbolManager::canSymbolicate(QualType T) { return Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType()); }