void DoubleFetchChecker::checkPreStmt(const CallExpr *CE, CheckerContext &Ctx) const{ ProgramStateRef state = Ctx.getState(); const FunctionDecl *FDecl = Ctx.getCalleeDecl(CE); StringRef funcName = Ctx.getCalleeName(FDecl); //std::cout<<"[checkPreStmt<CallExpr>] func name is:"<<funcName.<<std::endl; //printf("[checkPreStmt<CallExpr>] func name is:%s\n",funcName); //std::cout<<"-------------------->getLocStart: "<<CE->getLocStart().getRawEncoding()<<std::endl; //std::cout<<"--------------------->getLocEnd: "<<CE->getLocEnd().getRawEncoding()<<std::endl; //std::cout<<"-------------------->getExprLoc: "<<CE->getExprLoc().getRawEncoding()<<std::endl; unsigned int spelling = Ctx.getSourceManager().getSpellingLineNumber(CE->getExprLoc()); unsigned int ex = Ctx.getSourceManager().getExpansionLineNumber(CE->getExprLoc()); }
std::unique_ptr<BugReport> MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport( const AllocationPair &AP, ExplodedNode *N, CheckerContext &C) const { const ADFunctionInfo &FI = FunctionsToTrack[AP.second->AllocatorIdx]; initBugType(); SmallString<70> sbuf; llvm::raw_svector_ostream os(sbuf); os << "Allocated data is not released: missing a call to '" << FunctionsToTrack[FI.DeallocatorIdx].Name << "'."; // Most bug reports are cached at the location where they occurred. // With leaks, we want to unique them by the location where they were // allocated, and only report a single path. PathDiagnosticLocation LocUsedForUniqueing; const ExplodedNode *AllocNode = getAllocationNode(N, AP.first, C); const Stmt *AllocStmt = nullptr; ProgramPoint P = AllocNode->getLocation(); if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>()) AllocStmt = Exit->getCalleeContext()->getCallSite(); else if (Optional<clang::PostStmt> PS = P.getAs<clang::PostStmt>()) AllocStmt = PS->getStmt(); if (AllocStmt) LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt, C.getSourceManager(), AllocNode->getLocationContext()); auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N, LocUsedForUniqueing, AllocNode->getLocationContext()->getDecl()); Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(AP.first)); markInteresting(Report.get(), AP); return Report; }
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 TraversalDumper::checkBranchCondition(const Stmt *Condition, CheckerContext &C) const { // Special-case Objective-C's for-in loop, which uses the entire loop as its // condition. We just print the collection expression. const Stmt *Parent = dyn_cast<ObjCForCollectionStmt>(Condition); if (!Parent) { const ParentMap &Parents = C.getLocationContext()->getParentMap(); Parent = Parents.getParent(Condition); } // 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. SourceLocation Loc = Parent->getLocStart(); llvm::outs() << C.getSourceManager().getSpellingLineNumber(Loc) << " " << Parent->getStmtClassName() << "\n"; }
void RefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) { const SourceManager& SMgr = Ctx.getSourceManager(); if (!sym->getOriginRegion()) return; auto *Region = dyn_cast<DeclRegion>(sym->getOriginRegion()); if (Region) { const Decl *PDecl = Region->getDecl(); if (PDecl && isa<ParmVarDecl>(PDecl)) { PathDiagnosticLocation ParamLocation = PathDiagnosticLocation::create(PDecl, SMgr); Location = ParamLocation; UniqueingLocation = ParamLocation; UniqueingDecl = Ctx.getLocationContext()->getDecl(); } } }
void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx, SymbolRef sym) { // Most bug reports are cached at the location where they occurred. // With leaks, we want to unique them by the location where they were // allocated, and only report a single path. To do this, we need to find // the allocation site of a piece of tracked memory, which we do via a // call to GetAllocationSite. This will walk the ExplodedGraph backwards. // Note that this is *not* the trimmed graph; we are guaranteed, however, // that all ancestor nodes that represent the allocation site have the // same SourceLocation. const ExplodedNode *AllocNode = nullptr; const SourceManager& SMgr = Ctx.getSourceManager(); AllocationInfo AllocI = GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym); AllocNode = AllocI.N; AllocBinding = AllocI.R; markInteresting(AllocI.InterestingMethodContext); // Get the SourceLocation for the allocation site. // FIXME: This will crash the analyzer if an allocation comes from an // implicit call (ex: a destructor call). // (Currently there are no such allocations in Cocoa, though.) AllocStmt = PathDiagnosticLocation::getStmt(AllocNode); if (!AllocStmt) { AllocBinding = nullptr; return; } PathDiagnosticLocation AllocLocation = PathDiagnosticLocation::createBegin(AllocStmt, SMgr, AllocNode->getLocationContext()); Location = AllocLocation; // Set uniqieing info, which will be used for unique the bug reports. The // leaks should be uniqued on the allocation site. UniqueingLocation = AllocLocation; UniqueingDecl = AllocNode->getLocationContext()->getDecl(); }
/// 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 StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE) const { ExplodedNode *N = C.generateSink(); if (!N) return; if (!BT_returnstack) BT_returnstack.reset( new BuiltinBug("Return of address to stack-allocated memory")); // Generate a report for this bug. SmallString<512> buf; llvm::raw_svector_ostream os(buf); SourceRange range = GenName(os, R, C.getSourceManager()); os << " returned to caller"; BugReport *report = new BugReport(*BT_returnstack, os.str(), N); report->addRange(RetE->getSourceRange()); if (range.isValid()) report->addRange(range); C.EmitReport(report); }
void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const { ProgramStateRef state = Ctx.getState(); // Iterate over all bindings to global variables and see if it contains // a memory region in the stack space. class CallBack : public StoreManager::BindingsHandler { private: CheckerContext &Ctx; const StackFrameContext *CurSFC; public: SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V; CallBack(CheckerContext &CC) : Ctx(CC), CurSFC(CC.getLocationContext()->getCurrentStackFrame()) {} bool HandleBinding(StoreManager &SMgr, Store store, const MemRegion *region, SVal val) { if (!isa<GlobalsSpaceRegion>(region->getMemorySpace())) return true; const MemRegion *vR = val.getAsRegion(); if (!vR) return true; // Under automated retain release, it is okay to assign a block // directly to a global variable. if (Ctx.getASTContext().getLangOpts().ObjCAutoRefCount && isa<BlockDataRegion>(vR)) return true; if (const StackSpaceRegion *SSR = dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) { // If the global variable holds a location in the current stack frame, // record the binding to emit a warning. if (SSR->getStackFrame() == CurSFC) V.push_back(std::make_pair(region, vR)); } return true; } }; CallBack cb(Ctx); state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb); if (cb.V.empty()) return; // Generate an error node. ExplodedNode *N = Ctx.addTransition(state); if (!N) return; if (!BT_stackleak) BT_stackleak.reset( new BuiltinBug("Stack address stored into global variable", "Stack address was saved into a global variable. " "This is dangerous because the address will become " "invalid after returning from the function")); for (unsigned i = 0, e = cb.V.size(); i != e; ++i) { // Generate a report for this bug. SmallString<512> buf; llvm::raw_svector_ostream os(buf); SourceRange range = GenName(os, cb.V[i].second, Ctx.getSourceManager()); os << " is still referred to by the global variable '"; const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion()); os << *VR->getDecl() << "' upon returning to the caller. This will be a dangling reference"; BugReport *report = new BugReport(*BT_stackleak, os.str(), N); if (range.isValid()) report->addRange(range); Ctx.EmitReport(report); } }
void DoubleFetchChecker::checkPreCall(const CallEvent &Call,CheckerContext &Ctx) const { const IdentifierInfo *ID = Call.getCalleeIdentifier(); ProgramStateRef state = Ctx.getState(); if (ID == NULL) { return; } std::cout<<"[checkPreCall]-----call function:"<<ID->getName().str()<<std::endl; if(ID->getName() == "kernel_func") { ProgramStateRef state = Ctx.getState(); SVal arg = Call.getArgSVal(0); const MemRegion* mr = arg.getAsRegion(); /* state = state->add<TaintRegionMap>(mr); Ctx.addTransition(state); SVal val = state->getSVal(mr); ProgramStateRef newstate = addTaintToSymExpr(state, val); if(newstate){ Ctx.addTransition(newstate); std::cout<<"[checkPreCall] arg add taint finish: "<<toStr(arg)<<std::endl; } else std::cout<<"[checkPreCall] arg add taint failed: "<<toStr(arg)<<std::endl; */ } if (ID->getName() == "__builtin___memcpy_chk") { SVal Arg0 = Call.getArgSVal(0); SVal Arg1 = Call.getArgSVal(1); SVal Arg2 = Call.getArgSVal(2); const Expr * erg0 = Call.getArgExpr(0); const Expr * erg1 = Call.getArgExpr(1); const Expr * erg2 = Call.getArgExpr(2); if(this->isTaintedByTime(state,Arg0)){ std::cout<<"[checkPreCall]"<<"\tArg0, tainted, \t "<<std::endl; showTaintByTime(state, Arg0); } else std::cout<<"[checkPreCall]"<<"\tArg0, not tainted, \t "<<std::endl; if(this->isTaintedByTime(state,Arg1)){ std::cout<<"[checkPreCall]"<<"\tArg1, tainted, \t "<<std::endl; showTaintByTime(state, Arg1); } else std::cout<<"[checkPreCall]"<<"\tArg1, not tainted, \t "<<std::endl; if(this->isTaintedByTime(state,Arg2)){ std::cout<<"[checkPreCall]"<<"\tArg2, tainted, \t "<<std::endl; showTaintByTime(state, Arg2); } else std::cout<<"[checkPreCall]"<<"\tArg2, not tainted, \t "<<std::endl; if(diffTaintInBranch(state,Arg0,erg0,Ctx.getSourceManager())){ llvm::errs() << "### Found DF1!!#####\n"; this->reportDoubleFetch(Ctx, Call); } if(diffTaintInBranch(state,Arg1,erg1,Ctx.getSourceManager())){ llvm::errs() << "### Found DF2!!#####\n"; this->reportDoubleFetch(Ctx, Call); } if(diffTaintInBranch(state,Arg2,erg2, Ctx.getSourceManager())){ llvm::errs() << "### Found DF3!!#####\n"; this->reportDoubleFetch(Ctx, Call); } } }
void DoubleFetchChecker::checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const { std::cout<<"\n"; unsigned int bloc = Ctx.getSourceManager().getExpansionLineNumber(Condition->getLocEnd()); std::cout<<"[checkBranch] location: "<<bloc<<std::endl; ProgramStateRef state = Ctx.getState(); SVal Val; const Expr *exp = dyn_cast<Expr>(Condition); //if is binary branchCondition if (const BinaryOperator *B = dyn_cast<BinaryOperator>(Condition)) { if (B->isComparisonOp()) { Expr * rp = B->getRHS(); Expr * lp = B->getLHS(); SVal rsval = state->getSVal(rp, Ctx.getLocationContext()); SVal lsval = state->getSVal(lp, Ctx.getLocationContext()); std::cout<<"[checkBranch]--rvalue : "<<toStr(rsval)<<std::endl; std::cout<<"[checkBranch]--lvalue : "<<toStr(lsval)<<std::endl; //std::cout<<"[checkBranch]--rvalue expr: \n"<<toStr(rp); //std::cout<<"[checkBranch]--lvalue expr: \n"<<toStr(lp); /*use isValTainted instead of isTaintedByTime(), * because we need to pass all the taints to the branch, * in the form of taintList */ std::cout<<"[checkBranch]--rvalue in binary cond\n"; if(this->isTaintedByTime(state,rsval)){ std::cout<<"[checkBranch]"<<"\ttainted, binary rsval is: "<<toStr(rsval)<<std::endl; showValTaints(state, rsval, "--->rsval"); state = this->passTaintsToBranch(state, rsval, exp); Ctx.addTransition(state); } else std::cout<<"[checkBranch] not tainted"<<"\tbinary rsval is: "<<toStr(rsval)<<std::endl; std::cout<<"[checkBranch]--lvalue in binary cond\n"; if(this->isTaintedByTime(state,lsval)){ std::cout<<"[checkBranch]"<<"\ttainted, binary lsval is: "<<toStr(lsval)<<std::endl; showValTaints(state, lsval, "--->lsval"); state = this->passTaintsToBranch(state, lsval, exp); Ctx.addTransition(state); } else std::cout<<"[checkBranch] not tainted"<<"\tbinary lsval is: "<<toStr(lsval)<<std::endl; } } //if is unary branchCondition else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(Condition)){ Expr* sp = U->getSubExpr(); SVal ssval = state->getSVal(sp, Ctx.getLocationContext()); std::cout<<"[checkBranch]-- in unary cond\n"; if(this->isTaintedByTime(state,ssval)){ std::cout<<"[checkBranch]"<<"\ttainted, unary ssval is: "; showValTaints(state, ssval, "--->ssval"); state = this->passTaintsToBranch(state, ssval, exp); Ctx.addTransition(state); } else std::cout<<"[checkBranch] not tainted"<<"\tunary ssval is: "<<toStr(ssval)<<std::endl; } else{ std::cout<<"[checkBranch]-- get branch failed\n"; } // two branches //ProgramStateRef trueState, falseState; //std::tie(trueState, falseState) = state->assume(dv); }
void DoubleFetchChecker::checkLocation( SVal loc, bool isLoad, const Stmt* LoadS, CheckerContext &Ctx) const{ std::cout<<"\n"; const LocationContext *LC = Ctx.getLocationContext(); const Decl *D = LC->getAnalysisDeclContext()->getDecl(); const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); std::string funcName = FD->getNameAsString(); unsigned int bloc = Ctx.getSourceManager().getExpansionLineNumber(LoadS->getLocEnd()); std::cout<<"[checkLocation] location: "<<bloc<<std::endl; if(funcName == "copy_from_user" || funcName == "get_user") return; ProgramStateRef state = Ctx.getState(); const MemRegion *mrptr = loc.getAsRegion(); if (!mrptr){ std::cout<<"[checkLocation] get MemRegion failed!\n"; return; } std::string locStr = mrptr->getString(); SVal val= state->getSVal(mrptr); unsigned int curTime = this->getCurTime(state); bool isTainted; std::cout<<"[checkLocation()]"<<" funcName is: "<<funcName<<std::endl; std::cout<<"[checkLocation()]"<<"\tlocation is: "<<toStr(loc)<<"\taccess value is: "<<toStr(val)<<"\t time is:"<<curTime<<std::endl; if (isLoad){ /* pass loc to this func, then convert as loc->memregion->val*/ if(this->isTaintedByTime(state, val)){ std::cout<<"[checkLocation()] val tainted"<<std::endl; isTainted = true; } else{ std::cout<<"[checkLocation()] val untainted, return"<<std::endl; isTainted = false; return; } /* pass val to this func, no convertion from loc to val*/ this->showValTaints(state, val, "------>all taints"); } else{ std::cout<<"[checkLocation()]"<<" write neglect...return\n"; return; } this->showLocationMap(state, "--->"); if(isTainted ){ /*if(AL.contains(locStr,funcName)){ std::cout<<"[checkLocation()] is accessing base region"<<std::endl; }else{ std::cout<<"[checkLocation()] is dereference"<<std::endl; }*/ if(diffTaintInBranch(state,val,LoadS,Ctx.getSourceManager())){ //unsigned int loc = Ctx.getSourceManager().getExpansionLineNumber(LoadS->getLocStart()); //std::cout<<"------> stmtloc is: "<<loc<<std::endl; std::cout << "### Found DF1!!#####\n"; //ExplodedNode *Node = Ctx.addTransition(state); this->reportDoubleFetch(Ctx, state); } } }
void UninitializedObjectChecker::checkEndFunction( const ReturnStmt *RS, CheckerContext &Context) const { const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>( Context.getLocationContext()->getDecl()); if (!CtorDecl) return; if (!CtorDecl->isUserProvided()) return; if (CtorDecl->getParent()->isUnion()) return; // This avoids essentially the same error being reported multiple times. if (willObjectBeAnalyzedLater(CtorDecl, Context)) return; Optional<nonloc::LazyCompoundVal> Object = getObjectVal(CtorDecl, Context); if (!Object) return; FindUninitializedFields F(Context.getState(), Object->getRegion(), CheckPointeeInitialization); const UninitFieldMap &UninitFields = F.getUninitFields(); if (UninitFields.empty()) return; // In non-pedantic mode, if Object's region doesn't contain a single // initialized field, we'll assume that Object was intentionally left // uninitialized. if (!IsPedantic && !F.isAnyFieldInitialized()) return; // There are uninitialized fields in the record. ExplodedNode *Node = Context.generateNonFatalErrorNode(Context.getState()); if (!Node) return; PathDiagnosticLocation LocUsedForUniqueing; const Stmt *CallSite = Context.getStackFrame()->getCallSite(); if (CallSite) LocUsedForUniqueing = PathDiagnosticLocation::createBegin( CallSite, Context.getSourceManager(), Node->getLocationContext()); // For Plist consumers that don't support notes just yet, we'll convert notes // to warnings. if (ShouldConvertNotesToWarnings) { for (const auto &Pair : UninitFields) { auto Report = llvm::make_unique<BugReport>( *BT_uninitField, Pair.second, Node, LocUsedForUniqueing, Node->getLocationContext()->getDecl()); Context.emitReport(std::move(Report)); } return; } SmallString<100> WarningBuf; llvm::raw_svector_ostream WarningOS(WarningBuf); WarningOS << UninitFields.size() << " uninitialized field" << (UninitFields.size() == 1 ? "" : "s") << " at the end of the constructor call"; auto Report = llvm::make_unique<BugReport>( *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing, Node->getLocationContext()->getDecl()); for (const auto &Pair : UninitFields) { Report->addNote(Pair.second, PathDiagnosticLocation::create(Pair.first->getDecl(), Context.getSourceManager())); } Context.emitReport(std::move(Report)); }