https://github.com/ziqingluo-90 updated https://github.com/llvm/llvm-project/pull/189775
>From f561217ce6be85b30b15331e91423e60a8fba71e Mon Sep 17 00:00:00 2001 From: Ziqing Luo <[email protected]> Date: Tue, 31 Mar 2026 16:55:30 -0700 Subject: [PATCH] [APINotes][unsafe-buffer-usage] Add [[clang::unsafe_buffer_usage]] support in APINotes Support the ``[[clang::unsafe_buffer_usage]]`` attribute in APINotes, e.g., ``` Functions: - Name: myUnsafeFunction UnsafeBufferUsage: true ``` rdar://171859135 --- clang/docs/ReleaseNotes.rst | 9 ++++++++ clang/include/clang/APINotes/Types.h | 7 +++++- clang/lib/APINotes/APINotesFormat.h | 2 +- clang/lib/APINotes/APINotesReader.cpp | 3 +++ clang/lib/APINotes/APINotesTypes.cpp | 1 + clang/lib/APINotes/APINotesWriter.cpp | 2 ++ clang/lib/APINotes/APINotesYAMLCompiler.cpp | 3 +++ clang/lib/Sema/SemaAPINotes.cpp | 8 +++++++ .../Inputs/Headers/UnsafeBufferUsage.apinotes | 6 +++++ .../Inputs/Headers/UnsafeBufferUsage.h | 2 ++ .../APINotes/Inputs/Headers/module.modulemap | 5 ++++ clang/test/APINotes/unsafe-buffer-usage.cpp | 23 +++++++++++++++++++ 12 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.apinotes create mode 100644 clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.h create mode 100644 clang/test/APINotes/unsafe-buffer-usage.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index cd7f280fbb6db..13e39e240d9b4 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -252,6 +252,15 @@ Attribute Changes in Clang sound because any writer must hold all capabilities, so holding any one prevents concurrent writes. +- The ``[[clang::unsafe_buffer_usage]]`` attribute is now supported in API + notes. For example: + + .. code-block:: yaml + + Functions: + - Name: myUnsafeFunction + UnsafeBufferUsage: true + Improvements to Clang's diagnostics ----------------------------------- - ``-Wunused-but-set-variable`` now diagnoses file-scope variables with diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h index fb2b91a3e1750..8291b9e2668ea 100644 --- a/clang/include/clang/APINotes/Types.h +++ b/clang/include/clang/APINotes/Types.h @@ -570,6 +570,10 @@ class FunctionInfo : public CommonEntityInfo { /// A biased RetainCountConventionKind, where 0 means "unspecified". unsigned RawRetainCountConvention : 3; + /// Whether the function has the [[clang::unsafe_buffer_usage]] attribute + LLVM_PREFERRED_TYPE(bool) + unsigned UnsafeBufferUsage : 1; + // NullabilityKindSize bits are used to encode the nullability. The info // about the return type is stored at position 0, followed by the nullability // of the parameters. @@ -588,7 +592,7 @@ class FunctionInfo : public CommonEntityInfo { FunctionInfo() : NullabilityAudited(false), NumAdjustedNullable(0), - RawRetainCountConvention() {} + RawRetainCountConvention(), UnsafeBufferUsage(0) {} static unsigned getMaxNullabilityIndex() { return ((sizeof(NullabilityPayload) * CHAR_BIT) / NullabilityKindSize); @@ -660,6 +664,7 @@ class FunctionInfo : public CommonEntityInfo { inline bool operator==(const FunctionInfo &LHS, const FunctionInfo &RHS) { return static_cast<const CommonEntityInfo &>(LHS) == RHS && LHS.NullabilityAudited == RHS.NullabilityAudited && + LHS.UnsafeBufferUsage == RHS.UnsafeBufferUsage && LHS.NumAdjustedNullable == RHS.NumAdjustedNullable && LHS.NullabilityPayload == RHS.NullabilityPayload && LHS.ResultType == RHS.ResultType && LHS.Params == RHS.Params && diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h index 9d868a1b4da1f..db94e6cf5492b 100644 --- a/clang/lib/APINotes/APINotesFormat.h +++ b/clang/lib/APINotes/APINotesFormat.h @@ -24,7 +24,7 @@ const uint16_t VERSION_MAJOR = 0; /// API notes file minor version number. /// /// When the format changes IN ANY WAY, this number should be incremented. -const uint16_t VERSION_MINOR = 38; // SwiftSafety +const uint16_t VERSION_MINOR = 39; // 39 for [[clang::unsafe_buffer_usage]] const uint8_t kSwiftConforms = 1; const uint8_t kSwiftDoesNotConform = 2; diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp index f00c7ac1d9d9b..2e6e397577e76 100644 --- a/clang/lib/APINotes/APINotesReader.cpp +++ b/clang/lib/APINotes/APINotesReader.cpp @@ -354,6 +354,9 @@ void ReadFunctionInfo(const uint8_t *&Data, FunctionInfo &Info) { ReadCommonEntityInfo(Data, Info); uint8_t Payload = endian::readNext<uint8_t, llvm::endianness::little>(Data); + if (Payload & 0x1) + Info.UnsafeBufferUsage = 1; + Payload >>= 0x1; if (auto RawConvention = Payload & 0x7) { auto Convention = static_cast<RetainCountConventionKind>(RawConvention - 1); Info.setRetainCountConvention(Convention); diff --git a/clang/lib/APINotes/APINotesTypes.cpp b/clang/lib/APINotes/APINotesTypes.cpp index bff4be104c6c8..177b387d1c480 100644 --- a/clang/lib/APINotes/APINotesTypes.cpp +++ b/clang/lib/APINotes/APINotesTypes.cpp @@ -89,6 +89,7 @@ LLVM_DUMP_METHOD void ParamInfo::dump(llvm::raw_ostream &OS) const { LLVM_DUMP_METHOD void FunctionInfo::dump(llvm::raw_ostream &OS) const { static_cast<const CommonEntityInfo &>(*this).dump(OS); OS << (NullabilityAudited ? "[NullabilityAudited] " : "") + << (UnsafeBufferUsage ? "[UnsafeBufferUsage] " : "") << "RawRetainCountConvention: " << RawRetainCountConvention << ' '; if (!ResultType.empty()) OS << "Result Type: " << ResultType << ' '; diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp index 390aea57f3915..be9ffaa475b67 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -1122,6 +1122,8 @@ void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) { flags <<= 3; if (auto RCC = FI.getRetainCountConvention()) flags |= static_cast<uint8_t>(RCC.value()) + 1; + flags <<= 0x01; + flags |= FI.UnsafeBufferUsage; llvm::support::endian::Writer writer(OS, llvm::endianness::little); diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp index 3b82fdda68af1..202d3069d78ae 100644 --- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp +++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp @@ -316,6 +316,7 @@ struct Function { StringRef ResultType; StringRef SwiftReturnOwnership; SwiftSafetyKind SafetyKind = SwiftSafetyKind::None; + bool UnsafeBufferUsage = false; }; typedef std::vector<Function> FunctionsSeq; @@ -341,6 +342,7 @@ template <> struct MappingTraits<Function> { IO.mapOptional("SwiftReturnOwnership", F.SwiftReturnOwnership, StringRef("")); IO.mapOptional("SwiftSafety", F.SafetyKind, SwiftSafetyKind::None); + IO.mapOptional("UnsafeBufferUsage", F.UnsafeBufferUsage, false); } }; } // namespace yaml @@ -1003,6 +1005,7 @@ class YAMLConverter { FI.ResultType = std::string(Function.ResultType); FI.SwiftReturnOwnership = std::string(Function.SwiftReturnOwnership); FI.setRetainCountConvention(Function.RetainCountConvention); + FI.UnsafeBufferUsage = Function.UnsafeBufferUsage; } void convertTagContext(std::optional<Context> ParentContext, const Tag &T, diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index ab314a43abcca..40eb3d3de71a1 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -578,6 +578,14 @@ static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc, if (Info.NullabilityAudited) applyNullability(S, D, Info.getReturnTypeInfo(), Metadata); + // Add [[clang::unsafe_buffer_usage]] + if (Info.UnsafeBufferUsage) { + handleAPINotedAttribute<UnsafeBufferUsageAttr>(S, D, true, Metadata, [&]() { + return UnsafeBufferUsageAttr::Create(S.getASTContext(), + getPlaceholderAttrInfo()); + }); + } + // Parameters. unsigned NumParams = FD ? FD->getNumParams() : MD->param_size(); diff --git a/clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.apinotes b/clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.apinotes new file mode 100644 index 0000000000000..6ebde8f6ffdec --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.apinotes @@ -0,0 +1,6 @@ +--- +Name: UnsafeBufferUsage +Functions: + - Name: unsafeFunc + UnsafeBufferUsage: true +... diff --git a/clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.h b/clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.h new file mode 100644 index 0000000000000..e80f2e1f0b6d1 --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/UnsafeBufferUsage.h @@ -0,0 +1,2 @@ +void unsafeFunc(int *p, int n); +void safeFunc(int *p, int n); diff --git a/clang/test/APINotes/Inputs/Headers/module.modulemap b/clang/test/APINotes/Inputs/Headers/module.modulemap index bedb7d505f794..64ea476e80d8c 100644 --- a/clang/test/APINotes/Inputs/Headers/module.modulemap +++ b/clang/test/APINotes/Inputs/Headers/module.modulemap @@ -61,3 +61,8 @@ module SwiftImportAs { module SwiftReturnOwnershipForObjC { header "SwiftReturnOwnershipForObjC.h" } + +module UnsafeBufferUsage { + header "UnsafeBufferUsage.h" + export * +} diff --git a/clang/test/APINotes/unsafe-buffer-usage.cpp b/clang/test/APINotes/unsafe-buffer-usage.cpp new file mode 100644 index 0000000000000..03bc4c56e979b --- /dev/null +++ b/clang/test/APINotes/unsafe-buffer-usage.cpp @@ -0,0 +1,23 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules\ +// RUN: -I %S/Inputs/Headers %s -x c++ -verify -Wunsafe-buffer-usage -Wno-unused-value +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules\ +// RUN: -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter unsafeFunc | FileCheck %s + +#include "UnsafeBufferUsage.h" + +// CHECK: FunctionDecl {{.+}} unsafeFunc +// CHECK: UnsafeBufferUsageAttr + +void caller(int *p, int n) { + unsafeFunc(p, n); // expected-warning{{function introduces unsafe buffer manipulation}} + safeFunc(p, n); // no warning +} + +void unsafeFunc(int *p, int n) { + p[n]; // no warning +} + +void safeFunc(int *p, int n) { + p[n]; // expected-warning{{unsafe buffer access}} +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
