https://github.com/aloisklink created https://github.com/llvm/llvm-project/pull/68059
Ignore the `[[malloc(x)]]` or `[[malloc(x, 1)]]` function attribute syntax added in [GCC 11][1]. Unlike `[[malloc]]` with no arguments (which is supported by Clang), GCC uses the one or two argument form to specify a deallocator for GCC's static analyzer. Code currently compiled with `[[malloc(x)]]` or `__attribute__((malloc(x)))` fails with the following error: `'malloc' attribute takes no arguments`. [1]: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;f=gcc/doc/extend.texi;h=dce6c58db87ebf7f4477bd3126228e73e4eeee97#patch6 Fixes: https://github.com/llvm/llvm-project/issues/51607 Partial-Bug: https://github.com/llvm/llvm-project/issues/53152 (this PR only ignores `__attribute__((malloc(x)))` and allows it to compile, so only partially fixes the problem). --- In the future, we can add this attribute to the AST as well. This will let us improve the clang static analyzer's [`unix.MismatchedDeallocator`](https://clang.llvm.org/docs/analyzer/checkers.html#id93) checker. >From f9c914729a5f5ac7f8b61ea2d39509ff0236a228 Mon Sep 17 00:00:00 2001 From: Alois Klink <al...@aloisklink.com> Date: Mon, 2 Oct 2023 19:59:06 +0100 Subject: [PATCH] [clang] Ignore GCC 11 [[malloc(x)]] attribute Ignore the `[[malloc(x)]]` or `[[malloc(x, 1)]]` function attribute syntax added in [GCC 11][1]. Unlike `[[malloc]]` with no arguments (which is supported by Clang), GCC uses the one or two argument form to specify a deallocator for GCC's static analyzer. Code currently compiled with `[[malloc(x)]]` or `__attribute((malloc(x)))` fails with the following error: `'malloc' attribute takes no arguments`. [1]: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;f=gcc/doc/extend.texi;h=dce6c58db87ebf7f4477bd3126228e73e4eeee97#patch6 Fixes: https://github.com/llvm/llvm-project/issues/51607 Partial-Bug: https://github.com/llvm/llvm-project/issues/53152 --- clang/include/clang/Basic/Attr.td | 2 ++ clang/include/clang/Basic/AttrDocs.td | 3 +++ clang/lib/Sema/SemaDeclAttr.cpp | 19 ++++++++++++++++--- clang/test/Sema/attr-args.c | 5 +++-- clang/test/SemaCXX/attr-print.cpp | 8 ++++++++ 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 7a6ec77ae84b15a..db1f332efdb7653 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1629,6 +1629,8 @@ def IFunc : Attr, TargetSpecificAttr<TargetELF> { def Restrict : InheritableAttr { let Spellings = [Declspec<"restrict">, GCC<"malloc">]; + let Args = [IdentifierArgument<"Deallocator", /*opt*/ 1>, + ParamIdxArgument<"DeallocatorPtrArgIndex", /*opt*/ 1>]; let Subjects = SubjectList<[Function]>; let Documentation = [RestrictDocs]; } diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 8d928dcc146b254..1e498aeea6b7832 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -4122,6 +4122,9 @@ def RestrictDocs : Documentation { The ``malloc`` attribute indicates that the function acts like a system memory allocation function, returning a pointer to allocated storage disjoint from the storage for any other object accessible to the caller. + +The form of ``malloc`` with one or two arguments (supported by GCC 11) is +currently ignored by Clang. }]; } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index ed0b4d29b056397..fcc63cc27c1b537 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2064,13 +2064,26 @@ static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType ResultType = getFunctionOrMethodResultType(D); - if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()) { + if (!ResultType->isAnyPointerType() && !ResultType->isBlockPointerType()) { + S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) + << AL << getFunctionOrMethodResultSourceRange(D); + return; + } + + if (getNumAttributeArgs(AL) == 0) { D->addAttr(::new (S.Context) RestrictAttr(S.Context, AL)); return; } - S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) - << AL << getFunctionOrMethodResultSourceRange(D); + if (AL.getAttributeSpellingListIndex() == RestrictAttr::Declspec_restrict) { + // __declspec(restrict) accepts no arguments + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 0; + return; + } + + // FIXME: GCC uses [[malloc(my_func)]] to specify a deallocator for the + // returned pointer, but this isn't currently supported in LLVM + // see https://github.com/llvm/llvm-project/issues/51607 } static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { diff --git a/clang/test/Sema/attr-args.c b/clang/test/Sema/attr-args.c index e275c90be1f9dca..3054a08ad4ca456 100644 --- a/clang/test/Sema/attr-args.c +++ b/clang/test/Sema/attr-args.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -fsyntax-only %s +// RUN: %clang_cc1 -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -fsyntax-only -fdeclspec %s int a; inline __attribute__((noreturn(a))) void *f1(void); // expected-error {{'noreturn' attribute takes no arguments}} @@ -6,7 +6,8 @@ inline __attribute__((always_inline(a))) void *f2(void); // expected-error {{'a inline __attribute__((cdecl(a))) void *f3(void); // expected-error {{'cdecl' attribute takes no arguments}} inline __attribute__((const(a))) void *f4(void); // expected-error {{'const' attribute takes no arguments}} inline __attribute__((fastcall(a))) void *f5(void); // expected-error {{'fastcall' attribute takes no arguments}} -inline __attribute__((malloc(a))) void *f5(void); // expected-error {{'malloc' attribute takes no arguments}} +inline __declspec(restrict(a)) void *f6_a(void); // expected-error {{'restrict' attribute takes no arguments}} +inline __attribute__((malloc(a, 1, a))) void *f6_b(void); // expected-error {{'malloc' attribute takes no more than 2 arguments}} inline __attribute__((nothrow(a))) void *f7(void); // expected-error {{'nothrow' attribute takes no arguments}} inline __attribute__((stdcall(a))) void *f8(void); // expected-error {{'stdcall' attribute takes no arguments}} inline __attribute__((used(a))) void *f9(void); // expected-error {{'used' attribute takes no arguments}} diff --git a/clang/test/SemaCXX/attr-print.cpp b/clang/test/SemaCXX/attr-print.cpp index dff290be696be24..17e4d3d823cfd8e 100644 --- a/clang/test/SemaCXX/attr-print.cpp +++ b/clang/test/SemaCXX/attr-print.cpp @@ -28,6 +28,14 @@ int v __attribute__((visibility("hidden"))); // CHECK: char *PR24565() __attribute__((malloc)) char *PR24565() __attribute__((__malloc__)); +void my_cleanup_func(char *); + +// using __attribute__(malloc()) with args is currently ignored by Clang +// CHECK: char *PR52265_a() +__attribute__((malloc(my_cleanup_func))) char *PR52265_a(); +// CHECK: char *PR52265_b() +__attribute__((malloc(my_cleanup_func, 1))) char *PR52265_b(); + // CHECK: class __attribute__((consumable("unknown"))) AttrTester1 class __attribute__((consumable(unknown))) AttrTester1 { // CHECK: void callableWhen() __attribute__((callable_when("unconsumed", "consumed"))); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits