Skip to content

Commit f467673

Browse files
SC llvm teamSC llvm team
authored andcommitted
Merged main:8dd817b25ae8b666aef839d36ffe028c01d411b5 into amd-gfx:1928ca4d0875
Local branch amd-gfx 1928ca4 Merged main:631bcbe9de13e160d427ad7452a7ef2ca67911ab into amd-gfx:c94dc53f6a77 Remote branch main 8dd817b [LangRef] Disallow accessing byval arguments from tail-called functions (llvm#110093)
2 parents 1928ca4 + 8dd817b commit f467673

File tree

30 files changed

+465
-235
lines changed

30 files changed

+465
-235
lines changed

clang/docs/analyzer/checkers.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3442,6 +3442,27 @@ Check for non-determinism caused by sorting of pointers.
34423442
alpha.WebKit
34433443
^^^^^^^^^^^^
34443444
3445+
.. _alpha-webkit-NoUncheckedPtrMemberChecker:
3446+
3447+
alpha.webkit.NoUncheckedPtrMemberChecker
3448+
""""""""""""""""""""""""""""""""""""""""
3449+
Raw pointers and references to an object which supports CheckedPtr or CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, or Ref are allowed.
3450+
3451+
.. code-block:: cpp
3452+
3453+
struct CheckableObj {
3454+
void incrementPtrCount() {}
3455+
void decrementPtrCount() {}
3456+
};
3457+
3458+
struct Foo {
3459+
CheckableObj* ptr; // warn
3460+
CheckableObj& ptr; // warn
3461+
// ...
3462+
};
3463+
3464+
See `WebKit Guidelines for Safer C++ Programming <https://github.com/WebKit/WebKit/wiki/Safer-CPP-Guidelines>`_ for details.
3465+
34453466
.. _alpha-webkit-UncountedCallArgsChecker:
34463467
34473468
alpha.webkit.UncountedCallArgsChecker

clang/include/clang/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ class TranslationUnitDecl : public Decl,
133133
static TranslationUnitDecl *castFromDeclContext(const DeclContext *DC) {
134134
return static_cast<TranslationUnitDecl *>(const_cast<DeclContext*>(DC));
135135
}
136+
137+
/// Retrieves the canonical declaration of this translation unit.
138+
TranslationUnitDecl *getCanonicalDecl() override { return getFirstDecl(); }
139+
const TranslationUnitDecl *getCanonicalDecl() const { return getFirstDecl(); }
136140
};
137141

138142
/// Represents a `#pragma comment` line. Always a child of

clang/include/clang/AST/DeclID.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ class LocalDeclID : public DeclIDBase {
189189
// Every Decl ID is a local decl ID to the module being writing in ASTWriter.
190190
friend class ASTWriter;
191191
friend class GlobalDeclID;
192+
friend struct llvm::DenseMapInfo<clang::LocalDeclID>;
192193

193194
public:
194195
LocalDeclID() : Base() {}
@@ -267,6 +268,27 @@ template <> struct DenseMapInfo<clang::GlobalDeclID> {
267268
}
268269
};
269270

271+
template <> struct DenseMapInfo<clang::LocalDeclID> {
272+
using LocalDeclID = clang::LocalDeclID;
273+
using DeclID = LocalDeclID::DeclID;
274+
275+
static LocalDeclID getEmptyKey() {
276+
return LocalDeclID(DenseMapInfo<DeclID>::getEmptyKey());
277+
}
278+
279+
static LocalDeclID getTombstoneKey() {
280+
return LocalDeclID(DenseMapInfo<DeclID>::getTombstoneKey());
281+
}
282+
283+
static unsigned getHashValue(const LocalDeclID &Key) {
284+
return DenseMapInfo<DeclID>::getHashValue(Key.getRawValue());
285+
}
286+
287+
static bool isEqual(const LocalDeclID &L, const LocalDeclID &R) {
288+
return L == R;
289+
}
290+
};
291+
270292
} // namespace llvm
271293

272294
#endif

clang/include/clang/Serialization/ASTWriter.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,13 @@ class ASTWriter : public ASTDeserializationListener,
233233
/// instead of comparing the result of `getDeclID()` or `GetDeclRef()`.
234234
llvm::SmallPtrSet<const Decl *, 32> PredefinedDecls;
235235

236-
/// Mapping from FunctionDecl to the list of lambda IDs inside the function.
236+
/// Mapping from FunctionDecl ID to the list of lambda IDs inside the
237+
/// function.
237238
///
238239
/// These lambdas have to be loaded right after the function they belong to.
239240
/// In order to have canonical declaration for lambda class from the same
240241
/// module as enclosing function during deserialization.
241-
llvm::DenseMap<const Decl *, SmallVector<LocalDeclID, 4>>
242-
FunctionToLambdasMap;
242+
llvm::DenseMap<LocalDeclID, SmallVector<LocalDeclID, 4>> FunctionToLambdasMap;
243243

244244
/// Offset of each declaration in the bitstream, indexed by
245245
/// the declaration's ID.

clang/include/clang/StaticAnalyzer/Checkers/Checkers.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,6 +1764,10 @@ def UncountedLambdaCapturesChecker : Checker<"UncountedLambdaCapturesChecker">,
17641764

17651765
let ParentPackage = WebKitAlpha in {
17661766

1767+
def NoUncheckedPtrMemberChecker : Checker<"NoUncheckedPtrMemberChecker">,
1768+
HelpText<"Check for no unchecked member variables.">,
1769+
Documentation<HasDocumentation>;
1770+
17671771
def UncountedCallArgsChecker : Checker<"UncountedCallArgsChecker">,
17681772
HelpText<"Check uncounted call arguments.">,
17691773
Documentation<HasDocumentation>;

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ RawAddress CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align,
122122
Builder.SetInsertPoint(getPostAllocaInsertPoint());
123123
V = getTargetHooks().performAddrSpaceCast(
124124
*this, V, getASTAllocaAddressSpace(), LangAS::Default,
125-
Ty->getPointerTo(DestAddrSpace), /*non-null*/ true);
125+
Builder.getPtrTy(DestAddrSpace), /*non-null*/ true);
126126
}
127127

128128
return RawAddress(V, Ty, Align, KnownNonNull);
@@ -469,7 +469,8 @@ static RawAddress createReferenceTemporary(CodeGenFunction &CGF,
469469
if (AS != LangAS::Default)
470470
C = TCG.performAddrSpaceCast(
471471
CGF.CGM, GV, AS, LangAS::Default,
472-
GV->getValueType()->getPointerTo(
472+
llvm::PointerType::get(
473+
CGF.getLLVMContext(),
473474
CGF.getContext().getTargetAddressSpace(LangAS::Default)));
474475
// FIXME: Should we put the new global into a COMDAT?
475476
return RawAddress(C, GV->getValueType(), alignment);
@@ -3207,7 +3208,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
32073208

32083209
if (AS != T.getAddressSpace()) {
32093210
auto TargetAS = getContext().getTargetAddressSpace(T.getAddressSpace());
3210-
auto PtrTy = ATPO.getElementType()->getPointerTo(TargetAS);
3211+
auto PtrTy = llvm::PointerType::get(CGM.getLLVMContext(), TargetAS);
32113212
auto ASC = getTargetHooks().performAddrSpaceCast(
32123213
CGM, ATPO.getPointer(), AS, T.getAddressSpace(), PtrTy);
32133214
ATPO = ConstantAddress(ASC, ATPO.getElementType(), ATPO.getAlignment());
@@ -3835,9 +3836,7 @@ void CodeGenFunction::EmitCfiCheckFail() {
38353836
llvm::StructType::get(Int8Ty, SourceLocationTy, VoidPtrTy);
38363837

38373838
llvm::Value *V = Builder.CreateConstGEP2_32(
3838-
CfiCheckFailDataTy,
3839-
Builder.CreatePointerCast(Data, CfiCheckFailDataTy->getPointerTo(0)), 0,
3840-
0);
3839+
CfiCheckFailDataTy, Builder.CreatePointerCast(Data, UnqualPtrTy), 0, 0);
38413840

38423841
Address CheckKindAddr(V, Int8Ty, getIntAlign());
38433842
llvm::Value *CheckKind = Builder.CreateLoad(CheckKindAddr);
@@ -6115,36 +6114,6 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
61156114
if (ResolvedFnInfo)
61166115
*ResolvedFnInfo = &FnInfo;
61176116

6118-
// C99 6.5.2.2p6:
6119-
// If the expression that denotes the called function has a type
6120-
// that does not include a prototype, [the default argument
6121-
// promotions are performed]. If the number of arguments does not
6122-
// equal the number of parameters, the behavior is undefined. If
6123-
// the function is defined with a type that includes a prototype,
6124-
// and either the prototype ends with an ellipsis (, ...) or the
6125-
// types of the arguments after promotion are not compatible with
6126-
// the types of the parameters, the behavior is undefined. If the
6127-
// function is defined with a type that does not include a
6128-
// prototype, and the types of the arguments after promotion are
6129-
// not compatible with those of the parameters after promotion,
6130-
// the behavior is undefined [except in some trivial cases].
6131-
// That is, in the general case, we should assume that a call
6132-
// through an unprototyped function type works like a *non-variadic*
6133-
// call. The way we make this work is to cast to the exact type
6134-
// of the promoted arguments.
6135-
//
6136-
// Chain calls use this same code path to add the invisible chain parameter
6137-
// to the function type.
6138-
if (isa<FunctionNoProtoType>(FnType) || Chain) {
6139-
llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo);
6140-
int AS = Callee.getFunctionPointer()->getType()->getPointerAddressSpace();
6141-
CalleeTy = CalleeTy->getPointerTo(AS);
6142-
6143-
llvm::Value *CalleePtr = Callee.getFunctionPointer();
6144-
CalleePtr = Builder.CreateBitCast(CalleePtr, CalleeTy, "callee.knr.cast");
6145-
Callee.setFunctionPointer(CalleePtr);
6146-
}
6147-
61486117
// HIP function pointer contains kernel handle when it is used in triple
61496118
// chevron. The kernel stub needs to be loaded from kernel handle and used
61506119
// as callee.

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5713,8 +5713,7 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
57135713
// efficent becuase it allows lazy deserialization.
57145714
RecordData FunctionToLambdasMapRecord;
57155715
for (const auto &Pair : FunctionToLambdasMap) {
5716-
FunctionToLambdasMapRecord.push_back(
5717-
GetDeclRef(Pair.first).getRawValue());
5716+
FunctionToLambdasMapRecord.push_back(Pair.first.getRawValue());
57185717
FunctionToLambdasMapRecord.push_back(Pair.second.size());
57195718
for (const auto &Lambda : Pair.second)
57205719
FunctionToLambdasMapRecord.push_back(Lambda.getRawValue());

clang/lib/Serialization/ASTWriterDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1524,7 +1524,8 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
15241524
// For lambdas inside canonical FunctionDecl remember the mapping.
15251525
if (auto FD = llvm::dyn_cast_or_null<FunctionDecl>(D->getDeclContext());
15261526
FD && FD->isCanonicalDecl()) {
1527-
Writer.FunctionToLambdasMap[FD].push_back(Writer.GetDeclRef(D));
1527+
Writer.FunctionToLambdasMap[Writer.GetDeclRef(FD)].push_back(
1528+
Writer.GetDeclRef(D));
15281529
}
15291530
} else {
15301531
Record.push_back(CXXRecNotTemplate);

clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ add_clang_library(clangStaticAnalyzerCheckers
132132
VLASizeChecker.cpp
133133
ValistChecker.cpp
134134
VirtualCallChecker.cpp
135-
WebKit/NoUncountedMembersChecker.cpp
135+
WebKit/RawPtrRefMemberChecker.cpp
136136
WebKit/ASTUtils.cpp
137137
WebKit/PtrTypesSemantics.cpp
138138
WebKit/RefCntblBaseVirtualDtorChecker.cpp

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

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ using namespace clang;
1919

2020
namespace {
2121

22-
bool hasPublicMethodInBaseClass(const CXXRecordDecl *R,
23-
const char *NameToMatch) {
22+
bool hasPublicMethodInBaseClass(const CXXRecordDecl *R, StringRef NameToMatch) {
2423
assert(R);
2524
assert(R->hasDefinition());
2625

@@ -37,7 +36,7 @@ bool hasPublicMethodInBaseClass(const CXXRecordDecl *R,
3736
namespace clang {
3837

3938
std::optional<const clang::CXXRecordDecl *>
40-
hasPublicMethodInBase(const CXXBaseSpecifier *Base, const char *NameToMatch) {
39+
hasPublicMethodInBase(const CXXBaseSpecifier *Base, StringRef NameToMatch) {
4140
assert(Base);
4241

4342
const Type *T = Base->getType().getTypePtrOrNull();
@@ -53,48 +52,49 @@ hasPublicMethodInBase(const CXXBaseSpecifier *Base, const char *NameToMatch) {
5352
return hasPublicMethodInBaseClass(R, NameToMatch) ? R : nullptr;
5453
}
5554

56-
std::optional<bool> isRefCountable(const CXXRecordDecl* R)
57-
{
55+
std::optional<bool> isSmartPtrCompatible(const CXXRecordDecl *R,
56+
StringRef IncMethodName,
57+
StringRef DecMethodName) {
5858
assert(R);
5959

6060
R = R->getDefinition();
6161
if (!R)
6262
return std::nullopt;
6363

64-
bool hasRef = hasPublicMethodInBaseClass(R, "ref");
65-
bool hasDeref = hasPublicMethodInBaseClass(R, "deref");
64+
bool hasRef = hasPublicMethodInBaseClass(R, IncMethodName);
65+
bool hasDeref = hasPublicMethodInBaseClass(R, DecMethodName);
6666
if (hasRef && hasDeref)
6767
return true;
6868

6969
CXXBasePaths Paths;
7070
Paths.setOrigin(const_cast<CXXRecordDecl *>(R));
7171

7272
bool AnyInconclusiveBase = false;
73-
const auto hasPublicRefInBase =
74-
[&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) {
75-
auto hasRefInBase = clang::hasPublicMethodInBase(Base, "ref");
76-
if (!hasRefInBase) {
77-
AnyInconclusiveBase = true;
78-
return false;
79-
}
80-
return (*hasRefInBase) != nullptr;
81-
};
73+
const auto hasPublicRefInBase = [&](const CXXBaseSpecifier *Base,
74+
CXXBasePath &) {
75+
auto hasRefInBase = clang::hasPublicMethodInBase(Base, IncMethodName);
76+
if (!hasRefInBase) {
77+
AnyInconclusiveBase = true;
78+
return false;
79+
}
80+
return (*hasRefInBase) != nullptr;
81+
};
8282

8383
hasRef = hasRef || R->lookupInBases(hasPublicRefInBase, Paths,
8484
/*LookupInDependent =*/true);
8585
if (AnyInconclusiveBase)
8686
return std::nullopt;
8787

8888
Paths.clear();
89-
const auto hasPublicDerefInBase =
90-
[&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) {
91-
auto hasDerefInBase = clang::hasPublicMethodInBase(Base, "deref");
92-
if (!hasDerefInBase) {
93-
AnyInconclusiveBase = true;
94-
return false;
95-
}
96-
return (*hasDerefInBase) != nullptr;
97-
};
89+
const auto hasPublicDerefInBase = [&](const CXXBaseSpecifier *Base,
90+
CXXBasePath &) {
91+
auto hasDerefInBase = clang::hasPublicMethodInBase(Base, DecMethodName);
92+
if (!hasDerefInBase) {
93+
AnyInconclusiveBase = true;
94+
return false;
95+
}
96+
return (*hasDerefInBase) != nullptr;
97+
};
9898
hasDeref = hasDeref || R->lookupInBases(hasPublicDerefInBase, Paths,
9999
/*LookupInDependent =*/true);
100100
if (AnyInconclusiveBase)
@@ -103,11 +103,23 @@ std::optional<bool> isRefCountable(const CXXRecordDecl* R)
103103
return hasRef && hasDeref;
104104
}
105105

106+
std::optional<bool> isRefCountable(const clang::CXXRecordDecl *R) {
107+
return isSmartPtrCompatible(R, "ref", "deref");
108+
}
109+
110+
std::optional<bool> isCheckedPtrCapable(const clang::CXXRecordDecl *R) {
111+
return isSmartPtrCompatible(R, "incrementPtrCount", "decrementPtrCount");
112+
}
113+
106114
bool isRefType(const std::string &Name) {
107115
return Name == "Ref" || Name == "RefAllowingPartiallyDestroyed" ||
108116
Name == "RefPtr" || Name == "RefPtrAllowingPartiallyDestroyed";
109117
}
110118

119+
bool isCheckedPtr(const std::string &Name) {
120+
return Name == "CheckedPtr" || Name == "CheckedRef";
121+
}
122+
111123
bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
112124
assert(F);
113125
const std::string &FunctionName = safeGetName(F);
@@ -217,6 +229,15 @@ bool isRefCounted(const CXXRecordDecl *R) {
217229
return false;
218230
}
219231

232+
bool isCheckedPtr(const CXXRecordDecl *R) {
233+
assert(R);
234+
if (auto *TmplR = R->getTemplateInstantiationPattern()) {
235+
const auto &ClassName = safeGetName(TmplR);
236+
return isCheckedPtr(ClassName);
237+
}
238+
return false;
239+
}
240+
220241
bool isPtrConversion(const FunctionDecl *F) {
221242
assert(F);
222243
if (isCtorOfRefCounted(F))

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,23 @@ class Type;
3434
/// \returns CXXRecordDecl of the base if the type has ref as a public method,
3535
/// nullptr if not, std::nullopt if inconclusive.
3636
std::optional<const clang::CXXRecordDecl *>
37-
hasPublicMethodInBase(const CXXBaseSpecifier *Base, const char *NameToMatch);
37+
hasPublicMethodInBase(const CXXBaseSpecifier *Base,
38+
llvm::StringRef NameToMatch);
3839

3940
/// \returns true if \p Class is ref-countable, false if not, std::nullopt if
4041
/// inconclusive.
41-
std::optional<bool> isRefCountable(const clang::CXXRecordDecl* Class);
42+
std::optional<bool> isRefCountable(const clang::CXXRecordDecl *Class);
43+
44+
/// \returns true if \p Class is checked-pointer compatible, false if not,
45+
/// std::nullopt if inconclusive.
46+
std::optional<bool> isCheckedPtrCapable(const clang::CXXRecordDecl *Class);
4247

4348
/// \returns true if \p Class is ref-counted, false if not.
4449
bool isRefCounted(const clang::CXXRecordDecl *Class);
4550

51+
/// \returns true if \p Class is a CheckedPtr / CheckedRef, false if not.
52+
bool isCheckedPtr(const clang::CXXRecordDecl *Class);
53+
4654
/// \returns true if \p Class is ref-countable AND not ref-counted, false if
4755
/// not, std::nullopt if inconclusive.
4856
std::optional<bool> isUncounted(const clang::QualType T);

0 commit comments

Comments
 (0)