void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) { // Get the result type of the call. QualType expectedResultTy = CE->getType(); // Fetch the signature of the called function. const GRState *state = C.getState(); SVal V = state->getSVal(CE); if (V.isUnknown()) return; // Casting to void? Discard the value. if (expectedResultTy->isVoidType()) { C.GenerateNode(state->BindExpr(CE, UnknownVal())); return; } const MemRegion *callee = state->getSVal(CE->getCallee()).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(C.getASTContext())->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. SValuator &SVator = C.getSValuator(); V = SVator.EvalCast(V, expectedResultTy, actualResultTy); C.GenerateNode(state->BindExpr(CE, V)); } }
void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B) { // Using a fixed address is not portable because that address will probably // not be valid in all environments or platforms. if (B->getOpcode() != BinaryOperator::Assign) return; QualType T = B->getType(); if (!T->isPointerType()) return; const GRState *state = C.getState(); SVal RV = state->getSVal(B->getRHS()); if (!RV.isConstant() || RV.isZeroConstant()) return; if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Use fixed address", "Using a fixed address is not portable because that " "address will probably not be valid in all " "environments or platforms."); RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N); R->addRange(B->getRHS()->getSourceRange()); C.EmitReport(R); } }
void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME) { const IdentifierInfo *ClsName = ME->getClassName(); if (!ClsName) return; Selector S = ME->getSelector(); if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) return; if (!BT) BT = new APIMisuse("message incorrectly sent to class instead of class " "instance"); ExplodedNode *N = C.GenerateNode(); if (!N) return; llvm::SmallString<200> buf; llvm::raw_svector_ostream os(buf); os << "The '" << S.getAsString() << "' message should be sent to instances " "of class '" << ClsName->getName() << "' and not the class directly"; RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); report->addRange(ME->getSourceRange()); C.EmitReport(report); }
void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS) { const GRState *state = C.getState(); const Expr *RetE = RS->getRetValue(); if (!RetE) return; SVal V = state->getSVal(RetE); const MemRegion *R = V.getAsRegion(); if (!R) return; R = R->StripCasts(); if (!R) return; const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R); if (!ER) return; DefinedOrUnknownSVal &Idx = cast<DefinedOrUnknownSVal>(ER->getIndex()); // FIXME: All of this out-of-bounds checking should eventually be refactored // into a common place. DefinedOrUnknownSVal NumElements = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion()); const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { ExplodedNode *N = C.GenerateNode(RS, StOutBound, true); 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 = new BuiltinBug("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. RangedBugReport *report = new RangedBugReport(*BT, BT->getDescription(), N); report->addRange(RetE->getSourceRange()); C.EmitReport(report); } }
void CastToStructChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) { const Expr *E = CE->getSubExpr(); ASTContext &Ctx = C.getASTContext(); QualType OrigTy = Ctx.getCanonicalType(E->getType()); QualType ToTy = Ctx.getCanonicalType(CE->getType()); PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr()); PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr()); if (!ToPTy || !OrigPTy) return; QualType OrigPointeeTy = OrigPTy->getPointeeType(); QualType ToPointeeTy = ToPTy->getPointeeType(); if (!ToPointeeTy->isStructureOrClassType()) return; // We allow cast from void*. if (OrigPointeeTy->isVoidType()) return; // Now the cast-to-type is struct pointer, the original type is not void*. if (!OrigPointeeTy->isRecordType()) { if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Cast from non-struct type to struct type", "Casting a non-structure type to a structure type " "and accessing a field can lead to memory access " "errors or data corruption."); RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N); R->addRange(CE->getSourceRange()); C.EmitReport(R); } } }
bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE) { // Not enough arguments to match OSAtomicCompareAndSwap? if (CE->getNumArgs() != 3) return false; ASTContext &Ctx = C.getASTContext(); const Expr *oldValueExpr = CE->getArg(0); QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType()); const Expr *newValueExpr = CE->getArg(1); QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType()); // Do the types of 'oldValue' and 'newValue' match? if (oldValueType != newValueType) return false; const Expr *theValueExpr = CE->getArg(2); const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>(); // theValueType not a pointer? if (!theValueType) return false; QualType theValueTypePointee = Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType(); // The pointee must match newValueType and oldValueType. if (theValueTypePointee != newValueType) return false; static unsigned magic_load = 0; static unsigned magic_store = 0; const void *OSAtomicLoadTag = &magic_load; const void *OSAtomicStoreTag = &magic_store; // Load 'theValue'. GRExprEngine &Engine = C.getEngine(); const GRState *state = C.getState(); ExplodedNodeSet Tmp; SVal location = state->getSVal(theValueExpr); // Here we should use the value type of the region as the load type, because // we are simulating the semantics of the function, not the semantics of // passing argument. So the type of theValue expr is not we are loading. // But usually the type of the varregion is not the type we want either, // we still need to do a CastRetrievedVal in store manager. So actually this // LoadTy specifying can be omitted. But we put it here to emphasize the // semantics. QualType LoadTy; if (const TypedRegion *TR = dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { LoadTy = TR->getValueType(); } Engine.EvalLoad(Tmp, theValueExpr, C.getPredecessor(), state, location, OSAtomicLoadTag, LoadTy); if (Tmp.empty()) { // If no nodes were generated, other checkers must generated sinks. But // since the builder state was restored, we set it manually to prevent // auto transition. // FIXME: there should be a better approach. C.getNodeBuilder().BuildSinks = true; return true; } for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { ExplodedNode *N = *I; const GRState *stateLoad = N->getState(); SVal theValueVal_untested = stateLoad->getSVal(theValueExpr); SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr); // FIXME: Issue an error. if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) { return false; } DefinedOrUnknownSVal theValueVal = cast<DefinedOrUnknownSVal>(theValueVal_untested); DefinedOrUnknownSVal oldValueVal = cast<DefinedOrUnknownSVal>(oldValueVal_untested); SValuator &SVator = Engine.getSValuator(); // Perform the comparison. DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad,theValueVal,oldValueVal); const GRState *stateEqual = stateLoad->Assume(Cmp, true); // Were they equal? if (stateEqual) { // Perform the store. ExplodedNodeSet TmpStore; SVal val = stateEqual->getSVal(newValueExpr); // Handle implicit value casts. if (const TypedRegion *R = dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { val = SVator.EvalCast(val,R->getValueType(), newValueExpr->getType()); } Engine.EvalStore(TmpStore, NULL, theValueExpr, N, stateEqual, location, val, OSAtomicStoreTag); if (TmpStore.empty()) { // If no nodes were generated, other checkers must generated sinks. But // since the builder state was restored, we set it manually to prevent // auto transition. // FIXME: there should be a better approach. C.getNodeBuilder().BuildSinks = true; return true; } // Now bind the result of the comparison. for (ExplodedNodeSet::iterator I2 = TmpStore.begin(), E2 = TmpStore.end(); I2 != E2; ++I2) { ExplodedNode *predNew = *I2; const GRState *stateNew = predNew->getState(); // Check for 'void' return type if we have a bogus function prototype. SVal Res = UnknownVal(); QualType T = CE->getType(); if (!T->isVoidType()) Res = Engine.getValueManager().makeTruthVal(true, T); C.GenerateNode(stateNew->BindExpr(CE, Res), predNew); } } // Were they not equal? if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) { // Check for 'void' return type if we have a bogus function prototype. SVal Res = UnknownVal(); QualType T = CE->getType(); if (!T->isVoidType()) Res = Engine.getValueManager().makeTruthVal(false, CE->getType()); C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N); } } return true; }
void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { const GRState *state = C.getState(); const GRState *originalState = state; // Check if the callee has a 'nonnull' attribute. SVal X = state->getSVal(CE->getCallee()); const FunctionDecl* FD = X.getAsFunctionDecl(); if (!FD) return; const NonNullAttr* Att = FD->getAttr<NonNullAttr>(); if (!Att) return; // Iterate through the arguments of CE and check them for null. unsigned idx = 0; for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E; ++I, ++idx) { if (!Att->isNonNull(idx)) continue; const SVal &V = state->getSVal(*I); const DefinedSVal *DV = dyn_cast<DefinedSVal>(&V); if (!DV) continue; ConstraintManager &CM = C.getConstraintManager(); const GRState *stateNotNull, *stateNull; llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV); if (stateNull && !stateNotNull) { // Generate an error node. Check for a null node in case // we cache out. if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) { // Lazily allocate the BugType object if it hasn't already been // created. Ownership is transferred to the BugReporter object once // the BugReport is passed to 'EmitWarning'. if (!BT) BT = new BugType("Argument with 'nonnull' attribute passed null", "API"); EnhancedBugReport *R = new EnhancedBugReport(*BT, "Null pointer passed as an argument to a " "'nonnull' parameter", errorNode); // Highlight the range of the argument that was null. const Expr *arg = *I; R->addRange(arg->getSourceRange()); R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg); // Emit the bug report. C.EmitReport(R); } // Always return. Either we cached out or we just emitted an error. return; } // If a pointer value passed the check we should assume that it is // indeed not null from this point forward. assert(stateNotNull); state = stateNotNull; } // If we reach here all of the arguments passed the nonnull check. // If 'state' has been updated generated a new node. if (state != originalState) C.addTransition(C.GenerateNode(CE, state)); }