Skip to content

Commit c3b87a8

Browse files
authored
[alpha.webkit.UncountedCallArgsChecker] Allow ASSERT and atomic<T> operations in a trivial function (#82063)
1 parent 030d075 commit c3b87a8

File tree

6 files changed

+75
-15
lines changed

6 files changed

+75
-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: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,8 @@ class TrivialFunctionAnalysisVisitor
315315
return false;
316316
}
317317

318+
bool VisitAtomicExpr(const AtomicExpr *E) { return VisitChildren(E); }
319+
318320
bool VisitStaticAssertDecl(const StaticAssertDecl *SAD) {
319321
// Any static_assert is considered trivial.
320322
return true;
@@ -330,12 +332,18 @@ class TrivialFunctionAnalysisVisitor
330332
const auto &Name = safeGetName(Callee);
331333

332334
if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" ||
335+
Name == "WTFReportAssertionFailure" ||
333336
Name == "compilerFenceForCrash" || Name == "__builtin_unreachable")
334337
return true;
335338

336339
return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache);
337340
}
338341

342+
bool VisitPredefinedExpr(const PredefinedExpr *E) {
343+
// A predefined identifier such as "func" is considered trivial.
344+
return true;
345+
}
346+
339347
bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE) {
340348
if (!checkArguments(MCE))
341349
return false;
@@ -356,6 +364,14 @@ class TrivialFunctionAnalysisVisitor
356364
return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache);
357365
}
358366

367+
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
368+
if (auto *Expr = E->getExpr()) {
369+
if (!Visit(Expr))
370+
return false;
371+
}
372+
return true;
373+
}
374+
359375
bool checkArguments(const CallExpr *CE) {
360376
for (const Expr *Arg : CE->arguments()) {
361377
if (Arg && !Visit(Arg))

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ class UncountedCallArgsChecker
7373
unsigned ArgIdx = isa<CXXOperatorCallExpr>(CE) && isa_and_nonnull<CXXMethodDecl>(F);
7474

7575
if (auto *MemberCallExpr = dyn_cast<CXXMemberCallExpr>(CE)) {
76+
if (auto *MD = MemberCallExpr->getMethodDecl()) {
77+
auto name = safeGetName(MD);
78+
if (name == "ref" || name == "deref")
79+
return;
80+
}
7681
auto *E = MemberCallExpr->getImplicitObjectArgument();
7782
QualType ArgType = MemberCallExpr->getObjectType();
7883
std::optional<bool> IsUncounted =

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 test2() {
360+
someFunction(*object());
361+
}

0 commit comments

Comments
 (0)