[analyzer][StreamChecker] Using function description objects - NFC.

Summary:
Have a description object for the stream functions
that can store different aspects of a single stream operation.

I plan to extend the structure with other members,
for example pre-callback and index of the stream argument.

Reviewers: Szelethus, baloghadamsoftware, NoQ, martong, Charusso, xazax.hun

Reviewed By: Szelethus

Subscribers: rnkovacs, xazax.hun, baloghadamsoftware, szepet, a.sidorin, mikhail.ramalho, Szelethus, donat.nagy, dkrupp, gamesh411, Charusso, martong, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D75158
This commit is contained in:
Balázs Kéri 2020-03-02 11:48:19 +01:00
parent 7a42babeb8
commit b293a7217b
1 changed files with 28 additions and 21 deletions

View File

@ -49,6 +49,15 @@ struct StreamState {
} }
}; };
class StreamChecker;
using FnCheck = std::function<void(const StreamChecker *, const CallEvent &,
CheckerContext &)>;
struct FnDescription {
FnCheck EvalFn;
};
class StreamChecker : public Checker<eval::Call, class StreamChecker : public Checker<eval::Call,
check::DeadSymbols > { check::DeadSymbols > {
mutable std::unique_ptr<BuiltinBug> BT_nullfp, BT_illegalwhence, mutable std::unique_ptr<BuiltinBug> BT_nullfp, BT_illegalwhence,
@ -59,35 +68,33 @@ public:
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
private: private:
using FnCheck = std::function<void(const StreamChecker *, const CallEvent &,
CheckerContext &)>;
CallDescriptionMap<FnCheck> Callbacks = { CallDescriptionMap<FnDescription> FnDescriptions = {
{{"fopen"}, &StreamChecker::evalFopen}, {{"fopen"}, {&StreamChecker::evalFopen}},
{{"freopen", 3}, &StreamChecker::evalFreopen}, {{"freopen", 3}, {&StreamChecker::evalFreopen}},
{{"tmpfile"}, &StreamChecker::evalFopen}, {{"tmpfile"}, {&StreamChecker::evalFopen}},
{{"fclose", 1}, &StreamChecker::evalFclose}, {{"fclose", 1}, {&StreamChecker::evalFclose}},
{{"fread", 4}, {{"fread", 4},
std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}, {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}},
{{"fwrite", 4}, {{"fwrite", 4},
std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}, {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}},
{{"fseek", 3}, &StreamChecker::evalFseek}, {{"fseek", 3}, {&StreamChecker::evalFseek}},
{{"ftell", 1}, {{"ftell", 1},
std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}},
{{"rewind", 1}, {{"rewind", 1},
std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}},
{{"fgetpos", 2}, {{"fgetpos", 2},
std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}},
{{"fsetpos", 2}, {{"fsetpos", 2},
std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}},
{{"clearerr", 1}, {{"clearerr", 1},
std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}},
{{"feof", 1}, {{"feof", 1},
std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}},
{{"ferror", 1}, {{"ferror", 1},
std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}},
{{"fileno", 1}, {{"fileno", 1},
std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}},
}; };
void evalFopen(const CallEvent &Call, CheckerContext &C) const; void evalFopen(const CallEvent &Call, CheckerContext &C) const;
@ -125,11 +132,11 @@ bool StreamChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
return false; return false;
} }
const FnCheck *Callback = Callbacks.lookup(Call); const FnDescription *Description = FnDescriptions.lookup(Call);
if (!Callback) if (!Description)
return false; return false;
(*Callback)(this, Call, C); (Description->EvalFn)(this, Call, C);
return C.isDifferent(); return C.isDifferent();
} }