Skip to content

[V4] No allocation for exceptions#89

Merged
ConorWilliams merged 10 commits intomodulesfrom
v4-no-alloc-exception
Apr 6, 2026
Merged

[V4] No allocation for exceptions#89
ConorWilliams merged 10 commits intomodulesfrom
v4-no-alloc-exception

Conversation

@ConorWilliams
Copy link
Copy Markdown
Owner

@ConorWilliams ConorWilliams commented Apr 6, 2026

Motivated by desire to keep every allocation customizable

Summary by CodeRabbit

  • New Features

    • Added a new uninitialized utility module for managing uninitialized object storage with type-safe construction and destruction.
  • Refactor

    • Improved internal exception handling mechanism to enhance reliability and clarity in exception state management.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 6, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 32642456-7c67-473c-83a1-eb224d6a5df7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v4-no-alloc-exception

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ConorWilliams ConorWilliams changed the base branch from main to modules April 6, 2026 12:21
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/core/promise.cxx (1)

218-219: Acknowledge TODO: Exception cancel-safety needs attention.

The comment notes potential cancellation leakage. If a frame with a stashed exception is cancelled before extract_exception is called, the uninitialized<std::exception_ptr> storage may never be destroyed, leaking the exception state. Consider tracking this as a follow-up issue.

Would you like me to open an issue to track the exception/cancellation interaction?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/promise.cxx` around lines 218 - 219, Add a follow-up issue to track
and resolve exception cancel-safety referenced by the TODO in
src/core/promise.cxx: note that a stashed exception stored in
uninitialized<std::exception_ptr> can leak if a frame is cancelled before
extract_exception() runs, describe the potential leak scenario and desired
outcomes (e.g., ensure stored exception is destroyed on cancellation, or make
storage RAII/cancel-safe), include reproduction steps or unit-test ideas, and
link the issue to the TODO comment so it can be picked up later.
src/utils/uninitialized.cxx (1)

23-23: Consider simplifying pointer access.

The expression std::bit_cast<T*>(auto{buffer}) works because auto{buffer} decays the array to std::byte*, but it's unconventional. A more idiomatic approach:

♻️ Simplified pointer access
- auto operator->() noexcept -> T * { return std::launder(std::bit_cast<T *>(auto{buffer})); }
+ auto operator->() noexcept -> T * { return std::launder(reinterpret_cast<T *>(buffer)); }

Note: If constexpr support is desired in the future (per the TODO about trivial union), the current bit_cast approach won't help since reinterpret_cast and pointer bit_cast aren't constexpr anyway—only the trivial union approach would enable that.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/uninitialized.cxx` at line 23, The operator-> implementation uses
an unconventional std::bit_cast of auto{buffer}; change it to a conventional
pointer reinterpretation: return std::launder(reinterpret_cast<T*>(buffer)); so
locate operator-> (the auto operator->() noexcept -> T * function) and replace
the std::bit_cast(auto{buffer}) expression with a reinterpret_cast to T* of the
internal buffer variable; keep std::launder and noexcept as-is and ensure buffer
refers to the stored std::byte array used by this uninitialized wrapper.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/utils/uninitialized.cxx`:
- Around line 10-37: The buffer is incorrectly fixed to sizeof(std::max_align_t)
which can overflow for T; change the storage to be sized and aligned for T by
replacing the private member buffer with "alignas(alignof(T)) std::byte
buffer[sizeof(T)];" and add a compile-time check (e.g., static_assert(sizeof(T)
>= 1, "T must be complete") or static_assert(std::is_trivially_destructible_v<T>
|| true) as needed) to ensure T is a complete type; update usages (operator->,
construct, destroy) remain the same as they rely on buffer being correctly
sized/aligned in class uninitialized.

---

Nitpick comments:
In `@src/core/promise.cxx`:
- Around line 218-219: Add a follow-up issue to track and resolve exception
cancel-safety referenced by the TODO in src/core/promise.cxx: note that a
stashed exception stored in uninitialized<std::exception_ptr> can leak if a
frame is cancelled before extract_exception() runs, describe the potential leak
scenario and desired outcomes (e.g., ensure stored exception is destroyed on
cancellation, or make storage RAII/cancel-safe), include reproduction steps or
unit-test ideas, and link the issue to the TODO comment so it can be picked up
later.

In `@src/utils/uninitialized.cxx`:
- Line 23: The operator-> implementation uses an unconventional std::bit_cast of
auto{buffer}; change it to a conventional pointer reinterpretation: return
std::launder(reinterpret_cast<T*>(buffer)); so locate operator-> (the auto
operator->() noexcept -> T * function) and replace the
std::bit_cast(auto{buffer}) expression with a reinterpret_cast to T* of the
internal buffer variable; keep std::launder and noexcept as-is and ensure buffer
refers to the stored std::byte array used by this uninitialized wrapper.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 34d86898-763b-41e6-8175-6994fb32936e

📥 Commits

Reviewing files that changed from the base of the PR and between 4c52e08 and fbb6770.

📒 Files selected for processing (5)
  • CMakeLists.txt
  • src/core/frame.cxx
  • src/core/promise.cxx
  • src/utils/uninitialized.cxx
  • src/utils/utils.cxx

@ConorWilliams ConorWilliams force-pushed the v4-no-alloc-exception branch from 901158c to 2741d30 Compare April 6, 2026 13:09
@ConorWilliams ConorWilliams merged commit fe1130b into modules Apr 6, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant