Skip to content

Commit cba52d3

Browse files
[-Wunsafe-buffer-usage] Allow passing anything to void *__single
BoundsSafety assumes that `void *__single` cannot be dereferenced and allows assigning anything to `void *__single`. This commit ports this behavior to C++ interop. rdar://156007256 (cherry picked from commit 53149eb)
1 parent 602aa5c commit cba52d3

File tree

2 files changed

+35
-10
lines changed

2 files changed

+35
-10
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,24 +1071,32 @@ static bool isHardcodedCountedByPointerArgumentSafe(
10711071

10721072
// Checks if the argument passed to __single pointer is one of the following
10731073
// forms:
1074-
// 0. `nullptr`.
1075-
// 1. `&var`, if `var` is a variable identifier.
1076-
// 2. `&C[_]`, if `C` is a hardened container/view.
1077-
// 3. `sp.first(1).data()` and friends.
1078-
bool isSinglePointerArgumentSafe(ASTContext &Context, const Expr *Arg) {
1079-
const Expr *ArgNoImp = Arg->IgnoreParenImpCasts();
1074+
// 0. Anything, if the param type is a `void *__single`.
1075+
// 1. `nullptr`.
1076+
// 2. `&var`, if `var` is a variable identifier.
1077+
// 3. `&C[_]`, if `C` is a hardened container/view.
1078+
// 4. `sp.first(1).data()` and friends.
1079+
bool isSinglePointerArgumentSafe(ASTContext &Context, QualType ParamTy,
1080+
const Expr *Arg) {
1081+
assert(ParamTy->isSinglePointerType());
10801082

10811083
// Check form 0:
1082-
if (ArgNoImp->getType()->isNullPtrType())
1084+
if (ParamTy->getPointeeType()->isVoidType())
10831085
return true;
10841086

1087+
const Expr *ArgNoImp = Arg->IgnoreParenImpCasts();
1088+
10851089
// Check form 1:
1090+
if (ArgNoImp->getType()->isNullPtrType())
1091+
return true;
1092+
1093+
// Check form 2:
10861094
{
10871095
if (tryGetAddressofDRE(ArgNoImp))
10881096
return true;
10891097
}
10901098

1091-
// Check form 2:
1099+
// Check form 3:
10921100
{
10931101
if (const auto *UO = dyn_cast<UnaryOperator>(ArgNoImp))
10941102
if (UO->getOpcode() == UnaryOperator::Opcode::UO_AddrOf) {
@@ -1103,7 +1111,7 @@ bool isSinglePointerArgumentSafe(ASTContext &Context, const Expr *Arg) {
11031111
}
11041112
}
11051113

1106-
// Check form 3:
1114+
// Check form 4:
11071115
if (const Expr *ExtentExpr =
11081116
extractExtentFromSubviewDataCall(Context, ArgNoImp)) {
11091117
std::optional<llvm::APSInt> ExtentVal =
@@ -3394,7 +3402,7 @@ class SinglePointerArgumentGadget : public WarningGadget {
33943402
ast_matchers::matchEachArgumentWithParamType(
33953403
*Call, [&Results, &Ctx, &Found](QualType QT, const Expr *Arg) {
33963404
if (isSinglePointerType(QT) &&
3397-
!isSinglePointerArgumentSafe(Ctx, Arg)) {
3405+
!isSinglePointerArgumentSafe(Ctx, QT, Arg)) {
33983406
Results.emplace_back(ArgTag, DynTypedNode::create(*Arg));
33993407
Found = true;
34003408
}

clang/test/SemaCXX/warn-unsafe-buffer-usage-single-pointer-argument.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,23 @@ void single_int_int(int *__single p, int *__single q);
5656

5757
} // extern "C"
5858

59+
// Check passing to `void *__single`.
60+
61+
void pass_to_single_void(void *pv, std::span<int> sp, my_vec<int> &mv) {
62+
char array[42] = {};
63+
64+
single_void(pv);
65+
66+
single_void(sp.data());
67+
single_void(sp.first(1).data());
68+
single_void(sp.first(42).data());
69+
single_void(&sp[42]);
70+
71+
single_void(&mv[0]);
72+
73+
single_void(array);
74+
}
75+
5976
// Check passing `nullptr`.
6077

6178
void null() {

0 commit comments

Comments
 (0)