[clang] [clang][Sema] Diagnose passing function pointer to `__builtin_assume_aligned` (PR #153552)
Victor Chernyakin via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 14 17:05:35 PDT 2025
https://github.com/localspook updated https://github.com/llvm/llvm-project/pull/153552
>From 63c02556bc65571a84e27debde2e2cfd724a0e9b Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Thu, 14 Aug 2025 00:52:37 -0700
Subject: [PATCH 1/2] [clang][Sema] Diagnose passing function pointer to
`__builtin_assume_aligned`
---
.../include/clang/Basic/DiagnosticSemaKinds.td | 3 ++-
clang/lib/Sema/SemaChecking.cpp | 5 +++--
clang/test/Sema/builtin-assume-aligned.c | 17 +++++++++--------
3 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 116341f4b66d5..f7f26ed6062b3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12829,7 +12829,8 @@ def err_builtin_launder_invalid_arg : Error<
"%select{non-pointer|function pointer|void pointer}0 argument to "
"'__builtin_launder' is not allowed">;
def err_builtin_assume_aligned_invalid_arg : Error<
- "non-pointer argument to '__builtin_assume_aligned' is not allowed">;
+ "%select{non-pointer|function pointer}0 argument to "
+ "'__builtin_assume_aligned' is not allowed">;
def err_builtin_is_within_lifetime_invalid_arg : Error<
"%select{non-|function }0pointer argument to '__builtin_is_within_lifetime' "
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 9ecee18661340..d8ad9f65c1995 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5660,9 +5660,10 @@ bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) {
{
ExprResult FirstArgResult =
DefaultFunctionArrayLvalueConversion(FirstArg);
- if (!FirstArgResult.get()->getType()->isPointerType()) {
+ QualType FirstArgType = FirstArgResult.get()->getType();
+ if (!FirstArgType->isObjectPointerType()) {
Diag(TheCall->getBeginLoc(), diag::err_builtin_assume_aligned_invalid_arg)
- << TheCall->getSourceRange();
+ << FirstArgType->isFunctionPointerType() << TheCall->getSourceRange();
return true;
}
TheCall->setArg(0, FirstArgResult.get());
diff --git a/clang/test/Sema/builtin-assume-aligned.c b/clang/test/Sema/builtin-assume-aligned.c
index 57378a3426524..c6d1197fe8ab4 100644
--- a/clang/test/Sema/builtin-assume-aligned.c
+++ b/clang/test/Sema/builtin-assume-aligned.c
@@ -77,18 +77,19 @@ int test14(int *a, int b) {
a = (int *)__builtin_assume_aligned(b, 32); // expected-error {{non-pointer argument to '__builtin_assume_aligned' is not allowed}}
}
-int test15(int *b) {
- int arr[3] = {1, 2, 3};
- b = (int *)__builtin_assume_aligned(arr, 32);
- return b[0];
+void test15(void (*f)()) {
+ f = (void (*)())__builtin_assume_aligned(f, 32); // expected-error {{function pointer argument to '__builtin_assume_aligned' is not allowed}}
}
-int val(int x) {
- return x;
+void foo();
+
+void test16(void (*f)()) {
+ f = (void (*)())__builtin_assume_aligned(foo, 32); // expected-error {{function pointer argument to '__builtin_assume_aligned' is not allowed}}
}
-int test16(int *b) {
- b = (int *)__builtin_assume_aligned(val, 32);
+int test17(int *b) {
+ int arr[3] = {1, 2, 3};
+ b = (int *)__builtin_assume_aligned(arr, 32);
return b[0];
}
>From 0349a05a726efd80add99067a42acef2cb56b3bc Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Thu, 14 Aug 2025 17:05:14 -0700
Subject: [PATCH 2/2] Use `checkBuiltinArgument`, add release notes
---
clang/docs/ReleaseNotes.rst | 3 +++
.../include/clang/Basic/DiagnosticSemaKinds.td | 3 ---
clang/lib/Sema/SemaChecking.cpp | 18 +++---------------
.../CodeGen/catch-alignment-assumption-array.c | 2 +-
...ion-builtin_assume_aligned-polymorphism.cpp | 2 +-
...in_assume_aligned-three-params-variable.cpp | 2 +-
...ion-builtin_assume_aligned-three-params.cpp | 2 +-
...ption-builtin_assume_aligned-two-params.cpp | 2 +-
.../catch-alignment-assumption-ignorelist.c | 2 ++
.../Sema/builtin-assume-aligned-downgrade.c | 9 ---------
clang/test/Sema/builtin-assume-aligned.c | 7 ++++---
clang/test/SemaCXX/builtin-assume-aligned.cpp | 13 +++++++++++++
12 files changed, 30 insertions(+), 35 deletions(-)
delete mode 100644 clang/test/Sema/builtin-assume-aligned-downgrade.c
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a8b7a29933945..ec93e4d0629c2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -170,6 +170,9 @@ Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fix an ambiguous reference to the builtin `type_info` (available when using
`-fms-compatibility`) with modules. (#GH38400)
+- Make the pointer parameter to `__builtin_assume_aligned` undergo conversions
+ like any normal argument. This means that integer to pointer conversions are now
+ allowed, and passing function pointers is now diagnosed.
Bug Fixes to Attribute Support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f7f26ed6062b3..e12f19c819072 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12828,9 +12828,6 @@ def warn_cast_discards_cfi_unchecked_callee
def err_builtin_launder_invalid_arg : Error<
"%select{non-pointer|function pointer|void pointer}0 argument to "
"'__builtin_launder' is not allowed">;
-def err_builtin_assume_aligned_invalid_arg : Error<
- "%select{non-pointer|function pointer}0 argument to "
- "'__builtin_assume_aligned' is not allowed">;
def err_builtin_is_within_lifetime_invalid_arg : Error<
"%select{non-|function }0pointer argument to '__builtin_is_within_lifetime' "
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index d8ad9f65c1995..4ba5d978508d7 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5654,20 +5654,8 @@ bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) {
if (checkArgCountRange(TheCall, 2, 3))
return true;
- unsigned NumArgs = TheCall->getNumArgs();
- Expr *FirstArg = TheCall->getArg(0);
-
- {
- ExprResult FirstArgResult =
- DefaultFunctionArrayLvalueConversion(FirstArg);
- QualType FirstArgType = FirstArgResult.get()->getType();
- if (!FirstArgType->isObjectPointerType()) {
- Diag(TheCall->getBeginLoc(), diag::err_builtin_assume_aligned_invalid_arg)
- << FirstArgType->isFunctionPointerType() << TheCall->getSourceRange();
- return true;
- }
- TheCall->setArg(0, FirstArgResult.get());
- }
+ if (checkBuiltinArgument(*this, TheCall, 0))
+ return true;
// The alignment must be a constant integer.
Expr *SecondArg = TheCall->getArg(1);
@@ -5687,7 +5675,7 @@ bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) {
<< SecondArg->getSourceRange() << Sema::MaximumAlignment;
}
- if (NumArgs > 2) {
+ if (TheCall->getNumArgs() > 2) {
Expr *ThirdArg = TheCall->getArg(2);
if (convertArgumentToType(*this, ThirdArg, Context.getSizeType()))
return true;
diff --git a/clang/test/CodeGen/catch-alignment-assumption-array.c b/clang/test/CodeGen/catch-alignment-assumption-array.c
index 413068ecde42d..efbb3206a7042 100644
--- a/clang/test/CodeGen/catch-alignment-assumption-array.c
+++ b/clang/test/CodeGen/catch-alignment-assumption-array.c
@@ -3,7 +3,7 @@
// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER
// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE
-// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char *'\00" }
+// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'const void *'\00" }
// CHECK-SANITIZE-ANYRECOVER: @[[ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 30, i32 35 }, {{.*}} @[[CHAR]] }
void *caller(void) {
diff --git a/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-polymorphism.cpp b/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-polymorphism.cpp
index e40c0f3ce95d6..a8afc86ae83cb 100644
--- a/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-polymorphism.cpp
+++ b/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-polymorphism.cpp
@@ -3,7 +3,7 @@
// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER
// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE
-// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'B *'\00" }
+// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'const void *'\00" }
// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 35 }, {{.*}} @[[CHAR]] }
struct A { int n; };
diff --git a/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params-variable.cpp b/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params-variable.cpp
index 01934010a4c08..01562c868714a 100644
--- a/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params-variable.cpp
+++ b/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params-variable.cpp
@@ -3,7 +3,7 @@
// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER
// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE
-// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char **'\00" }
+// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'const void *'\00" }
// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 35 }, {{.*}} @[[CHAR]] }
void *caller(char **x, unsigned long offset) {
diff --git a/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params.cpp b/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params.cpp
index 5d5cef116b862..00a23e2d6d87f 100644
--- a/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params.cpp
+++ b/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params.cpp
@@ -3,7 +3,7 @@
// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER
// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE
-// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char **'\00" }
+// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'const void *'\00" }
// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 35 }, {{.*}} @[[CHAR]] }
void *caller(char **x) {
diff --git a/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-two-params.cpp b/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-two-params.cpp
index 3934c41f58618..4fed0d10dd67c 100644
--- a/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-two-params.cpp
+++ b/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-two-params.cpp
@@ -3,7 +3,7 @@
// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER
// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE
-// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char **'\00" }
+// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'const void *'\00" }
// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 35 }, {{.*}} @[[CHAR]] }
void *caller(char **x) {
diff --git a/clang/test/CodeGen/catch-alignment-assumption-ignorelist.c b/clang/test/CodeGen/catch-alignment-assumption-ignorelist.c
index 9087c26e98f3d..992f4d8d622df 100644
--- a/clang/test/CodeGen/catch-alignment-assumption-ignorelist.c
+++ b/clang/test/CodeGen/catch-alignment-assumption-ignorelist.c
@@ -24,11 +24,13 @@ void *dont_ignore_volatile_ptrs(void * volatile x) {
// CHECK-LABEL: ignore_volatiles
void *ignore_volatiles(volatile void * x) {
+ // CHECK: call void @__ubsan_handle_alignment_assumption(
return __builtin_assume_aligned(x, 1);
}
// CHECK-LABEL: ignore_array_volatiles
void *ignore_array_volatiles() {
volatile int arr[] = {1};
+ // CHECK: call void @__ubsan_handle_alignment_assumption(
return __builtin_assume_aligned(arr, 4);
}
diff --git a/clang/test/Sema/builtin-assume-aligned-downgrade.c b/clang/test/Sema/builtin-assume-aligned-downgrade.c
deleted file mode 100644
index 93631e7364373..0000000000000
--- a/clang/test/Sema/builtin-assume-aligned-downgrade.c
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -Wno-int-conversion -triple x86_64-linux -verify %s
-
-// Check that the pointer->int conversion error is not downgradable for the
-// pointer argument to __builtin_assume_aligned.
-
-int test(int *a, int b) {
- a = (int *)__builtin_assume_aligned(b, 32); // expected-error {{non-pointer argument to '__builtin_assume_aligned' is not allowed}}
- int *y = __builtin_assume_aligned(1, 1); // expected-error {{non-pointer argument to '__builtin_assume_aligned' is not allowed}}
-}
diff --git a/clang/test/Sema/builtin-assume-aligned.c b/clang/test/Sema/builtin-assume-aligned.c
index c6d1197fe8ab4..0768d4b47d620 100644
--- a/clang/test/Sema/builtin-assume-aligned.c
+++ b/clang/test/Sema/builtin-assume-aligned.c
@@ -74,17 +74,18 @@ int test13(int *a) {
}
int test14(int *a, int b) {
- a = (int *)__builtin_assume_aligned(b, 32); // expected-error {{non-pointer argument to '__builtin_assume_aligned' is not allowed}}
+ a = (int *)__builtin_assume_aligned(b, 32); // expected-error {{incompatible integer to pointer conversion passing 'int' to parameter of type 'const void *'}}
+ void *y = __builtin_assume_aligned(1, 1); // expected-error {{incompatible integer to pointer conversion passing 'int' to parameter of type 'const void *'}}
}
void test15(void (*f)()) {
- f = (void (*)())__builtin_assume_aligned(f, 32); // expected-error {{function pointer argument to '__builtin_assume_aligned' is not allowed}}
+ f = (void (*)())__builtin_assume_aligned(f, 32);
}
void foo();
void test16(void (*f)()) {
- f = (void (*)())__builtin_assume_aligned(foo, 32); // expected-error {{function pointer argument to '__builtin_assume_aligned' is not allowed}}
+ f = (void (*)())__builtin_assume_aligned(foo, 32);
}
int test17(int *b) {
diff --git a/clang/test/SemaCXX/builtin-assume-aligned.cpp b/clang/test/SemaCXX/builtin-assume-aligned.cpp
index 48bd8414fc50a..e2f8736a47a91 100644
--- a/clang/test/SemaCXX/builtin-assume-aligned.cpp
+++ b/clang/test/SemaCXX/builtin-assume-aligned.cpp
@@ -47,3 +47,16 @@ constexpr void *s1 = __builtin_assume_aligned(x, 32);
constexpr void *s2 = __builtin_assume_aligned(x, 32, 5);
constexpr void *s3 = __builtin_assume_aligned(x, 32, -1);
+void (*f)();
+// expected-error at +1 {{cannot initialize a parameter of type 'const void *' with an lvalue of type 'void (*)()'}}
+constexpr void * f1 = __builtin_assume_aligned(f, 32);
+
+void foo();
+// expected-error at +1 {{cannot initialize a parameter of type 'const void *' with an lvalue of type 'void ()'}}
+constexpr void * f2 = __builtin_assume_aligned(foo, 32);
+
+constexpr void * null_ptr1 = __builtin_assume_aligned(0, 32);
+constexpr void * null_ptr2 = __builtin_assume_aligned(nullptr, 32);
+
+// expected-error at +1 {{cannot initialize a parameter of type 'const void *' with an rvalue of type 'int'}}
+constexpr void * not_null_ptr = __builtin_assume_aligned(1, 32);
More information about the cfe-commits
mailing list