// Try to retrieve the function declaration and find the function parameter // types which are pointers/references to a non-pointer const. // We do not invalidate the corresponding argument regions. static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, const CallOrObjCMessage &Call) { const Decl *CallDecl = Call.getDecl(); if (!CallDecl) return; if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) { const IdentifierInfo *II = FDecl->getIdentifier(); // List the cases, where the region should be invalidated even if the // argument is const. if (II) { StringRef FName = II->getName(); // - 'int pthread_setspecific(ptheread_key k, const void *)' stores a // value into thread local storage. The value can later be retrieved with // 'void *ptheread_getspecific(pthread_key)'. So even thought the // parameter is 'const void *', the region escapes through the call. // - funopen - sets a buffer for future IO calls. // - ObjC functions that end with "NoCopy" can free memory, of the passed // in buffer. // - Many CF containers allow objects to escape through custom // allocators/deallocators upon container construction. // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can // be deallocated by NSMapRemove. // - Any call that has a callback as one of the arguments. if (FName == "pthread_setspecific" || FName == "funopen" || FName.endswith("NoCopy") || (FName.startswith("NS") && (FName.find("Insert") != StringRef::npos)) || Call.isCFCGAllowingEscape(FName) || Call.hasNonZeroCallbackArg()) return; } for (unsigned Idx = 0, E = Call.getNumArgs(); Idx != E; ++Idx) { if (FDecl && Idx < FDecl->getNumParams()) { if (isPointerToConst(FDecl->getParamDecl(Idx))) PreserveArgs.insert(Idx); } } return; } if (const ObjCMethodDecl *MDecl = dyn_cast<ObjCMethodDecl>(CallDecl)) { assert(MDecl->param_size() <= Call.getNumArgs()); unsigned Idx = 0; if (Call.hasNonZeroCallbackArg()) return; for (clang::ObjCMethodDecl::param_const_iterator I = MDecl->param_begin(), E = MDecl->param_end(); I != E; ++I, ++Idx) { if (isPointerToConst(*I)) PreserveArgs.insert(Idx); } return; } }
void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg, const char *BT_desc, OwningPtr<BugType> &BT) { // Don't check for uninitialized field values in arguments if the // caller has a body that is available and we have the chance to inline it. // This is a hack, but is a reasonable compromise betweens sometimes warning // and sometimes not depending on if we decide to inline a function. const Decl *D = callOrMsg.getDecl(); const bool checkUninitFields = !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody())); for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i) if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i), callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i), checkUninitFields, BT_desc, BT)) return; }