From c2c88e1f82e3d5981aff57873b08ff8b1d1e5cc6 Mon Sep 17 00:00:00 2001
From: Petr Shumilov
Date: Tue, 19 May 2026 19:43:34 +0300
Subject: [PATCH 1/4] Use alloc_align for coroutine frame allocation
Signed-off-by: Petr Shumilov
---
compiler/compiler-settings.cpp | 5 +++++
runtime-light/coroutine/task.h | 7 ++++++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/compiler/compiler-settings.cpp b/compiler/compiler-settings.cpp
index d096a120ac..2afde09710 100644
--- a/compiler/compiler-settings.cpp
+++ b/compiler/compiler-settings.cpp
@@ -340,6 +340,11 @@ void CompilerSettings::init() {
if (!dynamic_incremental_linkage.get()) {
ss << " -fvisibility=hidden";
}
+ if (vk::contains(cxx.get(), "clang")) {
+ // To avoid undefined behavior, the coroutine frame must be allocated using the aligned operator new overload (the one that takes a std::align_val_t)
+ // Details: https://github.com/llvm/llvm-project/commit/327141fb1d8ca35b323107a43d57886eb77e7384
+ ss << " -fcoro-aligned-allocation";
+ }
// Temporary solution. Required for allocator functions replacement in timelib
ss << " -DTIMELIB_ALLOC_FUNC_PREFIX=timelib_";
} else {
diff --git a/runtime-light/coroutine/task.h b/runtime-light/coroutine/task.h
index 7ba3fb2041..c64fe8c13e 100644
--- a/runtime-light/coroutine/task.h
+++ b/runtime-light/coroutine/task.h
@@ -69,7 +69,12 @@ struct promise_base : kphp::coro::async_stack_element {
return kphp::memory::script::alloc(n);
}
- auto operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept -> void {
+ template
+ auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* {
+ return kphp::memory::script::alloc_aligned(n, al);
+ }
+
+ auto operator delete([[maybe_unused]] void* ptr, [[maybe_unused]] size_t n) noexcept -> void {
kphp::memory::script::free(ptr);
}
From 34c31f395424426486c57f83f68405279187fe10 Mon Sep 17 00:00:00 2001
From: Petr Shumilov
Date: Wed, 20 May 2026 15:09:41 +0300
Subject: [PATCH 2/4] Add test
Signed-off-by: Petr Shumilov
---
.../phpt/fork/043_sched_yield_in_callback.php | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
create mode 100644 tests/phpt/fork/043_sched_yield_in_callback.php
diff --git a/tests/phpt/fork/043_sched_yield_in_callback.php b/tests/phpt/fork/043_sched_yield_in_callback.php
new file mode 100644
index 0000000000..7a7f847bbf
--- /dev/null
+++ b/tests/phpt/fork/043_sched_yield_in_callback.php
@@ -0,0 +1,21 @@
+@ok
+
Date: Wed, 20 May 2026 16:35:53 +0300
Subject: [PATCH 3/4] Use alloc_align for all coroutine-related heap-allocated
types
Signed-off-by: Petr Shumilov
---
runtime-light/coroutine/detail/await-set.h | 10 ++++++++++
runtime-light/coroutine/detail/task-self-deleting.h | 5 +++++
runtime-light/coroutine/detail/when-all.h | 5 +++++
runtime-light/coroutine/detail/when-any.h | 5 +++++
runtime-light/coroutine/shared-task.h | 5 +++++
runtime-light/coroutine/task.h | 2 +-
6 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/runtime-light/coroutine/detail/await-set.h b/runtime-light/coroutine/detail/await-set.h
index 2edbd086e4..2c05be0c6e 100644
--- a/runtime-light/coroutine/detail/await-set.h
+++ b/runtime-light/coroutine/detail/await-set.h
@@ -61,6 +61,11 @@ class await_broker {
return kphp::memory::script::alloc(n);
}
+ template
+ auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* {
+ return kphp::memory::script::alloc_aligned(n, al);
+ }
+
void operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept {
kphp::memory::script::free(ptr);
}
@@ -168,6 +173,11 @@ class await_set_task_promise_base : public kphp::coro::async_stack_element {
return kphp::memory::script::alloc(n);
}
+ template
+ auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* {
+ return kphp::memory::script::alloc_aligned(n, al);
+ }
+
void operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept {
kphp::memory::script::free(ptr);
}
diff --git a/runtime-light/coroutine/detail/task-self-deleting.h b/runtime-light/coroutine/detail/task-self-deleting.h
index daa72cdd17..3ff19f1831 100644
--- a/runtime-light/coroutine/detail/task-self-deleting.h
+++ b/runtime-light/coroutine/detail/task-self-deleting.h
@@ -35,6 +35,11 @@ struct promise_self_deleting : kphp::coro::async_stack_element {
return kphp::memory::script::alloc(n);
}
+ template
+ auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* {
+ return kphp::memory::script::alloc_aligned(n, al);
+ }
+
auto operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept -> void {
kphp::memory::script::free(ptr);
}
diff --git a/runtime-light/coroutine/detail/when-all.h b/runtime-light/coroutine/detail/when-all.h
index cc276f7996..2386e4fbb6 100644
--- a/runtime-light/coroutine/detail/when-all.h
+++ b/runtime-light/coroutine/detail/when-all.h
@@ -155,6 +155,11 @@ class when_all_task_promise_base : public kphp::coro::async_stack_element {
return kphp::memory::script::alloc(n);
}
+ template
+ auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* {
+ return kphp::memory::script::alloc_aligned(n, al);
+ }
+
auto operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept -> void {
kphp::memory::script::free(ptr);
}
diff --git a/runtime-light/coroutine/detail/when-any.h b/runtime-light/coroutine/detail/when-any.h
index 2d7df28e37..f5ee01549e 100644
--- a/runtime-light/coroutine/detail/when-any.h
+++ b/runtime-light/coroutine/detail/when-any.h
@@ -165,6 +165,11 @@ class when_any_task_promise_base : public kphp::coro::async_stack_element {
return kphp::memory::script::alloc(n);
}
+ template
+ auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* {
+ return kphp::memory::script::alloc_aligned(n, al);
+ }
+
auto operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept -> void {
kphp::memory::script::free(ptr);
}
diff --git a/runtime-light/coroutine/shared-task.h b/runtime-light/coroutine/shared-task.h
index c0a3c1cc29..ddec603c58 100644
--- a/runtime-light/coroutine/shared-task.h
+++ b/runtime-light/coroutine/shared-task.h
@@ -148,6 +148,11 @@ struct promise_base : kphp::coro::async_stack_element {
return kphp::memory::script::alloc(n);
}
+ template
+ auto operator new(size_t n, std::align_val_t al, [[maybe_unused]] Args&&... args) noexcept -> void* {
+ return kphp::memory::script::alloc_aligned(n, al);
+ }
+
auto operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept -> void {
kphp::memory::script::free(ptr);
}
diff --git a/runtime-light/coroutine/task.h b/runtime-light/coroutine/task.h
index c64fe8c13e..d5c064720b 100644
--- a/runtime-light/coroutine/task.h
+++ b/runtime-light/coroutine/task.h
@@ -74,7 +74,7 @@ struct promise_base : kphp::coro::async_stack_element {
return kphp::memory::script::alloc_aligned(n, al);
}
- auto operator delete([[maybe_unused]] void* ptr, [[maybe_unused]] size_t n) noexcept -> void {
+ auto operator delete(void* ptr, [[maybe_unused]] size_t n) noexcept -> void {
kphp::memory::script::free(ptr);
}
From c91f0dddaeccd1c779a03fe172e0a55046f406bd Mon Sep 17 00:00:00 2001
From: Petr Shumilov
Date: Wed, 20 May 2026 17:35:31 +0300
Subject: [PATCH 4/4] Add -fcoro-aligned-allocation into cmake
Signed-off-by: Petr Shumilov
---
runtime-light/runtime-light.cmake | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/runtime-light/runtime-light.cmake b/runtime-light/runtime-light.cmake
index 3b5494afd4..e5df2f323d 100644
--- a/runtime-light/runtime-light.cmake
+++ b/runtime-light/runtime-light.cmake
@@ -2,7 +2,7 @@ include(${THIRD_PARTY_DIR}/pcre2-cmake/pcre2.cmake)
# =================================================================================================
-set(RUNTIME_LIGHT_COMPILE_FLAGS -stdlib=libc++ ${RUNTIME_LIGHT_VISIBILITY})
+set(RUNTIME_LIGHT_COMPILE_FLAGS -stdlib=libc++ -fcoro-aligned-allocation ${RUNTIME_LIGHT_VISIBILITY})
set(RUNTIME_LIGHT_PLATFORM_SPECIFIC_LINK_FLAGS)
if(APPLE)