Skip to content

Commit fe3b20d

Browse files
authored
[analyzer] Use CDM::CLibrary instead of isGlobalCFunction() (#88267)
This commit updates several checkers to use call descriptions with the matching mode `CDM::CLibrary` instead of checking `Call.isGlobalCFunction()` after performing the match. This resolves several TODOs in various checkers. Note that both matching with `CDM::CLibrary` and calling `isGlobalCFunction` leads to `CheckerContext::isCLibraryFunction()` checks (so this change is close to being NFC), but if it is used via the matching mode then the checker can automatically recognize the builtin variants of the matched functions. I'll also make similar changes in GenericTaintChecker, but that checker has separate and inconsistent rules for handling the normal and the builtin variant of several functions (e.g. `memcpy` and `__builtin_memcpy`), so I'll put those changes into a separate commit.
1 parent def6174 commit fe3b20d

File tree

5 files changed

+130
-111
lines changed

5 files changed

+130
-111
lines changed

clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -542,10 +542,10 @@ namespace {
542542
class CFRetainReleaseChecker : public Checker<check::PreCall> {
543543
mutable APIMisuse BT{this, "null passed to CF memory management function"};
544544
const CallDescriptionSet ModelledCalls = {
545-
{{"CFRetain"}, 1},
546-
{{"CFRelease"}, 1},
547-
{{"CFMakeCollectable"}, 1},
548-
{{"CFAutorelease"}, 1},
545+
{CDM::CLibrary, {"CFRetain"}, 1},
546+
{CDM::CLibrary, {"CFRelease"}, 1},
547+
{CDM::CLibrary, {"CFMakeCollectable"}, 1},
548+
{CDM::CLibrary, {"CFAutorelease"}, 1},
549549
};
550550

551551
public:
@@ -555,10 +555,6 @@ class CFRetainReleaseChecker : public Checker<check::PreCall> {
555555

556556
void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
557557
CheckerContext &C) const {
558-
// TODO: Make this check part of CallDescription.
559-
if (!Call.isGlobalCFunction())
560-
return;
561-
562558
// Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
563559
if (!ModelledCalls.contains(Call))
564560
return;

clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp

Lines changed: 72 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -87,82 +87,115 @@ class PthreadLockChecker : public Checker<check::PostCall, check::DeadSymbols,
8787
CheckerKind CheckKind) const;
8888
CallDescriptionMap<FnCheck> PThreadCallbacks = {
8989
// Init.
90-
{{{"pthread_mutex_init"}, 2}, &PthreadLockChecker::InitAnyLock},
90+
{{CDM::CLibrary, {"pthread_mutex_init"}, 2},
91+
&PthreadLockChecker::InitAnyLock},
9192
// TODO: pthread_rwlock_init(2 arguments).
9293
// TODO: lck_mtx_init(3 arguments).
9394
// TODO: lck_mtx_alloc_init(2 arguments) => returns the mutex.
9495
// TODO: lck_rw_init(3 arguments).
9596
// TODO: lck_rw_alloc_init(2 arguments) => returns the mutex.
9697

9798
// Acquire.
98-
{{{"pthread_mutex_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
99-
{{{"pthread_rwlock_rdlock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
100-
{{{"pthread_rwlock_wrlock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
101-
{{{"lck_mtx_lock"}, 1}, &PthreadLockChecker::AcquireXNULock},
102-
{{{"lck_rw_lock_exclusive"}, 1}, &PthreadLockChecker::AcquireXNULock},
103-
{{{"lck_rw_lock_shared"}, 1}, &PthreadLockChecker::AcquireXNULock},
99+
{{CDM::CLibrary, {"pthread_mutex_lock"}, 1},
100+
&PthreadLockChecker::AcquirePthreadLock},
101+
{{CDM::CLibrary, {"pthread_rwlock_rdlock"}, 1},
102+
&PthreadLockChecker::AcquirePthreadLock},
103+
{{CDM::CLibrary, {"pthread_rwlock_wrlock"}, 1},
104+
&PthreadLockChecker::AcquirePthreadLock},
105+
{{CDM::CLibrary, {"lck_mtx_lock"}, 1},
106+
&PthreadLockChecker::AcquireXNULock},
107+
{{CDM::CLibrary, {"lck_rw_lock_exclusive"}, 1},
108+
&PthreadLockChecker::AcquireXNULock},
109+
{{CDM::CLibrary, {"lck_rw_lock_shared"}, 1},
110+
&PthreadLockChecker::AcquireXNULock},
104111

105112
// Try.
106-
{{{"pthread_mutex_trylock"}, 1}, &PthreadLockChecker::TryPthreadLock},
107-
{{{"pthread_rwlock_tryrdlock"}, 1}, &PthreadLockChecker::TryPthreadLock},
108-
{{{"pthread_rwlock_trywrlock"}, 1}, &PthreadLockChecker::TryPthreadLock},
109-
{{{"lck_mtx_try_lock"}, 1}, &PthreadLockChecker::TryXNULock},
110-
{{{"lck_rw_try_lock_exclusive"}, 1}, &PthreadLockChecker::TryXNULock},
111-
{{{"lck_rw_try_lock_shared"}, 1}, &PthreadLockChecker::TryXNULock},
113+
{{CDM::CLibrary, {"pthread_mutex_trylock"}, 1},
114+
&PthreadLockChecker::TryPthreadLock},
115+
{{CDM::CLibrary, {"pthread_rwlock_tryrdlock"}, 1},
116+
&PthreadLockChecker::TryPthreadLock},
117+
{{CDM::CLibrary, {"pthread_rwlock_trywrlock"}, 1},
118+
&PthreadLockChecker::TryPthreadLock},
119+
{{CDM::CLibrary, {"lck_mtx_try_lock"}, 1},
120+
&PthreadLockChecker::TryXNULock},
121+
{{CDM::CLibrary, {"lck_rw_try_lock_exclusive"}, 1},
122+
&PthreadLockChecker::TryXNULock},
123+
{{CDM::CLibrary, {"lck_rw_try_lock_shared"}, 1},
124+
&PthreadLockChecker::TryXNULock},
112125

113126
// Release.
114-
{{{"pthread_mutex_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
115-
{{{"pthread_rwlock_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
116-
{{{"lck_mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
117-
{{{"lck_rw_unlock_exclusive"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
118-
{{{"lck_rw_unlock_shared"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
119-
{{{"lck_rw_done"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
127+
{{CDM::CLibrary, {"pthread_mutex_unlock"}, 1},
128+
&PthreadLockChecker::ReleaseAnyLock},
129+
{{CDM::CLibrary, {"pthread_rwlock_unlock"}, 1},
130+
&PthreadLockChecker::ReleaseAnyLock},
131+
{{CDM::CLibrary, {"lck_mtx_unlock"}, 1},
132+
&PthreadLockChecker::ReleaseAnyLock},
133+
{{CDM::CLibrary, {"lck_rw_unlock_exclusive"}, 1},
134+
&PthreadLockChecker::ReleaseAnyLock},
135+
{{CDM::CLibrary, {"lck_rw_unlock_shared"}, 1},
136+
&PthreadLockChecker::ReleaseAnyLock},
137+
{{CDM::CLibrary, {"lck_rw_done"}, 1},
138+
&PthreadLockChecker::ReleaseAnyLock},
120139

121140
// Destroy.
122-
{{{"pthread_mutex_destroy"}, 1}, &PthreadLockChecker::DestroyPthreadLock},
123-
{{{"lck_mtx_destroy"}, 2}, &PthreadLockChecker::DestroyXNULock},
141+
{{CDM::CLibrary, {"pthread_mutex_destroy"}, 1},
142+
&PthreadLockChecker::DestroyPthreadLock},
143+
{{CDM::CLibrary, {"lck_mtx_destroy"}, 2},
144+
&PthreadLockChecker::DestroyXNULock},
124145
// TODO: pthread_rwlock_destroy(1 argument).
125146
// TODO: lck_rw_destroy(2 arguments).
126147
};
127148

128149
CallDescriptionMap<FnCheck> FuchsiaCallbacks = {
129150
// Init.
130-
{{{"spin_lock_init"}, 1}, &PthreadLockChecker::InitAnyLock},
151+
{{CDM::CLibrary, {"spin_lock_init"}, 1},
152+
&PthreadLockChecker::InitAnyLock},
131153

132154
// Acquire.
133-
{{{"spin_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
134-
{{{"spin_lock_save"}, 3}, &PthreadLockChecker::AcquirePthreadLock},
135-
{{{"sync_mutex_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
136-
{{{"sync_mutex_lock_with_waiter"}, 1},
155+
{{CDM::CLibrary, {"spin_lock"}, 1},
156+
&PthreadLockChecker::AcquirePthreadLock},
157+
{{CDM::CLibrary, {"spin_lock_save"}, 3},
158+
&PthreadLockChecker::AcquirePthreadLock},
159+
{{CDM::CLibrary, {"sync_mutex_lock"}, 1},
160+
&PthreadLockChecker::AcquirePthreadLock},
161+
{{CDM::CLibrary, {"sync_mutex_lock_with_waiter"}, 1},
137162
&PthreadLockChecker::AcquirePthreadLock},
138163

139164
// Try.
140-
{{{"spin_trylock"}, 1}, &PthreadLockChecker::TryFuchsiaLock},
141-
{{{"sync_mutex_trylock"}, 1}, &PthreadLockChecker::TryFuchsiaLock},
142-
{{{"sync_mutex_timedlock"}, 2}, &PthreadLockChecker::TryFuchsiaLock},
165+
{{CDM::CLibrary, {"spin_trylock"}, 1},
166+
&PthreadLockChecker::TryFuchsiaLock},
167+
{{CDM::CLibrary, {"sync_mutex_trylock"}, 1},
168+
&PthreadLockChecker::TryFuchsiaLock},
169+
{{CDM::CLibrary, {"sync_mutex_timedlock"}, 2},
170+
&PthreadLockChecker::TryFuchsiaLock},
143171

144172
// Release.
145-
{{{"spin_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
146-
{{{"spin_unlock_restore"}, 3}, &PthreadLockChecker::ReleaseAnyLock},
147-
{{{"sync_mutex_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
173+
{{CDM::CLibrary, {"spin_unlock"}, 1},
174+
&PthreadLockChecker::ReleaseAnyLock},
175+
{{CDM::CLibrary, {"spin_unlock_restore"}, 3},
176+
&PthreadLockChecker::ReleaseAnyLock},
177+
{{CDM::CLibrary, {"sync_mutex_unlock"}, 1},
178+
&PthreadLockChecker::ReleaseAnyLock},
148179
};
149180

150181
CallDescriptionMap<FnCheck> C11Callbacks = {
151182
// Init.
152-
{{{"mtx_init"}, 2}, &PthreadLockChecker::InitAnyLock},
183+
{{CDM::CLibrary, {"mtx_init"}, 2}, &PthreadLockChecker::InitAnyLock},
153184

154185
// Acquire.
155-
{{{"mtx_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
186+
{{CDM::CLibrary, {"mtx_lock"}, 1},
187+
&PthreadLockChecker::AcquirePthreadLock},
156188

157189
// Try.
158-
{{{"mtx_trylock"}, 1}, &PthreadLockChecker::TryC11Lock},
159-
{{{"mtx_timedlock"}, 2}, &PthreadLockChecker::TryC11Lock},
190+
{{CDM::CLibrary, {"mtx_trylock"}, 1}, &PthreadLockChecker::TryC11Lock},
191+
{{CDM::CLibrary, {"mtx_timedlock"}, 2}, &PthreadLockChecker::TryC11Lock},
160192

161193
// Release.
162-
{{{"mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
194+
{{CDM::CLibrary, {"mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
163195

164196
// Destroy
165-
{{{"mtx_destroy"}, 1}, &PthreadLockChecker::DestroyPthreadLock},
197+
{{CDM::CLibrary, {"mtx_destroy"}, 1},
198+
&PthreadLockChecker::DestroyPthreadLock},
166199
};
167200

168201
ProgramStateRef resolvePossiblyDestroyedMutex(ProgramStateRef state,
@@ -258,13 +291,9 @@ REGISTER_MAP_WITH_PROGRAMSTATE(DestroyRetVal, const MemRegion *, SymbolRef)
258291

259292
void PthreadLockChecker::checkPostCall(const CallEvent &Call,
260293
CheckerContext &C) const {
261-
// An additional umbrella check that all functions modeled by this checker
262-
// are global C functions.
263-
// TODO: Maybe make this the default behavior of CallDescription
264-
// with exactly one identifier?
265294
// FIXME: Try to handle cases when the implementation was inlined rather
266295
// than just giving up.
267-
if (!Call.isGlobalCFunction() || C.wasInlined)
296+
if (C.wasInlined)
268297
return;
269298

270299
if (const FnCheck *Callback = PThreadCallbacks.lookup(Call))

clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ class SimpleStreamChecker : public Checker<check::PostCall,
5252
check::PreCall,
5353
check::DeadSymbols,
5454
check::PointerEscape> {
55-
const CallDescription OpenFn{{"fopen"}, 2};
56-
const CallDescription CloseFn{{"fclose"}, 1};
55+
const CallDescription OpenFn{CDM::CLibrary, {"fopen"}, 2};
56+
const CallDescription CloseFn{CDM::CLibrary, {"fclose"}, 1};
5757

5858
const BugType DoubleCloseBugType{this, "Double fclose",
5959
"Unix Stream API Error"};
@@ -92,9 +92,6 @@ REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)
9292

9393
void SimpleStreamChecker::checkPostCall(const CallEvent &Call,
9494
CheckerContext &C) const {
95-
if (!Call.isGlobalCFunction())
96-
return;
97-
9895
if (!OpenFn.matches(Call))
9996
return;
10097

@@ -111,9 +108,6 @@ void SimpleStreamChecker::checkPostCall(const CallEvent &Call,
111108

112109
void SimpleStreamChecker::checkPreCall(const CallEvent &Call,
113110
CheckerContext &C) const {
114-
if (!Call.isGlobalCFunction())
115-
return;
116-
117111
if (!CloseFn.matches(Call))
118112
return;
119113

clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -302,85 +302,88 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
302302

303303
private:
304304
CallDescriptionMap<FnDescription> FnDescriptions = {
305-
{{{"fopen"}, 2}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
306-
{{{"fdopen"}, 2}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
307-
{{{"freopen"}, 3},
305+
{{CDM::CLibrary, {"fopen"}, 2},
306+
{nullptr, &StreamChecker::evalFopen, ArgNone}},
307+
{{CDM::CLibrary, {"fdopen"}, 2},
308+
{nullptr, &StreamChecker::evalFopen, ArgNone}},
309+
{{CDM::CLibrary, {"freopen"}, 3},
308310
{&StreamChecker::preFreopen, &StreamChecker::evalFreopen, 2}},
309-
{{{"tmpfile"}, 0}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
310-
{{{"fclose"}, 1},
311+
{{CDM::CLibrary, {"tmpfile"}, 0},
312+
{nullptr, &StreamChecker::evalFopen, ArgNone}},
313+
{{CDM::CLibrary, {"fclose"}, 1},
311314
{&StreamChecker::preDefault, &StreamChecker::evalFclose, 0}},
312-
{{{"fread"}, 4},
315+
{{CDM::CLibrary, {"fread"}, 4},
313316
{&StreamChecker::preRead,
314317
std::bind(&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, true), 3}},
315-
{{{"fwrite"}, 4},
318+
{{CDM::CLibrary, {"fwrite"}, 4},
316319
{&StreamChecker::preWrite,
317320
std::bind(&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, false), 3}},
318-
{{{"fgetc"}, 1},
321+
{{CDM::CLibrary, {"fgetc"}, 1},
319322
{&StreamChecker::preRead,
320323
std::bind(&StreamChecker::evalFgetx, _1, _2, _3, _4, true), 0}},
321-
{{{"fgets"}, 3},
324+
{{CDM::CLibrary, {"fgets"}, 3},
322325
{&StreamChecker::preRead,
323326
std::bind(&StreamChecker::evalFgetx, _1, _2, _3, _4, false), 2}},
324-
{{{"getc"}, 1},
327+
{{CDM::CLibrary, {"getc"}, 1},
325328
{&StreamChecker::preRead,
326329
std::bind(&StreamChecker::evalFgetx, _1, _2, _3, _4, true), 0}},
327-
{{{"fputc"}, 2},
330+
{{CDM::CLibrary, {"fputc"}, 2},
328331
{&StreamChecker::preWrite,
329332
std::bind(&StreamChecker::evalFputx, _1, _2, _3, _4, true), 1}},
330-
{{{"fputs"}, 2},
333+
{{CDM::CLibrary, {"fputs"}, 2},
331334
{&StreamChecker::preWrite,
332335
std::bind(&StreamChecker::evalFputx, _1, _2, _3, _4, false), 1}},
333-
{{{"putc"}, 2},
336+
{{CDM::CLibrary, {"putc"}, 2},
334337
{&StreamChecker::preWrite,
335338
std::bind(&StreamChecker::evalFputx, _1, _2, _3, _4, true), 1}},
336-
{{{"fprintf"}},
339+
{{CDM::CLibrary, {"fprintf"}},
337340
{&StreamChecker::preWrite,
338341
std::bind(&StreamChecker::evalFprintf, _1, _2, _3, _4), 0}},
339-
{{{"vfprintf"}, 3},
342+
{{CDM::CLibrary, {"vfprintf"}, 3},
340343
{&StreamChecker::preWrite,
341344
std::bind(&StreamChecker::evalFprintf, _1, _2, _3, _4), 0}},
342-
{{{"fscanf"}},
345+
{{CDM::CLibrary, {"fscanf"}},
343346
{&StreamChecker::preRead,
344347
std::bind(&StreamChecker::evalFscanf, _1, _2, _3, _4), 0}},
345-
{{{"vfscanf"}, 3},
348+
{{CDM::CLibrary, {"vfscanf"}, 3},
346349
{&StreamChecker::preRead,
347350
std::bind(&StreamChecker::evalFscanf, _1, _2, _3, _4), 0}},
348-
{{{"ungetc"}, 2},
351+
{{CDM::CLibrary, {"ungetc"}, 2},
349352
{&StreamChecker::preWrite,
350353
std::bind(&StreamChecker::evalUngetc, _1, _2, _3, _4), 1}},
351-
{{{"getdelim"}, 4},
354+
{{CDM::CLibrary, {"getdelim"}, 4},
352355
{&StreamChecker::preRead,
353356
std::bind(&StreamChecker::evalGetdelim, _1, _2, _3, _4), 3}},
354-
{{{"getline"}, 3},
357+
{{CDM::CLibrary, {"getline"}, 3},
355358
{&StreamChecker::preRead,
356359
std::bind(&StreamChecker::evalGetdelim, _1, _2, _3, _4), 2}},
357-
{{{"fseek"}, 3},
360+
{{CDM::CLibrary, {"fseek"}, 3},
358361
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
359-
{{{"fseeko"}, 3},
362+
{{CDM::CLibrary, {"fseeko"}, 3},
360363
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
361-
{{{"ftell"}, 1},
364+
{{CDM::CLibrary, {"ftell"}, 1},
362365
{&StreamChecker::preWrite, &StreamChecker::evalFtell, 0}},
363-
{{{"ftello"}, 1},
366+
{{CDM::CLibrary, {"ftello"}, 1},
364367
{&StreamChecker::preWrite, &StreamChecker::evalFtell, 0}},
365-
{{{"fflush"}, 1},
368+
{{CDM::CLibrary, {"fflush"}, 1},
366369
{&StreamChecker::preFflush, &StreamChecker::evalFflush, 0}},
367-
{{{"rewind"}, 1},
370+
{{CDM::CLibrary, {"rewind"}, 1},
368371
{&StreamChecker::preDefault, &StreamChecker::evalRewind, 0}},
369-
{{{"fgetpos"}, 2},
372+
{{CDM::CLibrary, {"fgetpos"}, 2},
370373
{&StreamChecker::preWrite, &StreamChecker::evalFgetpos, 0}},
371-
{{{"fsetpos"}, 2},
374+
{{CDM::CLibrary, {"fsetpos"}, 2},
372375
{&StreamChecker::preDefault, &StreamChecker::evalFsetpos, 0}},
373-
{{{"clearerr"}, 1},
376+
{{CDM::CLibrary, {"clearerr"}, 1},
374377
{&StreamChecker::preDefault, &StreamChecker::evalClearerr, 0}},
375-
{{{"feof"}, 1},
378+
{{CDM::CLibrary, {"feof"}, 1},
376379
{&StreamChecker::preDefault,
377380
std::bind(&StreamChecker::evalFeofFerror, _1, _2, _3, _4, ErrorFEof),
378381
0}},
379-
{{{"ferror"}, 1},
382+
{{CDM::CLibrary, {"ferror"}, 1},
380383
{&StreamChecker::preDefault,
381384
std::bind(&StreamChecker::evalFeofFerror, _1, _2, _3, _4, ErrorFError),
382385
0}},
383-
{{{"fileno"}, 1},
386+
{{CDM::CLibrary, {"fileno"}, 1},
384387
{&StreamChecker::preDefault, &StreamChecker::evalFileno, 0}},
385388
};
386389

@@ -540,8 +543,6 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
540543
const FnDescription *lookupFn(const CallEvent &Call) const {
541544
// Recognize "global C functions" with only integral or pointer arguments
542545
// (and matching name) as stream functions.
543-
if (!Call.isGlobalCFunction())
544-
return nullptr;
545546
for (auto *P : Call.parameters()) {
546547
QualType T = P->getType();
547548
if (!T->isIntegralOrEnumerationType() && !T->isPointerType() &&

0 commit comments

Comments
 (0)