Skip to content

Commit 52102bf

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
1 parent 632273d commit 52102bf

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
@@ -1064,24 +1064,32 @@ static bool isHardcodedCountedByPointerArgumentSafe(
10641064

10651065
// Checks if the argument passed to __single pointer is one of the following
10661066
// forms:
1067-
// 0. `nullptr`.
1068-
// 1. `&var`, if `var` is a variable identifier.
1069-
// 2. `&C[_]`, if `C` is a hardened container/view.
1070-
// 3. `sp.first(1).data()` and friends.
1071-
bool isSinglePointerArgumentSafe(ASTContext &Context, const Expr *Arg) {
1072-
const Expr *ArgNoImp = Arg->IgnoreParenImpCasts();
1067+
// 0. Anything, if the param type is a `void *__single`.
1068+
// 1. `nullptr`.
1069+
// 2. `&var`, if `var` is a variable identifier.
1070+
// 3. `&C[_]`, if `C` is a hardened container/view.
1071+
// 4. `sp.first(1).data()` and friends.
1072+
bool isSinglePointerArgumentSafe(ASTContext &Context, QualType ParamTy,
1073+
const Expr *Arg) {
1074+
assert(ParamTy->isSinglePointerType());
10731075

10741076
// Check form 0:
1075-
if (ArgNoImp->getType()->isNullPtrType())
1077+
if (ParamTy->getPointeeType()->isVoidType())
10761078
return true;
10771079

1080+
const Expr *ArgNoImp = Arg->IgnoreParenImpCasts();
1081+
10781082
// Check form 1:
1083+
if (ArgNoImp->getType()->isNullPtrType())
1084+
return true;
1085+
1086+
// Check form 2:
10791087
{
10801088
if (tryGetAddressofDRE(ArgNoImp))
10811089
return true;
10821090
}
10831091

1084-
// Check form 2:
1092+
// Check form 3:
10851093
{
10861094
if (const auto *UO = dyn_cast<UnaryOperator>(ArgNoImp))
10871095
if (UO->getOpcode() == UnaryOperator::Opcode::UO_AddrOf) {
@@ -1096,7 +1104,7 @@ bool isSinglePointerArgumentSafe(ASTContext &Context, const Expr *Arg) {
10961104
}
10971105
}
10981106

1099-
// Check form 3:
1107+
// Check form 4:
11001108
if (const Expr *ExtentExpr =
11011109
extractExtentFromSubviewDataCall(Context, ArgNoImp)) {
11021110
std::optional<llvm::APSInt> ExtentVal =
@@ -3451,7 +3459,7 @@ class SinglePointerArgumentGadget : public WarningGadget {
34513459
ast_matchers::matchEachArgumentWithParamType(
34523460
*Call, [&Results, &Ctx, &Found](QualType QT, const Expr *Arg) {
34533461
if (isSinglePointerType(QT) &&
3454-
!isSinglePointerArgumentSafe(Ctx, Arg)) {
3462+
!isSinglePointerArgumentSafe(Ctx, QT, Arg)) {
34553463
Results.emplace_back(ArgTag, DynTypedNode::create(*Arg));
34563464
Found = true;
34573465
}

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)