class CallEvent;
class CallEventManager;
+/// This class represents a description of a function call using the number of
+/// arguments and the name of the function.
+class CallDescription {
+ friend CallEvent;
+ mutable IdentifierInfo *II;
+ StringRef FuncName;
+ unsigned RequiredArgs;
+
+public:
+ const static unsigned NoArgRequirement = ~0;
+ /// \brief Constructs a CallDescription object.
+ ///
+ /// @param FuncName The name of the function that will be matched.
+ ///
+ /// @param RequiredArgs The number of arguments that is expected to match a
+ /// call. Omit this parameter to match every occurance of call with a given
+ /// name regardless the number of arguments.
+ CallDescription(StringRef FuncName, unsigned RequiredArgs = NoArgRequirement)
+ : FuncName(FuncName), RequiredArgs(RequiredArgs) {}
+};
+
template<typename T = CallEvent>
class CallEventRef : public IntrusiveRefCntPtr<const T> {
public:
return false;
}
+ /// \brief Returns true if the CallEvent is a call to a function that matches
+ /// the CallDescription.
+ ///
+ /// Note that this function is not intended to be used to match Obj-C method
+ /// calls.
+ bool isCalled(const CallDescription &CD) const;
+
/// \brief Returns a source range for the entire call, suitable for
/// outputting in diagnostics.
virtual SourceRange getSourceRange() const {
check::PreCall,
check::DeadSymbols,
check::PointerEscape> {
-
- mutable IdentifierInfo *IIfopen, *IIfclose;
+ CallDescription OpenFn, CloseFn;
std::unique_ptr<BugType> DoubleCloseBugType;
std::unique_ptr<BugType> LeakBugType;
- void initIdentifierInfo(ASTContext &Ctx) const;
-
void reportDoubleClose(SymbolRef FileDescSym,
const CallEvent &Call,
CheckerContext &C) const;
} // end anonymous namespace
SimpleStreamChecker::SimpleStreamChecker()
- : IIfopen(nullptr), IIfclose(nullptr) {
+ : OpenFn("fopen"), CloseFn("fclose", 1) {
// Initialize the bug types.
DoubleCloseBugType.reset(
new BugType(this, "Double fclose", "Unix Stream API Error"));
void SimpleStreamChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
- initIdentifierInfo(C.getASTContext());
-
if (!Call.isGlobalCFunction())
return;
- if (Call.getCalleeIdentifier() != IIfopen)
+ if (!Call.isCalled(OpenFn))
return;
// Get the symbolic value corresponding to the file handle.
void SimpleStreamChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
- initIdentifierInfo(C.getASTContext());
-
if (!Call.isGlobalCFunction())
return;
- if (Call.getCalleeIdentifier() != IIfclose)
- return;
-
- if (Call.getNumArgs() != 1)
+ if (!Call.isCalled(CloseFn))
return;
// Get the symbolic value corresponding to the file handle.
return State;
}
-void SimpleStreamChecker::initIdentifierInfo(ASTContext &Ctx) const {
- if (IIfopen)
- return;
- IIfopen = &Ctx.Idents.get("fopen");
- IIfclose = &Ctx.Idents.get("fclose");
-}
-
void ento::registerSimpleStreamChecker(CheckerManager &mgr) {
mgr.registerChecker<SimpleStreamChecker>();
}
return PostImplicitCall(D, Loc, getLocationContext(), Tag);
}
+bool CallEvent::isCalled(const CallDescription &CD) const {
+ assert(getKind() != CE_ObjCMessage && "Obj-C methods are not supported");
+ if (!CD.II)
+ CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName);
+ if (getCalleeIdentifier() != CD.II)
+ return false;
+ return (CD.RequiredArgs == CallDescription::NoArgRequirement ||
+ CD.RequiredArgs == getNumArgs());
+}
+
SVal CallEvent::getArgSVal(unsigned Index) const {
const Expr *ArgE = getArgExpr(Index);
if (!ArgE)