Skip to content

Preallocate binary joins and preserve buffer lifetimes - #8880

Merged
youknowone merged 1 commit into
RustPython:mainfrom
1ndahous3:binary_join_buffers
Sep 28, 2026
Merged

youknowone merged 1 commit into
RustPython:mainfrom
1ndahous3:binary_join_buffers

Conversation

@1ndahous3

@1ndahous3 1ndahous3 commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Exhaust generic iterables before validating join items, preserving producer exceptions and final contents of mutable chunks in str, bytes and bytearray joins.
  • Preallocate binary join results and copy each input buffer once; reuse an exact single bytes item.
  • Keep input buffers exported through copying and protect bytearray separators against resizing while allowing same-size mutations. Detect input lists resized by buffer exporters.

Follow-up to #8826.

Performance

Windows 11 x64

Operation Before After Speedup
bytes.join, 256 × 64-byte chunks 21.40 µs 6.16 µs 3.5×
bytes.join, 256 × 4 KiB chunks 143.71 µs 22.61 µs 6.4×
bytearray.join, 256 × 4 KiB chunks 145.77 µs 23.65 µs 6.2×
bytes.join, 64 × 4 KiB bytearray chunks 26.23 µs 12.19 µs 2.2×

AI assistance

Written with Codex (GPT-6), reviewed by a human before submission.

Summary by CodeRabbit

  • Bug Fixes
    • bytes.join and bytearray.join now handle mutable inputs consistently while iterating. Resizing a bytearray separator during iteration raises BufferError, while same-size content changes are reflected in the result.
    • Joining propagates errors raised by an iterable, including for str.join.
    • Invalid join items and changes to a sequence’s size during joining are handled with clearer errors.

@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: RustPython/RustPython/.coderabbit.yml

Review profile: CHILL

Plan: Advanced

Run ID: 56346ab4-78d0-4fbc-b4c4-c5e6e092f1dd

📥 Commits

Reviewing files that changed from the base of the PR and between 908368e and f7cbcd0.

📒 Files selected for processing (8)
  • crates/vm/src/anystr.rs
  • crates/vm/src/builtins/bytearray.rs
  • crates/vm/src/builtins/bytes.rs
  • crates/vm/src/builtins/str.rs
  • crates/vm/src/bytes_inner.rs
  • extra_tests/snippets/builtin_bytearray.py
  • extra_tests/snippets/builtin_bytes.py
  • extra_tests/snippets/builtin_str.py
💤 Files with no reviewable changes (1)
  • crates/vm/src/anystr.rs

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

Join handling for bytes, bytearray, and str now uses updated iterable processing. Bytes and bytearray share BytesJoin, which validates buffer items and assembles output while handling mutable inputs. Tests cover iterator errors, buffer behavior, separator mutation, and single-item bytes identity.

Changes

Join processing

Layer / File(s) Summary
Shared bytes join processing
crates/vm/src/bytes_inner.rs, crates/vm/src/anystr.rs
BytesJoin retains exact lists and tuples, materializes other iterables, and processes exact bytes or contiguous buffer items. The previous PyBytesInner::join and AnyStr::py_join helpers are removed.
Bytes and bytearray join integration
crates/vm/src/builtins/bytes.rs, crates/vm/src/builtins/bytearray.rs, extra_tests/snippets/builtin_bytes.py, extra_tests/snippets/builtin_bytearray.py
bytes.join returns a sole exact bytes item directly or joins through BytesJoin. bytearray.join exports its separator during iteration. Tests cover mutable inputs, iterator errors, buffer behavior, and separator mutation.
str iterable collection
crates/vm/src/builtins/str.rs, extra_tests/snippets/builtin_str.py
str.join collects its sized iterable into a vector and calls join_items. A test checks propagation of an iterator exception.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant PyBytesJoin
  participant BytesJoin
  participant Iterable
  participant BufferProtocol
  Caller->>PyBytesJoin: Call join with iterable
  PyBytesJoin->>BytesJoin: Create join state
  BytesJoin->>Iterable: Materialize items when needed
  BytesJoin->>BufferProtocol: Acquire contiguous item buffers
  BufferProtocol-->>BytesJoin: Return item buffers
  BytesJoin->>BytesJoin: Read separator and assemble output
  BytesJoin-->>Caller: Return joined bytes
Loading

Merge Risk: ⚪ Minimal · up to f7cbc

No actionable issue remains in the reviewed join changes; the PR is mergeable after normal checks.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to f7cbc

General iterables are now fully consumed before join items are validated. Where an application passes a large or nonterminating iterable to join, an invalid early item may no longer stop processing promptly. No application-facing route for such input has been established. The changed buffer handling has explicit protections for resizing and cleanup.

Retained concerns

  • Medium · security · inferred: For a general iterable, join now drains the producer before rejecting an invalid early item. If an application supplies attacker-influenced iterables without a work limit, that ordering can increase memory use or prevent prompt termination.
Security review details

Security Blast Radius

  • inferred — The demonstrated reach is a caller invoking VM join with a general iterable. Potential resource consumption is confined to that execution context on the available evidence; no network, tenant, credential, or deployment path was established.

Security Findings and Attack Paths

  • inferred — An iterable yielding an invalid first item followed by extensive further output can require that output to be consumed before TypeError. This is a conditional resource-amplification path, not an established production exploit.

Trust Boundaries and Controls

  • observed — Join can invoke user-defined iteration and buffer acquisition. Binary join requests a simple buffer, rejects noncontiguous buffers, retains acquired exports through copying, and prevents bytearray-separator resizing while its join is active.

Resilience and Maintainability Implications

  • inferred — The retained buffer handles and deferred separator-export release cover ordinary completion and error returns. The focused evidence does not establish behavior for every concurrent or nonconforming exporter interaction.

Hardening Proposals

  • proposed — Applications that pass untrusted general iterables to join should enforce input-size or execution budgets at their own boundary while retaining the intended join semantics.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.74% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 23 functions across 7 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: preallocating binary joins and preserving buffer lifetimes during joining.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

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.

@youknowone
youknowone merged commit fd10823 into RustPython:main Sep 28, 2026
21 checks passed
@1ndahous3
1ndahous3 deleted the binary_join_buffers branch September 28, 2026 16:09
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.

2 participants