static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr, ProgramStateRef State, CheckerContext &C) { SVal Val = State->getSVal(NonNullExpr, C.getLocationContext()); if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>()) return State->assume(*DV, true); return State; }
void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, const Stmt *StoreE, CheckerContext &C) const { if (!val.isUndef()) return; // Do not report assignments of uninitialized values inside swap functions. // This should allow to swap partially uninitialized structs // (radar://14129997) if (const FunctionDecl *EnclosingFunctionDecl = dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl())) if (C.getCalleeName(EnclosingFunctionDecl) == "swap") return; ExplodedNode *N = C.generateSink(); if (!N) return; const char *str = "Assigned value is garbage or undefined"; if (!BT) BT.reset(new BuiltinBug(str)); // Generate a report for this bug. const Expr *ex = 0; while (StoreE) { if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) { if (B->isCompoundAssignmentOp()) { ProgramStateRef state = C.getState(); if (state->getSVal(B->getLHS(), C.getLocationContext()).isUndef()) { str = "The left expression of the compound assignment is an " "uninitialized value. The computed value will also be garbage"; ex = B->getLHS(); break; } } ex = B->getRHS(); break; } if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) { const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); ex = VD->getInit(); } break; } BugReport *R = new BugReport(*BT, str, N); if (ex) { R->addRange(ex->getSourceRange()); bugreporter::trackNullOrUndefValue(N, ex, *R); } C.emitReport(R); }
void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { ProgramStateRef State = C.getState(); const FunctionDecl *FD = C.getCalleeDecl(CE); if (!FD || FD->getKind() != Decl::Function) return; StringRef funName = C.getCalleeName(FD); // If a value has been allocated, add it to the set for tracking. unsigned idx = getTrackedFunctionIndex(funName, true); if (idx == InvalidIdx) return; const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); // If the argument entered as an enclosing function parameter, skip it to // avoid false positives. if (isEnclosingFunctionParam(ArgExpr) && C.getLocationContext()->getParent() == 0) return; if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) { // If the argument points to something that's not a symbolic region, it // can be: // - unknown (cannot reason about it) // - undefined (already reported by other checker) // - constant (null - should not be tracked, // other constant will generate a compiler warning) // - goto (should be reported by other checker) // The call return value symbol should stay alive for as long as the // allocated value symbol, since our diagnostics depend on the value // returned by the call. Ex: Data should only be freed if noErr was // returned during allocation.) SymbolRef RetStatusSymbol = State->getSVal(CE, C.getLocationContext()).getAsSymbol(); C.getSymbolManager().addSymbolDependency(V, RetStatusSymbol); // Track the allocated value in the checker state. State = State->set<AllocatedData>(V, AllocationState(ArgExpr, idx, RetStatusSymbol)); assert(State); C.addTransition(State); } }
void DoubleFetchChecker::checkPreStmt(const Expr* E, CheckerContext &Ctx) const { ProgramStateRef state = Ctx.getState(); SVal ExpVal = state->getSVal(E, Ctx.getLocationContext()); SourceLocation L = E->getExprLoc(); }
/// \brief Returns true of the value of the expression is the object that 'self' /// points to and is an object that did not come from the result of calling /// an initializer. static bool isInvalidSelf(const Expr *E, CheckerContext &C) { SVal exprVal = C.getState()->getSVal(E, C.getLocationContext()); if (!hasSelfFlag(exprVal, SelfFlag_Self, C)) return false; // value did not come from 'self'. if (hasSelfFlag(exprVal, SelfFlag_InitRes, C)) return false; // 'self' is properly initialized. return true; }
void ObjCContainersChecker::addSizeInfo(const Expr *Array, const Expr *Size, CheckerContext &C) const { ProgramStateRef State = C.getState(); SVal SizeV = State->getSVal(Size, C.getLocationContext()); // Undefined is reported by another checker. if (SizeV.isUnknownOrUndef()) return; // Get the ArrayRef symbol. SVal ArrayRef = State->getSVal(Array, C.getLocationContext()); SymbolRef ArraySym = ArrayRef.getAsSymbol(); if (!ArraySym) return; C.addTransition( State->set<ArraySizeMap>(ArraySym, SizeV.castAs<DefinedSVal>())); return; }
void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { // Get the result type of the call. QualType expectedResultTy = CE->getType(); // Fetch the signature of the called function. const ProgramState *state = C.getState(); const LocationContext *LCtx = C.getLocationContext(); SVal V = state->getSVal(CE, LCtx); if (V.isUnknown()) return; // Casting to void? Discard the value. if (expectedResultTy->isVoidType()) { C.addTransition(state->BindExpr(CE, LCtx, UnknownVal())); return; } const MemRegion *callee = state->getSVal(CE->getCallee(), LCtx).getAsRegion(); if (!callee) return; QualType actualResultTy; if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) { const FunctionDecl *FD = FT->getDecl(); actualResultTy = FD->getResultType(); } else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) { const BlockTextRegion *BR = BD->getCodeRegion(); const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>(); const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>(); actualResultTy = FT->getResultType(); } // Can this happen? if (actualResultTy.isNull()) return; // For now, ignore references. if (actualResultTy->getAs<ReferenceType>()) return; // Are they the same? if (expectedResultTy != actualResultTy) { // FIXME: Do more checking and actual emit an error. At least performing // the cast avoids some assertion failures elsewhere. SValBuilder &svalBuilder = C.getSValBuilder(); V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy); C.addTransition(state->BindExpr(CE, LCtx, V)); } }
void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const { ProgramStateRef state = C.getState(); const LocationContext *LCtx = C.getLocationContext(); // FIXME: Handle 'super'? if (const Expr *receiver = msg.getInstanceReceiver()) { SVal recVal = state->getSVal(receiver, LCtx); if (recVal.isUndef()) { if (ExplodedNode *N = C.generateSink()) { BugType *BT = 0; if (msg.isPureMessageExpr()) { if (!BT_msg_undef) BT_msg_undef.reset(new BuiltinBug("Receiver in message expression " "is an uninitialized value")); BT = BT_msg_undef.get(); } else { if (!BT_objc_prop_undef) BT_objc_prop_undef.reset(new BuiltinBug("Property access on an " "uninitialized object pointer")); BT = BT_objc_prop_undef.get(); } BugReport *R = new BugReport(*BT, BT->getName(), N); R->addRange(receiver->getSourceRange()); R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, receiver, R)); C.EmitReport(R); } return; } else { // Bifurcate the state into nil and non-nil ones. DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal); ProgramStateRef notNilState, nilState; llvm::tie(notNilState, nilState) = state->assume(receiverVal); // Handle receiver must be nil. if (nilState && !notNilState) { HandleNilReceiver(C, state, msg); return; } } } const char *bugDesc = msg.isPropertySetter() ? "Argument for property setter is an uninitialized value" : "Argument in message expression is an uninitialized value"; // Check for any arguments that are uninitialized/undefined. PreVisitProcessArgs(C, CallOrObjCMessage(msg, state, LCtx), bugDesc, BT_msg_arg); }
/// 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); } }
void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const { ProgramStateRef state = C.getState(); const Expr *RetE = RS->getRetValue(); if (!RetE) return; SVal V = state->getSVal(RetE, C.getLocationContext()); const MemRegion *R = V.getAsRegion(); const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R); if (!ER) return; DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); // Zero index is always in bound, this also passes ElementRegions created for // pointer casts. if (Idx.isZeroConstant()) return; // FIXME: All of this out-of-bounds checking should eventually be refactored // into a common place. DefinedOrUnknownSVal NumElements = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), ER->getValueType()); ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { ExplodedNode *N = C.generateSink(StOutBound); if (!N) return; // FIXME: This bug correspond to CWE-466. Eventually we should have bug // types explicitly reference such exploit categories (when applicable). if (!BT) BT.reset(new BuiltinBug( this, "Return of pointer value outside of expected range", "Returned pointer value points outside the original object " "(potential buffer overflow)")); // FIXME: It would be nice to eventually make this diagnostic more clear, // e.g., by referencing the original declaration or by saying *why* this // reference is outside the range. // Generate a report for this bug. auto report = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N); report->addRange(RetE->getSourceRange()); C.emitReport(std::move(report)); } }
static ProgramStateRef assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State, const ObjCForCollectionStmt *FCS, bool Assumption) { if (!State) return nullptr; SymbolRef CollectionS = State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol(); return assumeCollectionNonEmpty(C, State, CollectionS, Assumption); }
void CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const { unsigned Indentation = 0; for (const LocationContext *LC = C.getLocationContext()->getParent(); LC != nullptr; LC = LC->getParent()) ++Indentation; // It is mildly evil to print directly to llvm::outs() rather than emitting // warnings, but this ensures things do not get filtered out by the rest of // the static analyzer machinery. llvm::outs().indent(Indentation); Call.dump(llvm::outs()); }
void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { const Expr *E = CE->getSubExpr(); ASTContext &Ctx = C.getASTContext(); QualType ToTy = Ctx.getCanonicalType(CE->getType()); const PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr()); if (!ToPTy) return; QualType ToPointeeTy = ToPTy->getPointeeType(); // Only perform the check if 'ToPointeeTy' is a complete type. if (ToPointeeTy->isIncompleteType()) return; ProgramStateRef state = C.getState(); const MemRegion *R = state->getSVal(E, C.getLocationContext()).getAsRegion(); if (!R) return; const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R); if (!SR) return; SValBuilder &svalBuilder = C.getSValBuilder(); SVal extent = SR->getExtent(svalBuilder); const llvm::APSInt *extentInt = svalBuilder.getKnownValue(state, extent); if (!extentInt) return; CharUnits regionSize = CharUnits::fromQuantity(extentInt->getSExtValue()); CharUnits typeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy); // Ignore void, and a few other un-sizeable types. if (typeSize.isZero()) return; if (regionSize % typeSize == 0) return; if (evenFlexibleArraySize(Ctx, regionSize, typeSize, ToPointeeTy)) return; if (ExplodedNode *errorNode = C.generateErrorNode()) { if (!BT) BT.reset(new BuiltinBug(this, "Cast region with wrong size.", "Cast a region whose size is not a multiple" " of the destination type size.")); auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), errorNode); R->addRange(CE->getSourceRange()); C.emitReport(std::move(R)); } }
void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const { const Expr *Ex = S->getSynchExpr(); ProgramStateRef state = C.getState(); SVal V = state->getSVal(Ex, C.getLocationContext()); // Uninitialized value used for the mutex? if (V.getAs<UndefinedVal>()) { if (ExplodedNode *N = C.generateSink()) { if (!BT_undef) BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex " "for @synchronized")); BugReport *report = new BugReport(*BT_undef, BT_undef->getDescription(), N); bugreporter::trackNullOrUndefValue(N, Ex, *report); C.emitReport(report); } return; } if (V.isUnknown()) return; // Check for null mutexes. ProgramStateRef notNullState, nullState; llvm::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>()); if (nullState) { if (!notNullState) { // Generate an error node. This isn't a sink since // a null mutex just means no synchronization occurs. if (ExplodedNode *N = C.addTransition(nullState)) { if (!BT_null) BT_null.reset(new BuiltinBug( this, "Nil value used as mutex for @synchronized() " "(no synchronization will occur)")); BugReport *report = new BugReport(*BT_null, BT_null->getDescription(), N); bugreporter::trackNullOrUndefValue(N, Ex, *report); C.emitReport(report); return; } } // Don't add a transition for 'nullState'. If the value is // under-constrained to be null or non-null, assume it is non-null // afterwards. } if (notNullState) C.addTransition(notNullState); }
/// If this is the beginning of -dealloc, mark the values initially stored in /// instance variables that must be released by the end of -dealloc /// as unreleased in the state. void ObjCDeallocChecker::checkBeginFunction( CheckerContext &C) const { initIdentifierInfoAndSelectors(C.getASTContext()); // Only do this if the current method is -dealloc. SVal SelfVal; if (!isInInstanceDealloc(C, SelfVal)) return; SymbolRef SelfSymbol = SelfVal.getAsSymbol(); const LocationContext *LCtx = C.getLocationContext(); ProgramStateRef InitialState = C.getState(); ProgramStateRef State = InitialState; SymbolSet::Factory &F = State->getStateManager().get_context<SymbolSet>(); // Symbols that must be released by the end of the -dealloc; SymbolSet RequiredReleases = F.getEmptySet(); // If we're an inlined -dealloc, we should add our symbols to the existing // set from our subclass. if (const SymbolSet *CurrSet = State->get<UnreleasedIvarMap>(SelfSymbol)) RequiredReleases = *CurrSet; for (auto *PropImpl : getContainingObjCImpl(LCtx)->property_impls()) { ReleaseRequirement Requirement = getDeallocReleaseRequirement(PropImpl); if (Requirement != ReleaseRequirement::MustRelease) continue; SVal LVal = State->getLValue(PropImpl->getPropertyIvarDecl(), SelfVal); Optional<Loc> LValLoc = LVal.getAs<Loc>(); if (!LValLoc) continue; SVal InitialVal = State->getSVal(LValLoc.getValue()); SymbolRef Symbol = InitialVal.getAsSymbol(); if (!Symbol || !isa<SymbolRegionValue>(Symbol)) continue; // Mark the value as requiring a release. RequiredReleases = F.add(RequiredReleases, Symbol); } if (!RequiredReleases.isEmpty()) { State = State->set<UnreleasedIvarMap>(SelfSymbol, RequiredReleases); } if (State != InitialState) { C.addTransition(State); } }
void IteratorChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE, CheckerContext &C) const { /* Transfer iterator state to temporary objects */ auto State = C.getState(); const auto *LCtx = C.getLocationContext(); const auto *Pos = getIteratorPosition(State, State->getSVal(MTE->GetTemporaryExpr(), LCtx)); if (!Pos) return; State = setIteratorPosition(State, State->getSVal(MTE, LCtx), *Pos); C.addTransition(State); }
/// Given the address expression, retrieve the value it's pointing to. Assume /// that value is itself an address, and return the corresponding symbol. static SymbolRef getAsPointeeSymbol(const Expr *Expr, CheckerContext &C) { const ProgramState *State = C.getState(); SVal ArgV = State->getSVal(Expr, C.getLocationContext()); if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&ArgV)) { StoreManager& SM = C.getStoreManager(); const MemRegion *V = SM.getBinding(State->getStore(), *X).getAsRegion(); if (V) return getSymbolForRegion(C, V); } return 0; }
/// Returns true if there is a call to -dealloc anywhere on the stack and false /// otherwise. If true, it also sets InstanceValOut to the value of /// 'self' in the frame for -dealloc. bool ObjCDeallocChecker::instanceDeallocIsOnStack(const CheckerContext &C, SVal &InstanceValOut) const { const LocationContext *LCtx = C.getLocationContext(); while (LCtx) { if (isInInstanceDealloc(C, LCtx, InstanceValOut)) return true; LCtx = LCtx->getParent(); } return false; }
/// Given the address expression, retrieve the value it's pointing to. Assume /// that value is itself an address, and return the corresponding symbol. static SymbolRef getAsPointeeSymbol(const Expr *Expr, CheckerContext &C) { ProgramStateRef State = C.getState(); SVal ArgV = State->getSVal(Expr, C.getLocationContext()); if (Optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) { StoreManager& SM = C.getStoreManager(); SymbolRef sym = SM.getBinding(State->getStore(), *X).getAsLocSymbol(); if (sym) return sym; } return 0; }
void DoubleFetchChecker::checkBind(SVal loc, SVal val,const Stmt *StoreE,CheckerContext &Ctx) const{ ProgramStateRef state = Ctx.getState(); std::cout<<"\n"; unsigned int bloc = Ctx.getSourceManager().getExpansionLineNumber(StoreE->getLocEnd()); std::cout<<"[checkBind] location: "<<bloc<<std::endl; const LocationContext *LC = Ctx.getLocationContext(); const Decl *D = LC->getAnalysisDeclContext()->getDecl(); const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); std::string funcName = FD->getNameAsString(); std::cout<<"[checkbind()]"<<" funcName is: "<<funcName<<std::endl; if(isValTainted(state,val)){ std::cout<<"[checkbind()] tainted"<<"\tlocation is: "<<toStr(loc)<<"\tbind value is: "<<toStr(val)<<std::endl; unsigned int curTime = this->getCurTime(state); TaintList *tl = this->getTaintList(state, val); if(tl != NULL) tl->showTaints("--->"); /* it is the value in loc that should be reference*/ SymbolRef sr = this->getSymbolRef(val); if (!sr){ std::cout<<"[checkbind()] SymbolRef failed!\n"; return; } /*update locationMap. * LocationMap, records when each local var is created. */ state = state->set<LocalVarAccessRecord>(sr,curTime); std::cout<<"--->add loc to LocalVarAccessRecord: SymbolRef is: "<<toStr(sr)<<"\t time is:"<<curTime<<std::endl; /*update timer of the checker, only when taint is passed to another expr */ state = this->increTime(state); /*update program state*/ Ctx.addTransition(state); } else std::cout<<"[checkbind()] untainted"<<"\tlocation is: "<<toStr(loc)<<"\tbind value is: "<<toStr(val)<<std::endl; }
void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, const Stmt *StoreE, CheckerContext &C) const { if (!val.isUndef()) return; ExplodedNode *N = C.generateSink(); if (!N) return; const char *str = "Assigned value is garbage or undefined"; if (!BT) BT.reset(new BuiltinBug(str)); // Generate a report for this bug. const Expr *ex = 0; while (StoreE) { if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) { if (B->isCompoundAssignmentOp()) { ProgramStateRef state = C.getState(); if (state->getSVal(B->getLHS(), C.getLocationContext()).isUndef()) { str = "The left expression of the compound assignment is an " "uninitialized value. The computed value will also be garbage"; ex = B->getLHS(); break; } } ex = B->getRHS(); break; } if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) { const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); ex = VD->getInit(); } break; } BugReport *R = new BugReport(*BT, str, N); if (ex) { R->addRange(ex->getSourceRange()); R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, ex, R)); } C.EmitReport(R); }
static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) { const StackFrameContext * SFC = C.getLocationContext()->getCurrentStackFrame(); if (Optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) { const MemRegion* R = X->getRegion(); if (const VarRegion *VR = R->getAs<VarRegion>()) if (const StackArgumentsSpaceRegion * stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getMemorySpace())) if (stackReg->getStackFrame() == SFC) return VR->getValueType(); } return QualType(); }
void UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE, CheckerContext &C) const { if (!BE->getBlockDecl()->hasCaptures()) return; ProgramStateRef state = C.getState(); const BlockDataRegion *R = cast<BlockDataRegion>(state->getSVal(BE, C.getLocationContext()).getAsRegion()); BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), E = R->referenced_vars_end(); for (; I != E; ++I) { // This VarRegion is the region associated with the block; we need // the one associated with the encompassing context. const VarRegion *VR = I.getCapturedRegion(); const VarDecl *VD = VR->getDecl(); if (VD->hasAttr<BlocksAttr>() || !VD->hasLocalStorage()) continue; // Get the VarRegion associated with VD in the local stack frame. if (Optional<UndefinedVal> V = state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) { if (ExplodedNode *N = C.generateSink()) { if (!BT) BT.reset( new BuiltinBug(this, "uninitialized variable captured by block")); // Generate a bug report. SmallString<128> buf; llvm::raw_svector_ostream os(buf); os << "Variable '" << VD->getName() << "' is uninitialized when captured by block"; BugReport *R = new BugReport(*BT, os.str(), N); if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD)) R->addRange(Ex->getSourceRange()); R->addVisitor(llvm::make_unique<FindLastStoreBRVisitor>( *V, VR, /*EnableNullFPSuppression*/ false)); R->disablePathPruning(); // need location of block C.emitReport(R); } } } }
// Handle operator calls. First, if it is operator=, check the argument, // and handle assigning and set target state appropriately. Otherwise, for // other operators, check the args for bad iterators and handle comparisons. void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE, CheckerContext &C) const { const LocationContext *LC = C.getLocationContext(); const ProgramState *state = C.getState(); OverloadedOperatorKind Kind = OCE->getOperator(); if (Kind == OO_Equal) { checkExpr(C, OCE->getArg(1)); state = handleAssign(state, OCE->getArg(0), OCE->getArg(1), LC); C.addTransition(state); return; } else { checkArgs(C, OCE); // If it is a compare and both are iterators, ensure that they are for // the same container. if (Kind == OO_EqualEqual || Kind == OO_ExclaimEqual || Kind == OO_Less || Kind == OO_LessEqual || Kind == OO_Greater || Kind == OO_GreaterEqual) { const MemRegion *MR0, *MR1; MR0 = getRegion(state, OCE->getArg(0), LC); if (!MR0) return; MR1 = getRegion(state, OCE->getArg(1), LC); if (!MR1) return; const RefState *RS0, *RS1; RS0 = state->get<IteratorState>(MR0); if (!RS0) return; RS1 = state->get<IteratorState>(MR1); if (!RS1) return; if (RS0->getMemRegion() != RS1->getMemRegion()) { if (ExplodedNode *N = C.addTransition()) { if (!BT_Incompatible) const_cast<IteratorsChecker*>(this)->BT_Incompatible = new BuiltinBug( "Cannot compare iterators from different containers"); BugReport *R = new BugReport(*BT_Incompatible, BT_Incompatible->getDescription(), N); R->addRange(OCE->getSourceRange()); C.EmitReport(R); } } } } }
void UndefResultChecker::checkPostStmt(const BinaryOperator *B, CheckerContext &C) const { const ProgramState *state = C.getState(); const LocationContext *LCtx = C.getLocationContext(); if (state->getSVal(B, LCtx).isUndef()) { // Generate an error node. ExplodedNode *N = C.generateSink(); if (!N) return; if (!BT) BT.reset(new BuiltinBug("Result of operation is garbage or undefined")); llvm::SmallString<256> sbuf; llvm::raw_svector_ostream OS(sbuf); const Expr *Ex = NULL; bool isLeft = true; if (state->getSVal(B->getLHS(), LCtx).isUndef()) { Ex = B->getLHS()->IgnoreParenCasts(); isLeft = true; } else if (state->getSVal(B->getRHS(), LCtx).isUndef()) { Ex = B->getRHS()->IgnoreParenCasts(); isLeft = false; } if (Ex) { OS << "The " << (isLeft ? "left" : "right") << " operand of '" << BinaryOperator::getOpcodeStr(B->getOpcode()) << "' is a garbage value"; } else { // Neither operand was undefined, but the result is undefined. OS << "The result of the '" << BinaryOperator::getOpcodeStr(B->getOpcode()) << "' expression is undefined"; } BugReport *report = new BugReport(*BT, OS.str(), N); if (Ex) { report->addRange(Ex->getSourceRange()); report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); } else report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, B)); C.EmitReport(report); } }
void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal, const MemRegion *Cont) const { while (const auto *CBOR = Cont->getAs<CXXBaseObjectRegion>()) { Cont = CBOR->getSuperRegion(); } auto State = C.getState(); auto &SymMgr = C.getSymbolManager(); auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(), C.getASTContext().LongTy, C.blockCount()); State = setIteratorPosition(State, RetVal, IteratorPosition::getPosition(Cont, Sym)); C.addTransition(State); }
void TaintTesterChecker::checkPostStmt(const Expr *E, CheckerContext &C) const { ProgramStateRef State = C.getState(); if (!State) return; if (State->isTainted(E, C.getLocationContext())) { if (ExplodedNode *N = C.generateNonFatalErrorNode()) { initBugType(); auto report = llvm::make_unique<BugReport>(*BT, "tainted",N); report->addRange(E->getSourceRange()); C.emitReport(std::move(report)); } } }
void TaintTesterChecker::checkPostStmt(const Expr *E, CheckerContext &C) const { ProgramStateRef State = C.getState(); if (!State) return; if (State->isTainted(E, C.getLocationContext())) { if (ExplodedNode *N = C.addTransition()) { initBugType(); BugReport *report = new BugReport(*BT, "tainted",N); report->addRange(E->getSourceRange()); C.emitReport(report); } } }
Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C, const Expr* Arg) { ProgramStateRef State = C.getState(); SVal AddrVal = State->getSVal(Arg->IgnoreParens(), C.getLocationContext()); if (AddrVal.isUnknownOrUndef()) return None; Optional<Loc> AddrLoc = AddrVal.getAs<Loc>(); if (!AddrLoc) return None; const PointerType *ArgTy = dyn_cast<PointerType>(Arg->getType().getCanonicalType().getTypePtr()); return State->getSVal(*AddrLoc, ArgTy ? ArgTy->getPointeeType(): QualType()); }
// If argument 0(protocol domain) is network, the return value should get taint. ProgramStateRef GenericTaintChecker::postSocket(const CallExpr *CE, CheckerContext &C) const { ProgramStateRef State = C.getState(); if (CE->getNumArgs() < 3) return State; SourceLocation DomLoc = CE->getArg(0)->getExprLoc(); StringRef DomName = C.getMacroNameOrSpelling(DomLoc); // White list the internal communication protocols. if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") || DomName.equals("AF_UNIX") || DomName.equals("AF_RESERVED_36")) return State; State = State->addTaint(CE, C.getLocationContext()); return State; }