Skip to content

Fix bytearray membership racing with resizing - #9091

Merged
youknowone merged 2 commits into
RustPython:mainfrom
youknowdot:fix-bytearray-internal-export-concurrency
Oct 13, 2026
Merged

youknowone merged 2 commits into
RustPython:mainfrom
youknowdot:fix-bytearray-internal-export-concurrency

Conversation

@youknowdot

@youknowdot youknowdot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Avoid synthetic buffer exports when bytearray membership uses an exact bytes, int, or bool needle. These needles cannot run Python while being prepared, so the existing read lock is sufficient to serialize the search with resizing.

This addresses the intermittent macOS test_free_threading_bytearray failure seen in #9063: one worker's b'\xdd' not in a temporarily exported a, making another worker's a[:] = c raise BufferError after c changed length. CPython protects its temporary export with an object critical section; the previous RustPython path exposed that temporary export to concurrent assignments.

Generic index/buffer callbacks, subclasses, and real memoryview exports keep their existing protection. This is scoped to exact bytes/int/bool membership, not a general critical-section implementation.

Add deterministic Python regression coverage in the existing builtin_bytearray.py snippet for membership results, integer range checks, self-containment, bytes-subclass index dispatch, reentrant callbacks, real exports, same-size mutation, and export cleanup. Lib is unchanged.

Validation

Initial fix (375501d6):

  • Release build and strict workspace/all-targets plus separate CAPI/all-targets Clippy passed with -D warnings.
  • The deterministic Python contract passed on RustPython and final CPython 3.15; the three selected upstream containment/reentrancy tests passed on RustPython.
  • One bounded concurrent run passed on free-threading RustPython. The CPython reference run also passed, but that oracle has the GIL enabled.
  • Workspace test-binary compilation (cargo test --workspace --exclude rustpython_wasm --exclude rustpython-venvlauncher --exclude rustpython-capi --no-run) passed, producing 22 executables without running them.
  • GitHub CI passed: 14 jobs passed, 2 configured skips; CodSpeed passed.

Review follow-up (b373af16e):

  • Exact builtin bool uses the callback-free integer path; regression coverage is consolidated into builtin_bytearray.py.
  • Fresh release build and strict workspace/all-targets plus separate CAPI/all-targets Clippy passed with -D warnings.
  • The isolated finite regression function, including True/False cases, passed once on the fresh RustPython binary and once on final CPython 3.15.
  • The concurrent fixture and upstream selectors were not rerun for this follow-up. Its CI is tracked separately.

Full local workspace runtime tests, the full snippets suite, and the full test_bytes module have not been run. Separate CAPI test-binary compilation has not been run. This is targeted local validation, not a claim that all local tests pass.

The fixed concurrent fixture is retained as external evidence rather than a deadline-sensitive CI snippet. It has three workers, 512 rounds each, at most 16 KiB target storage, and an external process watchdog. A passing run is probabilistic evidence, not proof of absence of races.

AI assistance

Codex/OpenAI performed source diagnosis, implemented the patch and Python regression checks, independently reviewed the lock/callback contract, and ran the reported validation. The runtime did not expose an exact model version.

Summary by CodeRabbit

  • Bug Fixes
    • Improved bytearray containment checks for byte strings, integers, and booleans, including correct handling of out-of-range integers.
    • Preserved resizing restrictions while a memoryview or buffer operation is active, with resizing available again after the buffer is released.

Search exact bytes and int needles under the data read lock instead of
taking a temporary export. This prevents a concurrent slice replacement
from receiving BufferError for a callback-free membership operation.

Preserve export protection for generic index/buffer callbacks and actual
memoryviews. Add Python coverage for these contracts.

AI assistance: Codex/OpenAI diagnosed the race, implemented and reviewed
the patch and regression snippet, and ran the reported validation. The
runtime did not expose an exact model version.

Assisted-by: Codex:model-version-unavailable
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

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: a9c399c8-5c79-4ead-b623-0f7a35436761
📥 Commits

Reviewing files that changed from the base of the PR and between 375501d and b373af1.

📒 Files selected for processing (2)
  • crates/vm/src/builtins/bytearray.rs
  • extra_tests/snippets/builtin_bytearray.py

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

📝 Walkthrough

bytearray.__contains__ now searches exact bytes needles and converted integer needles directly. Other needle types retain the exported-buffer conversion path. Tests cover containment results, integer conversion, buffer callbacks, and resizing behavior.

Changes: Bytearray containment

Layer / File(s) Summary
Containment paths and validation
crates/vm/src/builtins/bytearray.rs, extra_tests/snippets/builtin_bytearray.py
Exact bytes needles use substring containment. int and bool needles are converted with byte_or and searched as single bytes without creating a temporary export. Other needle types retain the exported-buffer path. Tests cover containment results, out-of-range values, conversion callbacks, active memoryviews, and buffer acquisition and release callbacks.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: youknowone

Merge Risk: ⚪ Minimal · up to b373a

No actionable issue remains in the supplied review evidence; the change is mergeable after normal checks.

Pre-merge checks · Passed 4 · Failed 1

Failed Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks (4 passed)
Check name Status Explanation
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.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: fixing bytearray membership behavior during concurrent resizing.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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 marked this pull request as ready for review October 13, 2026 03:47
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-13T04:42:12.019971Z b373af1 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

move to builtin_bytearray.py; this is a permanent rule. extract_tests/snippets/ must have only one file for one type/module in most cases

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Moved the coverage into builtin_bytearray.py and removed the separate snippet in b373af1. Coverage for this type will stay in its existing snippet file.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 375501d63a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}

fn __contains__(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
// Exact builtins cannot call Python while preparing the needle. The

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add the mandatory AI-assistance trailer

This commit explicitly documents Codex/OpenAI assistance but ends without the required Assisted-by: AGENT_NAME:MODEL_VERSION trailer, so it does not satisfy the repository's AI-disclosure format; add the trailer before merging.

AGENTS.md reference: AGENTS.md:L20-L23

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Commit 375501d already contains Assisted-by: Codex:model-version-unavailable; b373af1 contains the same trailer. Both commit bodies and the PR disclose the assistance. The runtime did not expose an exact model version.

@@ -0,0 +1,74 @@
from testutils import assert_raises

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Complete the mandatory test runs

The commit's Validation section explicitly says the workspace test run was still in progress and that the C-API tests and full snippets suite were not run, even though this interpreter change plus the new snippet requires all three before completion; finish the mandated workspace, C-API, and pytest -v runs rather than relying only on targeted checks.

AGENTS.md reference: AGENTS.md:L31-L35

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The full local runtime suites have not been run. For 375501d, workspace test-binary compilation passed (22 executables, none run), along with three selected upstream tests and bounded Python contract/concurrency checks. For b373af1, the fresh release build, isolated finite contract on RustPython/final CPython, and strict workspace/all-targets plus separate CAPI/all-targets Clippy passed. Full local suites include stress/extreme-allocation paths outside the approved execution scope, so the PR explicitly reports that limit. CI for 375501d passed; the new head has a separate CI run.

@@ -0,0 +1,74 @@
from testutils import assert_raises

for value in (b"", b"a", b"ab\x00\xff"):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Remove the prohibited test-file addition

This new file adds assertions and callback test logic, but the repository restricts test-file changes to adding or removing expectedFailure markers and explicitly disallows modifying test assertions, logic, or data; remove this test addition or obtain an explicit policy exception.

AGENTS.md reference: AGENTS.md:L273-L279

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The requested fix includes Python regression coverage, and the maintainer explicitly requested consolidating it into builtin_bytearray.py. b373af1 preserves that file's existing tests, moves this PR's new coverage there, and removes the separate snippet. Lib is unchanged.

Comment thread crates/vm/src/builtins/bytearray.rs Outdated
if let Some(bytes) = needle.downcast_ref_if_exact::<PyBytes>(vm) {
return Ok(self.borrow_buf().contains_str(bytes.as_bytes()));
}
if let Some(int) = needle.downcast_ref_if_exact::<PyInt>(vm) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include exact bools in the callback-free path

On a free-threaded run where one worker evaluates True in target or False in target while another resizes target, this exact-type check misses bool because its class is bool, not int. try_index_opt then handles the value through its callback-free downcast_ref::<PyInt>() path, but only after exports has been incremented, so the resizer can still observe a synthetic export and raise BufferError instead of waiting; exact bools need the same fast path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Fixed in b373af1: exact builtin bool now uses the callback-free integer path. Added True/False membership cases in builtin_bytearray.py. The exact bool type guard leaves int subclasses and generic conversion/buffer paths under their existing export protection. The isolated finite contract passed on the rebuilt RustPython binary and final CPython 3.15; strict workspace and separate CAPI Clippy passed with -D warnings.

@codspeed

codspeed Bot commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 62 untouched benchmarks
⏩ 4 skipped benchmarks1


Comparing youknowdot:fix-bytearray-internal-export-concurrency (375501d) with main (85edb52)

Open in CodSpeed

Footnotes

  1. 4 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

Include exact builtin bool in the callback-free integer membership path.
Keep int subclasses and generic conversion paths under export protection.
Move this PR's regression coverage into the existing bytearray snippet
and cover True/False membership as requested in review.

AI assistance: Codex/OpenAI implemented and independently reviewed the
review follow-up and ran the reported validation. The runtime did not
expose an exact model version.

Assisted-by: Codex:model-version-unavailable
@youknowone
youknowone enabled auto-merge (squash) October 13, 2026 05:12
@youknowone
youknowone merged commit e09846b into RustPython:main Oct 13, 2026
20 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.

2 participants