Skip to content

Commit 1974862

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 f5a8063 commit 1974862

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

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

10861088
// Check form 0:
1087-
if (ArgNoImp->getType()->isNullPtrType())
1089+
if (ParamTy->getPointeeType()->isVoidType())
10881090
return true;
10891091

1092+
const Expr *ArgNoImp = Arg->IgnoreParenImpCasts();
1093+
10901094
// Check form 1:
1095+
if (ArgNoImp->getType()->isNullPtrType())
1096+
return true;
1097+
1098+
// Check form 2:
10911099
{
10921100
if (tryGetAddressofDRE(ArgNoImp))
10931101
return true;
10941102
}
10951103

1096-
// Check form 2:
1104+
// Check form 3:
10971105
{
10981106
if (const auto *UO = dyn_cast<UnaryOperator>(ArgNoImp))
10991107
if (UO->getOpcode() == UnaryOperator::Opcode::UO_AddrOf) {
@@ -1108,7 +1116,7 @@ bool isSinglePointerArgumentSafe(ASTContext &Context, const Expr *Arg) {
11081116
}
11091117
}
11101118

1111-
// Check form 3:
1119+
// Check form 4:
11121120
if (const Expr *ExtentExpr =
11131121
extractExtentFromSubviewDataCall(Context, ArgNoImp)) {
11141122
std::optional<llvm::APSInt> ExtentVal =
@@ -3463,7 +3471,7 @@ class SinglePointerArgumentGadget : public WarningGadget {
34633471
ast_matchers::matchEachArgumentWithParamType(
34643472
*Call, [&Results, &Ctx, &Found](QualType QT, const Expr *Arg) {
34653473
if (isSinglePointerType(QT) &&
3466-
!isSinglePointerArgumentSafe(Ctx, Arg)) {
3474+
!isSinglePointerArgumentSafe(Ctx, QT, Arg)) {
34673475
Results.emplace_back(ArgTag, DynTypedNode::create(*Arg));
34683476
Found = true;
34693477
}

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)