Skip to content

Commit 69a593f

Browse files
committed
[alpha.webkit.UncountedCallArgsChecker] Allow ASSERT and atomic<T> operations in a trivial function
This PR permits the use of WebKit's ASSERT macros as well as std::atomic<T> operations to appear within a trivial function. It also skips checkers on methods of Ref/RefPtr types.
1 parent 118a2a5 commit 69a593f

File tree

6 files changed

+81
-15
lines changed

6 files changed

+81
-15
lines changed

clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
2323
E = tempExpr->getSubExpr();
2424
continue;
2525
}
26+
if (auto *tempExpr = dyn_cast<CXXBindTemporaryExpr>(E)) {
27+
E = tempExpr->getSubExpr();
28+
continue;
29+
}
2630
if (auto *cast = dyn_cast<CastExpr>(E)) {
2731
if (StopAtFirstRefCountedObj) {
2832
if (auto *ConversionFunc =

clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ class TrivialFunctionAnalysisVisitor
315315
return false;
316316
}
317317

318+
bool VisitAtomicExpr(const AtomicExpr* E) {
319+
return VisitChildren(E);
320+
}
321+
318322
bool VisitStaticAssertDecl(const StaticAssertDecl *SAD) {
319323
// Any static_assert is considered trivial.
320324
return true;
@@ -330,12 +334,18 @@ class TrivialFunctionAnalysisVisitor
330334
const auto &Name = safeGetName(Callee);
331335

332336
if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" ||
337+
Name == "WTFReportAssertionFailure" ||
333338
Name == "compilerFenceForCrash" || Name == "__builtin_unreachable")
334339
return true;
335340

336341
return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache);
337342
}
338343

344+
bool VisitPredefinedExpr(const PredefinedExpr *E) {
345+
// A predefined identifier such as "func" is considered trivial.
346+
return true;
347+
}
348+
339349
bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE) {
340350
if (!checkArguments(MCE))
341351
return false;
@@ -356,6 +366,14 @@ class TrivialFunctionAnalysisVisitor
356366
return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache);
357367
}
358368

369+
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr* E) {
370+
if (auto *Expr = E->getExpr()) {
371+
if (!Visit(Expr))
372+
return false;
373+
}
374+
return true;
375+
}
376+
359377
bool checkArguments(const CallExpr *CE) {
360378
for (const Expr *Arg : CE->arguments()) {
361379
if (Arg && !Visit(Arg))

clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ class UncountedCallArgsChecker
5353
bool shouldVisitTemplateInstantiations() const { return true; }
5454
bool shouldVisitImplicitCode() const { return false; }
5555

56+
bool VisitCXXMethodDecl(const CXXMethodDecl *D) {
57+
if (auto* Class = D->getParent()) {
58+
auto name = safeGetName(Class);
59+
if (isRefCounted(Class))
60+
return false; // Don't visit contents of Ref/RefPtr methods.
61+
}
62+
return true;
63+
}
64+
5665
bool VisitCallExpr(const CallExpr *CE) {
5766
Checker->visitCallExpr(CE);
5867
return true;

clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55

66
class RefCounted {
77
public:
8-
void ref();
9-
void deref();
8+
void ref() const;
9+
void deref() const;
1010
};
1111

1212
class Object {
1313
public:
14+
void ref() const;
15+
void deref() const;
1416
void someFunction(RefCounted&);
1517
};
1618

clang/test/Analysis/Checkers/WebKit/mock-types.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@ template <typename T> struct Ref {
55
T *t;
66

77
Ref() : t{} {};
8-
Ref(T *) {}
8+
Ref(T &t)
9+
: t(t) {
10+
if (t)
11+
t->ref();
12+
}
13+
~Ref() {
14+
if (t)
15+
t->deref();
16+
}
917
T *get() { return t; }
1018
T *ptr() { return t; }
1119
operator const T &() const { return *t; }
@@ -16,7 +24,15 @@ template <typename T> struct RefPtr {
1624
T *t;
1725

1826
RefPtr() : t(new T) {}
19-
RefPtr(T *t) : t(t) {}
27+
RefPtr(T *t)
28+
: t(t) {
29+
if (t)
30+
t->ref();
31+
}
32+
~RefPtr() {
33+
if (t)
34+
t->deref();
35+
}
2036
T *get() { return t; }
2137
T *operator->() { return t; }
2238
const T *operator->() const { return t; }

clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
void WTFBreakpointTrap();
66
void WTFCrashWithInfo(int, const char*, const char*, int);
7+
void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion);
78

89
inline void compilerFenceForCrash()
910
{
@@ -31,21 +32,19 @@ void isIntegralOrPointerType(T, Types... types)
3132
CRASH_WITH_INFO(__VA_ARGS__); \
3233
} while (0)
3334

34-
#if !defined(NOT_TAIL_CALLED)
35-
#if __has_attribute(not_tail_called)
36-
#define NOT_TAIL_CALLED __attribute__((not_tail_called))
37-
#else
38-
#define NOT_TAIL_CALLED
39-
#endif
40-
#endif
41-
#define NO_RETURN_DUE_TO_CRASH
35+
#define ASSERT(assertion, ...) do { \
36+
if (!(assertion)) { \
37+
WTFReportAssertionFailure(__FILE__, __LINE__, __PRETTY_FUNCTION__, #assertion); \
38+
CRASH_WITH_INFO(__VA_ARGS__); \
39+
} \
40+
} while (0)
4241

4342
#if !defined(ALWAYS_INLINE)
4443
#define ALWAYS_INLINE inline
4544
#endif
4645

47-
NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfoImpl(int line, const char* file, const char* function, int counter, unsigned long reason);
48-
NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfo(int line, const char* file, const char* function, int counter);
46+
void WTFCrashWithInfoImpl(int line, const char* file, const char* function, int counter, unsigned long reason);
47+
void WTFCrashWithInfo(int line, const char* file, const char* function, int counter);
4948

5049
template<typename T>
5150
ALWAYS_INLINE unsigned long wtfCrashArg(T* arg) { return reinterpret_cast<unsigned long>(arg); }
@@ -54,7 +53,7 @@ template<typename T>
5453
ALWAYS_INLINE unsigned long wtfCrashArg(T arg) { return arg; }
5554

5655
template<typename T>
57-
NO_RETURN_DUE_TO_CRASH ALWAYS_INLINE void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, T reason)
56+
void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, T reason)
5857
{
5958
WTFCrashWithInfoImpl(line, file, function, counter, wtfCrashArg(reason));
6059
}
@@ -198,6 +197,8 @@ class RefCounted {
198197
bool trivial22() { return enumValue == Enum::Value1; }
199198

200199
bool trivial23() const { return OptionSet<Flags>::fromRaw(v).contains(Flags::Flag1); }
200+
int trivial24() const { ASSERT(v); return v; }
201+
unsigned trivial25() const { return __c11_atomic_load((volatile _Atomic(unsigned) *)&v, __ATOMIC_RELAXED); }
201202

202203
static RefCounted& singleton() {
203204
static RefCounted s_RefCounted;
@@ -256,6 +257,11 @@ class RefCounted {
256257
}
257258
}
258259

260+
static unsigned* another();
261+
unsigned nonTrivial10() const {
262+
return __c11_atomic_load((volatile _Atomic(unsigned) *)another(), __ATOMIC_RELAXED);
263+
}
264+
259265
unsigned v { 0 };
260266
Number* number { nullptr };
261267
Enum enumValue { Enum::Value1 };
@@ -301,6 +307,8 @@ class UnrelatedClass {
301307
getFieldTrivial().trivial21(); // no-warning
302308
getFieldTrivial().trivial22(); // no-warning
303309
getFieldTrivial().trivial23(); // no-warning
310+
getFieldTrivial().trivial24(); // no-warning
311+
getFieldTrivial().trivial25(); // no-warning
304312
RefCounted::singleton().trivial18(); // no-warning
305313
RefCounted::singleton().someFunction(); // no-warning
306314

@@ -324,6 +332,8 @@ class UnrelatedClass {
324332
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
325333
getFieldTrivial().nonTrivial9();
326334
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
335+
getFieldTrivial().nonTrivial10();
336+
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
327337
}
328338
};
329339

@@ -342,3 +352,10 @@ class UnrelatedClass2 {
342352
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
343353
}
344354
};
355+
356+
RefPtr<RefCounted> object();
357+
void someFunction(const RefCounted&);
358+
359+
void test() {
360+
someFunction(*object());
361+
}

0 commit comments

Comments
 (0)