bool BlockInCriticalSectionChecker::isBlockingFunction(const CallEvent &Call) const { if (Call.isCalled(SleepFn) || Call.isCalled(GetcFn) || Call.isCalled(FgetsFn) || Call.isCalled(ReadFn) || Call.isCalled(RecvFn)) { return true; } return false; }
bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) const { if (const auto *Dtor = dyn_cast<CXXDestructorCall>(&Call)) { const auto *DRecordDecl = dyn_cast<CXXRecordDecl>(Dtor->getDecl()->getParent()); auto IdentifierInfo = DRecordDecl->getIdentifier(); if (IdentifierInfo == IILockGuard || IdentifierInfo == IIUniqueLock) return true; } if (Call.isCalled(UnlockFn) || Call.isCalled(PthreadUnlockFn) || Call.isCalled(MtxUnlock)) { return true; } return false; }
void SimpleStreamChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { if (!Call.isGlobalCFunction()) return; if (!Call.isCalled(CloseFn)) return; // Get the symbolic value corresponding to the file handle. SymbolRef FileDesc = Call.getArgSVal(0).getAsSymbol(); if (!FileDesc) return; // Check if the stream has already been closed. ProgramStateRef State = C.getState(); const StreamState *SS = State->get<StreamMap>(FileDesc); if (SS && SS->isClosed()) { reportDoubleClose(FileDesc, Call, C); return; } // Generate the next transition, in which the stream is closed. State = State->set<StreamMap>(FileDesc, StreamState::getClosed()); C.addTransition(State); }
void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { // TODO: Make this check part of CallDescription. if (!Call.isGlobalCFunction()) return; // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease. if (!(Call.isCalled(CFRetain) || Call.isCalled(CFRelease) || Call.isCalled(CFMakeCollectable) || Call.isCalled(CFAutorelease))) return; // Get the argument's value. SVal ArgVal = Call.getArgSVal(0); Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>(); if (!DefArgVal) return; // Is it null? ProgramStateRef state = C.getState(); ProgramStateRef stateNonNull, stateNull; std::tie(stateNonNull, stateNull) = state->assume(*DefArgVal); if (!stateNonNull) { ExplodedNode *N = C.generateErrorNode(stateNull); if (!N) return; SmallString<64> Str; raw_svector_ostream OS(Str); OS << "Null pointer argument in call to " << cast<FunctionDecl>(Call.getDecl())->getName(); auto report = llvm::make_unique<BugReport>(BT, OS.str(), N); report->addRange(Call.getArgSourceRange(0)); bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *report); C.emitReport(std::move(report)); return; } // From here on, we know the argument is non-null. C.addTransition(stateNonNull); }
void InnerPointerChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); if (const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) { // TODO: Do we need these to be typed? const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>( ICall->getCXXThisVal().getAsRegion()); if (!ObjRegion) return; if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) { SVal RawPtr = Call.getReturnValue(); if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) { // Start tracking this raw pointer by adding it to the set of symbols // associated with this container object in the program state map. PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>(); const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion); PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet(); assert(C.wasInlined || !Set.contains(Sym)); Set = F.add(Set, Sym); State = State->set<RawPtrMap>(ObjRegion, Set); C.addTransition(State); } return; } // Check [string.require] / second point. if (isInvalidatingMemberFunction(Call)) { markPtrSymbolsReleased(Call, State, ObjRegion, C); return; } } // Check [string.require] / first point. checkFunctionArguments(Call, State, C); }
void SimpleStreamChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { if (!Call.isGlobalCFunction()) return; if (!Call.isCalled(OpenFn)) return; // Get the symbolic value corresponding to the file handle. SymbolRef FileDesc = Call.getReturnValue().getAsSymbol(); if (!FileDesc) return; // Generate the next transition (an edge in the exploded graph). ProgramStateRef State = C.getState(); State = State->set<StreamMap>(FileDesc, StreamState::getOpened()); C.addTransition(State); }
bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const { if (const auto *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { auto IdentifierInfo = Ctor->getDecl()->getParent()->getIdentifier(); if (IdentifierInfo == IILockGuard || IdentifierInfo == IIUniqueLock) return true; } if (Call.isCalled(LockFn) || Call.isCalled(PthreadLockFn) || Call.isCalled(PthreadTryLockFn) || Call.isCalled(MtxLock) || Call.isCalled(MtxTimedLock) || Call.isCalled(MtxTryLock)) { return true; } return false; }
bool InnerPointerChecker::isInvalidatingMemberFunction( const CallEvent &Call) const { if (const auto *MemOpCall = dyn_cast<CXXMemberOperatorCall>(&Call)) { OverloadedOperatorKind Opc = MemOpCall->getOriginExpr()->getOperator(); if (Opc == OO_Equal || Opc == OO_PlusEqual) return true; return false; } return (isa<CXXDestructorCall>(Call) || Call.isCalled(AppendFn) || Call.isCalled(AssignFn) || Call.isCalled(ClearFn) || Call.isCalled(EraseFn) || Call.isCalled(InsertFn) || Call.isCalled(PopBackFn) || Call.isCalled(PushBackFn) || Call.isCalled(ReplaceFn) || Call.isCalled(ReserveFn) || Call.isCalled(ResizeFn) || Call.isCalled(ShrinkToFitFn) || Call.isCalled(SwapFn)); }