[clang] [compiler-rt] [clang][SemaCXX] Fixed a crash when returning an initialization to a top-level deleted function (PR #210973)
Rajveer Singh Bharadwaj via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 21 06:30:08 PDT 2026
https://github.com/Rajveer100 updated https://github.com/llvm/llvm-project/pull/210973
>From e1656df3890c0cd1e8e796573f31fac0a3bb75af Mon Sep 17 00:00:00 2001
From: Rajveer <rajveer.developer at icloud.com>
Date: Tue, 21 Jul 2026 18:07:30 +0530
Subject: [PATCH 1/2] [clang][SemaCXX] Fixed a crash when returning an
initialization to a top-level deleted function
Resolves #208488
This crash is caused due to requesting declaration alignment for
undeduced types like `auto`.
---
clang/docs/ReleaseNotes.md | 2 ++
clang/lib/Sema/SemaStmt.cpp | 7 +++++++
clang/test/SemaCXX/deleted-function-return.cpp | 8 ++++++++
3 files changed, 17 insertions(+)
create mode 100644 clang/test/SemaCXX/deleted-function-return.cpp
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 28fea9a99b609..d8943d6af7a7d 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -334,6 +334,8 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
`[](Types... = args...) {}`). Clang now diagnoses the illegal default
argument instead of asserting. (#GH210714)
+- Fixed a crash when returning an initialization to a top-level deleted function. (#GH208488)
+
#### Bug Fixes to AST Handling
- Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index cc325620883f0..83e0eb9caadca 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -3545,6 +3545,13 @@ Sema::NamedReturnInfo Sema::getNamedReturnInfo(const VarDecl *VD) {
return NamedReturnInfo();
}
+ const Type *T = VDType.getTypePtr();
+ if (T->getTypeClass() == Type::Auto) {
+ const auto *A = cast<DeducedType>(T);
+ if (A->isUndeducedAutoType())
+ return NamedReturnInfo();
+ }
+
// Variables with higher required alignment than their type's ABI
// alignment cannot use NRVO.
if (!VD->hasDependentAlignment() && !VDType->isIncompleteType() &&
diff --git a/clang/test/SemaCXX/deleted-function-return.cpp b/clang/test/SemaCXX/deleted-function-return.cpp
new file mode 100644
index 0000000000000..9320b85cd1dc8
--- /dev/null
+++ b/clang/test/SemaCXX/deleted-function-return.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only %s
+
+auto f() = delete; // expected-note {{candidate function has been explicitly deleted}}
+
+auto g() {
+ auto x = f(); // expected-error {{call to deleted function 'f'}}
+ return x;
+}
>From 3820e62ad8399b0a45755594a29f80e1ba85ed66 Mon Sep 17 00:00:00 2001
From: Dan Blackwell <dan_blackwell at apple.com>
Date: Tue, 21 Jul 2026 14:08:51 +0100
Subject: [PATCH 2/2] [Darwin][TSan] Fix race in mach_vm_deallocate interceptor
(#210716)
I have seen an issue whereby the meta store in MetaMap::AllocBlock lands
in the unmapped gap left during the tsan::MetaMap::ResetRange call;
where the range is first unmapped, and then remapped with MAP_FIXED.
This occurred under the mach_vm_deallocate interceptor, because it first
does the deallocate call, and only then does it call UnmapShadow -
leaving a gap where a fresh slab for malloc can land, only to have the
meta region for that range mapped out from under it, resulting in a bad
access fault.
It is worth noting that there is a comment above the IsValidMmapRange
function (which gets called during UnmapShadow), that describes this
exact issue in the context of munmap.
rdar://179172055
Assisted by: Claude
---
.../test/SemaCXX/deleted-function-return.cpp | 7 ++-
.../tsan/rtl/tsan_interceptors_mach_vm.cpp | 5 +-
.../tsan/Darwin/mach_vm_deallocate_race.c | 57 +++++++++++++++++++
3 files changed, 65 insertions(+), 4 deletions(-)
create mode 100644 compiler-rt/test/tsan/Darwin/mach_vm_deallocate_race.c
diff --git a/clang/test/SemaCXX/deleted-function-return.cpp b/clang/test/SemaCXX/deleted-function-return.cpp
index 9320b85cd1dc8..a0dd145ec0ec9 100644
--- a/clang/test/SemaCXX/deleted-function-return.cpp
+++ b/clang/test/SemaCXX/deleted-function-return.cpp
@@ -2,7 +2,12 @@
auto f() = delete; // expected-note {{candidate function has been explicitly deleted}}
-auto g() {
+auto g1() {
auto x = f(); // expected-error {{call to deleted function 'f'}}
return x;
}
+
+auto g2() {
+ decltype(auto) x = f(); // expected-error {{call to deleted function 'f'}}
+ return x;
+}
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_mach_vm.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_mach_vm.cpp
index 6d62ff6a83825..4b0c86d772b5a 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_mach_vm.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_mach_vm.cpp
@@ -44,10 +44,9 @@ TSAN_INTERCEPTOR(kern_return_t, mach_vm_deallocate, vm_map_t target,
SCOPED_TSAN_INTERCEPTOR(mach_vm_deallocate, target, address, size);
if (target != mach_task_self())
return REAL(mach_vm_deallocate)(target, address, size);
- kern_return_t kr = REAL(mach_vm_deallocate)(target, address, size);
- if (kr == KERN_SUCCESS && address)
+ if (address)
UnmapShadow(thr, address, size);
- return kr;
+ return REAL(mach_vm_deallocate)(target, address, size);
}
} // namespace __tsan
diff --git a/compiler-rt/test/tsan/Darwin/mach_vm_deallocate_race.c b/compiler-rt/test/tsan/Darwin/mach_vm_deallocate_race.c
new file mode 100644
index 0000000000000..ccbe8173922ee
--- /dev/null
+++ b/compiler-rt/test/tsan/Darwin/mach_vm_deallocate_race.c
@@ -0,0 +1,57 @@
+// Test that concurrent mach_vm_deallocate / mach_vm_allocate on the same
+// virtual address range do not race in the TSan runtime's shadow/meta reset.
+//
+// Several threads free a region while others reuse the same VA (via an address
+// hint) and touch it. If mach_vm_deallocate resets the shadow/meta *after* the
+// real deallocation, the freed VA can be handed to a reusing thread mid reset
+// -> SEGV at a meta address (or clobbered metadata). Resetting before the real
+// deallocation (while we still own the mapping) avoids this.
+//
+// RUN: %clang_tsan %s -o %t
+// RUN: %env_tsan_opts=abort_on_error=0 %run %t 2>&1 | FileCheck %s
+
+// UNSUPPORTED: iossim
+
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <pthread.h>
+#include <stdio.h>
+
+static const mach_vm_size_t kSize =
+ 16 << 20; // >128KB forces ResetRange unmap path
+static const int kThreads = 4;
+static const long kIters = 1000;
+static mach_vm_address_t g_hint; // shared placement hint (the contended VA)
+
+static void *worker(void *arg) {
+ for (long i = 0; i < kIters; i++) {
+ mach_vm_address_t a = g_hint; // prefer the just-freed VA
+ if (mach_vm_allocate(mach_task_self(), &a, kSize, VM_FLAGS_ANYWHERE) !=
+ KERN_SUCCESS)
+ continue;
+ *(volatile char *)a = 1; // touch to check for faults
+ mach_vm_deallocate(mach_task_self(), a, kSize);
+ }
+ return NULL;
+}
+
+int main(void) {
+ mach_vm_address_t a = 0;
+ if (mach_vm_allocate(mach_task_self(), &a, kSize, VM_FLAGS_ANYWHERE) !=
+ KERN_SUCCESS)
+ return 1;
+ g_hint = a;
+ mach_vm_deallocate(mach_task_self(), a, kSize);
+
+ pthread_t t[kThreads];
+ for (int i = 0; i < kThreads; i++)
+ pthread_create(&t[i], NULL, worker, NULL);
+ for (int i = 0; i < kThreads; i++)
+ pthread_join(t[i], NULL);
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK-NOT: ThreadSanitizer
+// CHECK: Done.
More information about the cfe-commits
mailing list