diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index 842e40b6da5c7..fcc0181db1a3c 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -1076,24 +1076,32 @@ static bool isHardcodedCountedByPointerArgumentSafe( // Checks if the argument passed to __single pointer is one of the following // forms: -// 0. `nullptr`. -// 1. `&var`, if `var` is a variable identifier. -// 2. `&C[_]`, if `C` is a hardened container/view. -// 3. `sp.first(1).data()` and friends. -bool isSinglePointerArgumentSafe(ASTContext &Context, const Expr *Arg) { - const Expr *ArgNoImp = Arg->IgnoreParenImpCasts(); +// 0. Anything, if the param type is a `void *__single`. +// 1. `nullptr`. +// 2. `&var`, if `var` is a variable identifier. +// 3. `&C[_]`, if `C` is a hardened container/view. +// 4. `sp.first(1).data()` and friends. +bool isSinglePointerArgumentSafe(ASTContext &Context, QualType ParamTy, + const Expr *Arg) { + assert(ParamTy->isSinglePointerType()); // Check form 0: - if (ArgNoImp->getType()->isNullPtrType()) + if (ParamTy->getPointeeType()->isVoidType()) return true; + const Expr *ArgNoImp = Arg->IgnoreParenImpCasts(); + // Check form 1: + if (ArgNoImp->getType()->isNullPtrType()) + return true; + + // Check form 2: { if (tryGetAddressofDRE(ArgNoImp)) return true; } - // Check form 2: + // Check form 3: { if (const auto *UO = dyn_cast(ArgNoImp)) if (UO->getOpcode() == UnaryOperator::Opcode::UO_AddrOf) { @@ -1108,7 +1116,7 @@ bool isSinglePointerArgumentSafe(ASTContext &Context, const Expr *Arg) { } } - // Check form 3: + // Check form 4: if (const Expr *ExtentExpr = extractExtentFromSubviewDataCall(Context, ArgNoImp)) { std::optional ExtentVal = @@ -3463,7 +3471,7 @@ class SinglePointerArgumentGadget : public WarningGadget { ast_matchers::matchEachArgumentWithParamType( *Call, [&Results, &Ctx, &Found](QualType QT, const Expr *Arg) { if (isSinglePointerType(QT) && - !isSinglePointerArgumentSafe(Ctx, Arg)) { + !isSinglePointerArgumentSafe(Ctx, QT, Arg)) { Results.emplace_back(ArgTag, DynTypedNode::create(*Arg)); Found = true; } diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-single-pointer-argument.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-single-pointer-argument.cpp index e38621f7c546d..89d07265061ff 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-single-pointer-argument.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-single-pointer-argument.cpp @@ -56,6 +56,23 @@ void single_int_int(int *__single p, int *__single q); } // extern "C" +// Check passing to `void *__single`. + +void pass_to_single_void(void *pv, std::span sp, my_vec &mv) { + char array[42] = {}; + + single_void(pv); + + single_void(sp.data()); + single_void(sp.first(1).data()); + single_void(sp.first(42).data()); + single_void(&sp[42]); + + single_void(&mv[0]); + + single_void(array); +} + // Check passing `nullptr`. void null() {