Skip to content

Support uninitialised fields for skipping pre-zeroing - #2

Open
BrianXu0623 wants to merge 9 commits into
cur_test_v2from
support_uninitialised_field_for_skipping_pre_zeroing
Open

Support uninitialised fields for skipping pre-zeroing#2
BrianXu0623 wants to merge 9 commits into
cur_test_v2from
support_uninitialised_field_for_skipping_pre_zeroing

Conversation

@BrianXu0623

@BrianXu0623 BrianXu0623 commented Dec 28, 2025

Copy link
Copy Markdown
Owner

Refers to issue capnproto#2400
Replaces capnproto#2423

Motivation

As discussed in issue capnproto#2400 and the previous PR capnproto#2423, the current memory allocation strategy (relying strictly on calloc or pre-zeroed memory) incurs a significant performance penalty for large allocations, specifically for large DATA blobs.

When a user allocates a large buffer (e.g., for file uploads or large serialized payloads) using the standard initData(), the memory is zeroed out by the allocator, only to be immediately overwritten by the user. This "double-write" (zeroing + copying) consumes unnecessary memory bandwidth and CPU cycles.

Proposed Changes

This PR introduces a non-invasive, opt-in mechanism to support Lazy Zeroing. Instead of fundamentally changing the allocator interface for all users, this change allows MallocMessageBuilder (and custom builders) to switch allocation strategies via a new configuration enum.

Key Changes

  1. MessageBuilder Base Class Update:

    • Added virtual bool needLazyZero() const. By default, it returns false, maintaining the existing behavior (allocators must return zeroed memory).
    • When overridden to return true, it changes the allocation contract: allocateSegment() is permitted to return uninitialized (dirty) memory.
    • In this mode, MessageBuilder takes responsibility for proactively zero-initializing Structs, Fields and Pointer Tables, ensuring safety.
  2. MallocMessageBuilder Update:

    • Introduced InitializationStrategy enum:
      • PRE_ZERO_MEMORY (Default): Uses calloc, strictly preserves legacy behavior and safety guarantees.
      • LAZY_ZERO_MEMORY: Uses malloc, returns dirty memory to avoid redundant OS-level zeroing.
    • Updated MallocMessageBuilder constructors to accept this new strategy.
  3. New API for DATA Fields:

    • Added support for uninitializedData() (or uninitializedFoo generated methods) for DATA type fields.
    • This API serves as the explicit signal from the caller to skip zeroing the data body.
    • When combined with InitializationStrategy::LAZY_ZERO_MEMORY, this avoids the "double-write" penalty while automatically ensuring that alignment padding bytes remain zeroed for security.

Usage Example

// Opt-in to the new LAZY_ZERO_MEMORY strategy
capnp::MallocMessageBuilder builder(
    1024, 
    capnp::AllocationStrategy::FIXED_SIZE, 
    capnp::MallocMessageBuilder::InitializationStrategy::LAZY_ZERO_MEMORY
);

auto root = builder.initRoot<MySchema>();

// Performance benefit:
// This allocation skips the memset cost for the body of the data.
// The memory remains "dirty" until overwritten by the user.
auto data = root.uninitializedFoo(10 * 1024 * 1024); // 10MB
memcpy(data.begin(), largeSourceBuffer, data.size());

Safety & Correctness

This PR strictly adheres to the safety requirements discussed in the previous PR to prevent information leaks or undefined behavior:

  • Structs & Pointer Tables: The MessageBuilder logic takes full responsibility for zero-initializing struct fields and pointer tables upon allocation. This guarantees deterministic behavior and valid pointers even when the underlying segment contains "dirty" memory.
  • Information Leak Prevention (Padding): For DATA blobs where zeroing is skipped (via uninitializedFoo), the logic strictly enforces zeroing of alignment padding bytes. This ensures that residual heap data does not leak into the wire format.
  • Backward Compatibility: The default InitializationStrategy remains PRE_ZERO_MEMORY. Existing codebases will see no behavioral change and will continue to receive zero-filled segments from the allocator by default.

@BrianXu0623 BrianXu0623 changed the title support_uninitialised_field_for_skipping_pre_zeroing Support uninitialised fields for skipping pre-zeroing Dec 29, 2025
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