void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE, CheckerContext &C) const { // FIXME: A callback should disable checkers at the start of functions. if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>( C.getCurrentAnalysisDeclContext()->getDecl()))) return; ProgramStateRef state = C.getState(); SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>(); if (!prevFlags) return; state = state->remove<PreCallSelfFlags>(); unsigned NumArgs = CE.getNumArgs(); for (unsigned i = 0; i < NumArgs; ++i) { SVal argV = CE.getArgSVal(i); if (isSelfVar(argV, C)) { // If the address of 'self' is being passed to the call, assume that the // 'self' after the call will have the same flags. // EX: log(&self) addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C); return; } else if (hasSelfFlag(argV, SelfFlag_Self, C)) { // If 'self' is passed to the call by value, assume that the function // returns 'self'. So assign the flags, which were set on 'self' to the // return value. // EX: self = performMoreInitialization(self) addSelfFlag(state, CE.getReturnValue(), prevFlags, C); return; } } C.addTransition(state); }
void DoubleFetchChecker::checkPostCall(const CallEvent &Call,CheckerContext &Ctx) const { const IdentifierInfo *ID = Call.getCalleeIdentifier(); std::cout<<"[checkPostCall]------call function:"<<ID->getName().str()<<std::endl; ProgramStateRef state = Ctx.getState(); if(ID == NULL) { return; } if (ID->getName() == "malloc") { SVal arg = Call.getArgSVal(0); SVal ret = Call.getReturnValue(); if (this->isTaintedByTime(state, arg)){ std::cout<<"[checkPostCall] arg of malloc is tainted."<<"\targ is:"<<toStr(arg)<<std::endl; //pass current taint tag to return value ProgramStateRef newstate = passTaints(state, arg, ret); if (newstate!=state && newstate != NULL){ Ctx.addTransition(newstate); std::cout<<"[checkPostCall][add ret Taint finish] ret is "<<toStr(ret)<<std::endl; showValTaintTags(newstate, ret); } else std::cout<<"[checkPostCall][add ret Taint failed] ret is "<<toStr(ret)<<std::endl; } else{ std::cout<<"[checkPostCall] arg of malloc not tainted."<<"\targ is:"<<toStr(arg)<<std::endl; } } }
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); }
/// 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); } }
void BlockInCriticalSectionChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { initIdentifierInfo(C.getASTContext()); if (!isBlockingFunction(Call) && !isLockFunction(Call) && !isUnlockFunction(Call)) return; ProgramStateRef State = C.getState(); unsigned mutexCount = State->get<MutexCounter>(); if (isUnlockFunction(Call) && mutexCount > 0) { State = State->set<MutexCounter>(--mutexCount); C.addTransition(State); } else if (isLockFunction(Call)) { State = State->set<MutexCounter>(++mutexCount); C.addTransition(State); } else if (mutexCount > 0) { SymbolRef BlockDesc = Call.getReturnValue().getAsSymbol(); reportBlockInCritSection(BlockDesc, Call, C); } }
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 IteratorChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { // Record new iterator positions and iterator position changes const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); if (!Func) return; if (Func->isOverloadedOperator()) { const auto Op = Func->getOverloadedOperator(); if (isSimpleComparisonOperator(Op)) { if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { handleComparison(C, Call.getReturnValue(), InstCall->getCXXThisVal(), Call.getArgSVal(0), Op); } else { handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0), Call.getArgSVal(1), Op); } } } else { const auto *OrigExpr = Call.getOriginExpr(); if (!OrigExpr) return; if (!isIteratorType(Call.getResultType())) return; auto State = C.getState(); // Already bound to container? if (getIteratorPosition(State, Call.getReturnValue())) return; if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { if (isEndCall(Func)) { handleEnd(C, OrigExpr, Call.getReturnValue(), InstCall->getCXXThisVal()); return; } } // Copy-like and move constructors if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) { if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) { State = setIteratorPosition(State, Call.getReturnValue(), *Pos); if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) { State = removeIteratorPosition(State, Call.getArgSVal(0)); } C.addTransition(State); return; } } // Assumption: if return value is an iterator which is not yet bound to a // container, then look for the first iterator argument, and // bind the return value to the same container. This approach // works for STL algorithms. // FIXME: Add a more conservative mode for (unsigned i = 0; i < Call.getNumArgs(); ++i) { if (isIteratorType(Call.getArgExpr(i)->getType())) { if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) { assignToContainer(C, OrigExpr, Call.getReturnValue(), Pos->getContainer()); return; } } } } }
void DynamicTypePropagation::checkPostCall(const CallEvent &Call, CheckerContext &C) const { // We can obtain perfect type info for return values from some calls. if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { // Get the returned value if it's a region. const MemRegion *RetReg = Call.getReturnValue().getAsRegion(); if (!RetReg) return; ProgramStateRef State = C.getState(); switch (Msg->getMethodFamily()) { default: break; // We assume that the type of the object returned by alloc and new are the // pointer to the object of the class specified in the receiver of the // message. case OMF_alloc: case OMF_new: { // Get the type of object that will get created. const ObjCMessageExpr *MsgE = Msg->getOriginExpr(); const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C); if (!ObjTy) return; QualType DynResTy = C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0)); C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false)); break; } case OMF_init: { // Assume, the result of the init method has the same dynamic type as // the receiver and propagate the dynamic type info. const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); if (!RecReg) return; DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg); C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType)); break; } } return; } if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { // We may need to undo the effects of our pre-call check. switch (Ctor->getOriginExpr()->getConstructionKind()) { case CXXConstructExpr::CK_Complete: case CXXConstructExpr::CK_Delegating: // No additional work necessary. // Note: This will leave behind the actual type of the object for // complete constructors, but arguably that's a good thing, since it // means the dynamic type info will be correct even for objects // constructed with operator new. return; case CXXConstructExpr::CK_NonVirtualBase: case CXXConstructExpr::CK_VirtualBase: if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) { // We just finished a base constructor. Now we can use the subclass's // type when resolving virtual calls. const Decl *D = C.getLocationContext()->getDecl(); recordFixedType(Target, cast<CXXConstructorDecl>(D), C); } return; } } }
void DoubleFetchChecker::checkPostCall(const CallEvent &Call,CheckerContext &Ctx) const { const IdentifierInfo *ID = Call.getCalleeIdentifier(); std::cout<<"\n"; std::cout<<"[checkPostCall]------call function:"<<ID->getName().str()<<std::endl; ProgramStateRef state = Ctx.getState(); if(ID == NULL) { return; } unsigned int curTime = this->getCurTime(state); /*everytime copy_from_user is invoked, *a new tainted is added to the taintList of the first Arg, *which is the fetched value in kernel */ if (ID->getName() == "copy_from_user"){ SVal Val0 = state->getSVal(Call.getArgExpr(0), Ctx.getLocationContext()); SVal origin = state->getSVal(Call.getArgExpr(1), Ctx.getLocationContext()); SVal len = state->getSVal(Call.getArgExpr(2), Ctx.getLocationContext()); std::cout<<"[checkPostCall]---> Val0: "<<toStr(Val0)<<std::endl; std::cout<<"[checkPostCall]---> origin: "<<toStr(origin)<<std::endl; std::cout<<"[checkPostCall]---> len: "<<toStr(len)<<std::endl; /* here has to use val1 as the origin, * since it is conveted from the actuall Expr */ state = this->addNewTaint(state, Val0, origin); /*after making change to time line, we need to increase the time */ state = this->increTime(state); std::cout<<"[checkPostCall] timer++"<<std::endl; if(state != NULL) Ctx.addTransition(state); } if (ID->getName() == "get_user" || ID->getName() =="__get_user"){ SVal arg0 = Call.getArgSVal(0); SVal arg1 = Call.getArgSVal(1); std::cout<<"--->arg0: "<<toStr(arg0)<<std::endl; std::cout<<"--->arg1: "<<toStr(arg1)<<std::endl; //const Expr* e0 = Call.getArgExpr(0); //const Expr* e1 =Call.getArgExpr(1); /* here has to use val1 as the origin, * since it is conveted from the actuall Expr */ state = this->addNewTaint(state, arg0, arg1); /*after making change to time line, we need to increase the time */ state = this->increTime(state); std::cout<<"[checkPostCall] timer++"<<std::endl; if(state != NULL) Ctx.addTransition(state); } if (ID->getName() == "malloc" || ID->getName() == "UserAllocPoolWithQuota") { int num = Call.getNumArgs(); SVal arg = Call.getArgSVal(0); SVal ret = Call.getReturnValue(); /*no need to check by time*/ if (this->isValTainted(state, arg)){ std::cout<<"[checkPostCall] arg of malloc is tainted."<<"\targ is:"<<toStr(arg)<<std::endl; //pass current taint taint to return value ProgramStateRef newstate = passTaints(state, arg, ret); if (newstate!=state && newstate != NULL){ Ctx.addTransition(newstate); std::cout<<"[checkPostCall]add ret Taint finish, ret is: "<<toStr(ret)<<std::endl; showValTaints(newstate, ret, "--->ret: "); } else std::cout<<"[checkPostCall] add ret Taint failed, ret is "<<toStr(ret)<<std::endl; } else{ std::cout<<"[checkPostCall] arg of malloc not tainted."<<"\targ is:"<<toStr(arg)<<std::endl; } } //int num = Call.getNumArgs(); //for(int i =0; i< num; i++){ if (ID->getName() == "CMSG_COMPAT_ALIGN") { SVal arg = Call.getArgSVal(0); SVal ret = Call.getReturnValue(); /*no need to check by time*/ if (this->isValTainted(state, arg)){ std::cout<<"[checkPostCall] arg of anyfunc is tainted."<<"\targ is:"<<toStr(arg)<<std::endl; //pass current taint taint to return value ProgramStateRef newstate = passTaints(state, arg, ret); if (newstate!=state && newstate != NULL){ Ctx.addTransition(newstate); std::cout<<"[checkPostCall]add ret Taint finish, ret is: "<<toStr(ret)<<std::endl; showValTaints(newstate, ret, "--->ret: "); return; } else std::cout<<"[checkPostCall] add ret Taint failed, ret is "<<toStr(ret)<<std::endl; } else{ std::cout<<"[checkPostCall] arg of anyfunc not tainted."<<"\targ is:"<<toStr(arg)<<std::endl; } } }