Skip to content

run: support directory and zip targets and reduce list GC memory - #1163

Merged
youknowone merged 17 commits into
mainfrom
import
Aug 13, 2026
Merged

run: support directory and zip targets and reduce list GC memory#1163
youknowone merged 17 commits into
mainfrom
import

Conversation

@youknowone

@youknowone youknowone commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • run directory and zipfile script targets through path hooks and runpy while preserving the canonical __main__ frame/globals
  • update the pinned RustPython revision and CPython compatibility baselines, including test_zipimport
  • keep short-lived list headers in the nursery and match PyPy shutdown behavior to avoid steady-state and teardown memory growth

Validation

  • cargo check --features dynasm
  • cargo test --features dynasm
  • python3 pyre/check.py target/release/pyre-dynasm --backend dynasm --no-synthetic --no-cpython-suite (17/17 passed)

Summary by CodeRabbit

  • New Features

    • Improved execution of directory- and ZIP-based Python scripts, including path handling and runpy support.
    • socket.sethostname() now accepts strings and bytes.
    • Improved frame and global namespace handling.
  • Bug Fixes

    • Fixed string formatting errors involving unsupported = alignment.
    • Improved garbage-collection safety for lists, virtual references, and optimized values.
    • Corrected ZIP-import behavior and expanded interpreter compatibility.
  • Tests

    • Added package-script parity coverage and updated runtime benchmarks and compatibility baselines.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bd27fc56-505f-4dee-bcde-42f4a5a8bc1b

📥 Commits

Reviewing files that changed from the base of the PR and between 21e2c99 and 2be9988.

📒 Files selected for processing (2)
  • pyre/bench/synth/str_fstring.dynasm.linux.github-actions.jitstats
  • pyre/pyre-object/src/object_array.rs

Walkthrough

The PR hardens moving-GC handling across virtual references, lists, interpreter code, and JIT paths. It refactors script and module execution, adds package-target parity coverage, updates runtime compatibility behavior, refreshes test and JIT baselines, and pins RustPython dependencies.

Changes

Moving-GC safety

Layer / File(s) Summary
Virtual-reference tracing
majit/majit-metainterp/src/optimizeopt/virtualize.rs, majit/majit-metainterp/src/resume.rs, majit/majit-metainterp/src/virtualref.rs
Virtual-reference allocation, decoding, and tracing now root objects and reload forwarded addresses.
Movable list storage
pyre/pyre-object/src/listobject.rs, pyre/pyre-object/src/object_array.rs, pyre/pyre-object/src/lltype.rs
List allocation, growth, mutation, item-block handling, and barriers now support movable headers and forwarded pointers.
GC-safe interpreter and JIT paths
pyre/pyre-interpreter/src/baseobjspace.rs, pyre/pyre-interpreter/src/builtins.rs, pyre/pyre-jit-trace/src/jitcode_dispatch/*, pyre/pyre-jit/tests/gc_stress.rs
Interpreter and JIT paths root objects across safepoints and reload forwarded references.

Script and module execution

Layer / File(s) Summary
Execution context and finalization
pyre/pyre-interpreter/src/pyframe.rs, pyre/pyrex/src/lib.rs
Frame construction accepts explicit globals. Main-module setup, exception handling, and reduced finalization are centralized.
Script-path dispatch
pyre/pyre-interpreter/src/importing.rs, pyre/pyrex/src/lib.rs
Script startup stages sys.path[0], probes import hooks, invokes runpy for package targets, and falls back to direct source evaluation.
Script-target validation
pyre/extra_tests/parity_tests/script_target_is_a_package.py, pyre/cpython_tests/run.py, pyre/cpython_tests/baseline.json
Tests and baselines cover package, zipfile, plain-file, safe-path, isolated, and resource-gated execution.

Runtime compatibility and baselines

Layer / File(s) Summary
Runtime compatibility behavior
pyre/pyre-interpreter/src/module/_socket/interp_socket.rs, pyre/pyre-interpreter/src/type_methods.rs
sethostname accepts strings and bytes. Invalid string alignment now raises ValueError.
Test and JIT baselines
pyre/bench/synth/*, pyre/check.py
JIT statistics and platform-specific guard-failure measurements were updated.
RustPython dependency pin
Cargo.toml
RustPython workspace crates now use revision 557bec1adf1c9c64e17c7fea42cbc36d8c09f8fb.

Estimated code review effort: 5 (Critical) | ~90 minutes

Possibly related issues

  • youknowone/pyre#205 — The changes extend moving-GC rooting, forwarding, and related JIT safety work.

Possibly related PRs

  • youknowone/pyre#1158 — Directly overlaps GC-safe list handling, forwarded-pointer reloads, JIT updates, shutdown changes, and benchmark files.
  • youknowone/pyre#303 — Relates to GC-relocation safety in list growth, append, insertion, and strategy promotion.
  • youknowone/pyre#316 — Relates to the pyrex startup and source-execution flow.

Poem

A rabbit roots pointers beneath the moon,
Forwarded fields hop safely in tune.
Scripts find packages, paths settle right,
Baselines record each test-night.
RustPython pins close the gate—
GC-safe carrots celebrate! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 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 two primary changes: directory and zip script targets, and reduced list GC memory usage.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch import

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.

@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: 95700c64eb

ℹ️ 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".

Comment on lines +990 to +995
crate::gc_hook::try_gc_alloc_collecting_rooted(
W_LIST_GC_TYPE_ID,
W_LIST_OBJECT_SIZE,
&mut allocation_root,
&mut needs_write_barrier,
)

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 Reload list owners after making headers movable

When a young list reaches a GC safepoint during an operation, the collector updates shadow-stack roots but cannot update an existing Rust &mut W_ListObject. Switching headers to this collecting allocator therefore makes existing paths unsafe: W_ListObject::object_grow allocates a backing block and then continues through self, while w_list_pop may box an item before calling list.sync_allocated; path_hook_accepts likewise calls one hook and then indexes the same raw list again. If that allocation or hook triggers a minor collection, these paths access the evacuated nursery address, causing corruption or incorrect directory/zip target detection. The owner must be rooted and reloaded after every safepoint, including accounting for the address-striped list lock, before headers can safely move.

Useful? React with 👍 / 👎.

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

🤖 Codex parity review

Static analysis of this diff vs the local RPython/PyPy sources (commit cbd0267).
Updated: 2026-08-13T19:11:45.924Z

Files in the reviewed diff
pyre/cpython_tests/baseline.json
pyre/cpython_tests/run.py
pyre/extra_tests/parity_tests/script_target_is_a_package.py
pyre/pyre-interpreter/src/builtins.rs
pyre/pyre-interpreter/src/importing.rs
pyre/pyre-interpreter/src/module/_socket/interp_socket.rs
pyre/pyre-interpreter/src/module/unicodedata/mod.rs
pyre/pyre-interpreter/src/pyframe.rs
pyre/pyre-object/src/object_array.rs
pyre/pyrex/src/lib.rs

1. Regressions to PyPy parity introduced by this patch

None.

2. Other mismatches introduced by this patch

  • pyre/pyrex/src/lib.rs:1760 ↔ pypy/interpreter/app_main.py:1054 — pyre evaluates sys.path_hooks before import_site (pyre/pyrex/src/lib.rs:1772), whereas PyPy imports site first (pypy/interpreter/app_main.py:875). Consequently, sitecustomize cannot add or alter a hook that determines whether a directory/zip target is accepted.

3. Pre-existing mismatches (already present before this patch)

  • pyre/pyrex/src/lib.rs:1690 ↔ pypy/interpreter/app_main.py:1052 — pyre sets __main__.__file__ before importing site (pyre/pyrex/src/lib.rs:1708); PyPy imports site first (pypy/interpreter/app_main.py:875) and only later sets __file__. Thus a sitecustomize module observes __file__ too early in pyre.
  • pyre/pyrex/src/lib.rs:1576 ↔ pypy/interpreter/app_main.py:872 — pyre’s startup __main__ namespace has __name__ and builtins but does not create __annotations__ = {}; PyPy initializes that mapping before publishing __main__.

4. Structural adaptations

  • pyre/pyre-interpreter/src/builtins.rs:16141 ↔ pypy/module/_io/interp_fileio.py:434 — pyre emulates cursor-aware FileIO.write against an in-memory path backing rather than PyPy’s direct os.write; the new overwrite-at-position behavior preserves the upstream observable semantics.
  • pyre/pyre-object/src/object_array.rs:463 ↔ rpython/memory/gctransform/shadowstack.py:100 — explicit Rust shadow-stack pinning is required before a movable-GC safepoint, corresponding to RPython’s translated root-stack management.
  • pyre/pyre-interpreter/src/module/unicodedata/mod.rs:110 ↔ pypy/module/unicodedata/interp_ucd.py:131w_str_new_managed is Rust’s collectable allocation equivalent of PyPy’s space.newtext; it avoids making dynamic Unicode query results immortal.
  • pyre/pyre-interpreter/src/pyframe.rs:2740 ↔ pypy/interpreter/module.py:77 — accepting an already-owned globals dictionary is a Rust startup/GC adaptation that preserves PyPy’s single module-dictionary identity.

@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: 0fb1871711

ℹ️ 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".

Comment thread pyre/pyrex/src/lib.rs
if let Err(e) = init_importlib_bootstrap(canonical, ec_ptr) {
eprintln!("pyre: importlib bootstrap failed: {}", e.message_text());
}
path_hook_accepts(filename, canonical, ec_ptr)

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 Import site before consulting path hooks

When sitecustomize installs or removes a path hook, this probes only the bootstrap hooks and does not call import_site until after a target has already been accepted. PyPy imports site in pypy/interpreter/app_main.py:875-882 before iterating sys.path_hooks at lines 1054-1061, so custom executable-path formats are ignored or misclassified here; move site initialization ahead of this probe.

AGENTS.md reference: AGENTS.md:L231-L233

Useful? React with 👍 / 👎.

@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: 1070a68ed7

ℹ️ 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".

Comment thread pyre/pyrex/src/lib.rs
if let Err(e) = runpy_run_module_as_main(canonical, ec_ptr, "__main__", false) {
handle_main_error(e, canonical, ec_ptr);
}
finish_main(canonical, ec_ptr);

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 Defer package-target finalization until after the REPL

When a directory or zip target is run with -i, this branch calls finish_main before returning to the dispatcher, which then invokes repl::run_repl; that function creates a fresh execution context and replaces __main__ with new globals (pyre/pyrex/src/repl.rs:53-77). Consequently the prompt cannot inspect names defined by the target, and it starts after the original runtime has already been marked finalizing. PyPy instead passes the existing mainmodule to interactive_console and performs shutdown only after the prompt exits (app_main.py:1158-1172), so preserve the package target's context/module through the REPL and finalize afterward.

AGENTS.md reference: AGENTS.md:L231-L233

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pyre/pyre-jit-trace/src/jitcode_dispatch/specialize.rs`:
- Around line 13129-13133: Update the comment above emit_module_dict_cell_fold
to remove IntMutableCell from the unfoldable states, since
emit_namespace_cell_fold handles it via the live integer-field fold; describe
the false result generically as an absent name or present entry that could not
be folded.

In `@pyre/pyre-object/src/listobject.rs`:
- Around line 999-1008: After the `try_gc_alloc_collecting_rooted` call in the
allocation fallback, reload `items_block` from `block_root` before evaluating or
handling `raw.is_null()`. Ensure the boxed header initialization uses this
refreshed block address when allocation returns null, while preserving the
existing non-null allocation path.

In `@pyre/pyrex/src/lib.rs`:
- Around line 1284-1302: Root path_hooks before invoking hooks and retrieve the
rooted value from its shadow-stack slot on each iteration. Update the loop
around call_function_impl_result so w_list_getitem uses that rooted path_hooks
reference, while preserving the existing hook iteration and error handling.
- Around line 1354-1378: Update run_module’s error-handling tail to delegate to
handle_main_error, and route its successful finalization through finish_main
instead of duplicating the shutdown logic inline. Preserve the existing
exception-printing, runtime-finalization, JIT-statistics, keyboard-interrupt,
and process-exit ordering by passing the existing error, canonical object, and
execution context to these helpers.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 55fd3669-c347-4b97-953d-b5ab166a92ae

📥 Commits

Reviewing files that changed from the base of the PR and between e17be6f and 603b914.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (23)
  • Cargo.toml
  • majit/majit-metainterp/src/optimizeopt/virtualize.rs
  • majit/majit-metainterp/src/resume.rs
  • majit/majit-metainterp/src/virtualref.rs
  • pyre/bench/synth/bytes_split_whitespace_maxsplit.cranelift.jitstats
  • pyre/bench/synth/bytes_split_whitespace_maxsplit.dynasm.jitstats
  • pyre/bench/synth/bytes_split_whitespace_maxsplit.wasm.jitstats
  • pyre/bench/synth/str_fstring.cranelift.linux.github-actions.jitstats
  • pyre/check.py
  • pyre/cpython_tests/baseline.json
  • pyre/cpython_tests/run.py
  • pyre/extra_tests/parity_tests/script_target_is_a_package.py
  • pyre/pyre-interpreter/src/baseobjspace.rs
  • pyre/pyre-interpreter/src/importing.rs
  • pyre/pyre-interpreter/src/module/_socket/interp_socket.rs
  • pyre/pyre-interpreter/src/pyframe.rs
  • pyre/pyre-interpreter/src/type_methods.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/mod.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/specialize.rs
  • pyre/pyre-jit/tests/gc_stress.rs
  • pyre/pyre-object/src/listobject.rs
  • pyre/pyre-object/src/lltype.rs
  • pyre/pyrex/src/lib.rs

Comment on lines 13129 to 13133
// `emit_module_dict_cell_fold` returns `false` for BOTH an absent name and
// a present-but-unfoldable one (`IntMutableCell` / movable / strategy
// switched). Only an ABSENT name may fall through to the builtins fold — a
// a present-but-unfoldable one (`IntMutableCell` / strategy switched).
// Only an ABSENT name may fall through to the builtins fold — a
// present global shadows the builtin, so keep the residual (which reads the
// live globals slot) when the slot still exists.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the IntMutableCell fold description.

emit_module_dict_cell_fold forwards a non-null IntMutableCell to emit_namespace_cell_fold. That function has an is_int_cell branch that emits the live integer-field fold. Do not describe IntMutableCell as unfoldable here.

Use a generic description such as “a present entry that could not be folded,” or list only the actual non-foldable states.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-jit-trace/src/jitcode_dispatch/specialize.rs` around lines 13129 -
13133, Update the comment above emit_module_dict_cell_fold to remove
IntMutableCell from the unfoldable states, since emit_namespace_cell_fold
handles it via the live integer-field fold; describe the false result
generically as an absent name or present entry that could not be folded.

Comment thread pyre/pyre-object/src/listobject.rs
Comment thread pyre/pyrex/src/lib.rs Outdated
Comment thread pyre/pyrex/src/lib.rs

@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: 2ddf6efbd6

ℹ️ 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".

Comment thread pyre/pyrex/src/lib.rs
match result {
Ok(true) => {
importing::restage_sys_path_0(std::ffi::OsStr::new(filename));
import_site(no_site, canonical, ec_ptr);

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 Seed standard main attributes before importing site

When a directory or ZIP target is run and sitecustomize inspects __main__, this branch imports site while prepare_main_module has initialized only __name__ and __builtins__; the package path bypasses eval_source_in_main, so attributes such as __loader__, __spec__, and __package__ are not installed until runpy executes afterward. A customization that reads these standard attributes therefore sees missing state or raises during package-target startup. PyPy's app_main.py:869-880 initializes the main module and its loader before importing site, so seed the standard main-module state before this call.

AGENTS.md reference: AGENTS.md:L231-L233

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai 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.

🔇 Additional comments (4)
pyre/pyre-object/src/listobject.rs (4)

1039-1048: The Box fallback still stores the pre-collection items_block.

try_gc_alloc_collecting_rooted can collect and relocate the pinned block before it returns null. The raw.is_null() path at lines 1057-1069 writes the stale items_block into the boxed header, because the reload from block_root runs only at lines 1071-1073. Move the reload to immediately after the allocator call.

Proposed fix
     .filter(|p| !p.is_null())
     .unwrap_or(std::ptr::null_mut());
+    // Re-read the (possibly relocated) nursery items block after the header alloc.
+    if let Some(s) = block_root {
+        items_block = crate::gc_roots::shadow_stack_get(s) as *mut ItemsBlock;
+    }
     // `pop_roots` for the two typed blocks: this was the last allocation they
-    // Re-read the (possibly relocated) nursery items block after the header alloc.
-    if let Some(s) = block_root {
-        items_block = crate::gc_roots::shadow_stack_get(s) as *mut ItemsBlock;
-    }
     unsafe {

214-245: LGTM!

Also applies to: 265-283, 295-310, 380-415, 435-435, 450-455, 805-819, 831-833, 1455-1457, 1473-1477


1032-1048: 🩺 Stability & Availability

⚠️ Unverified finding
Sandbox verification was unavailable.

Verify that header.w_class survives the now-collecting header allocation.

Line 1015-1018 captures header.w_class = get_instantiate(&LIST_TYPE) in a plain local before the allocation, and line 1074-1087 writes it into the new object. The previous try_gc_alloc_stable path never collected, so the capture could not go stale. try_gc_alloc_collecting_rooted can run a collection. If get_instantiate(&LIST_TYPE) returns a movable object, this stores a stale pointer into every list header.

Confirm that the returned w_class is immortal. If it is not, pin it with the surrounding push_roots frame and rebuild header from the reloaded slot after the allocation.

Also confirm the try_gc_alloc_collecting_rooted parameter order and the needs_write_barrier output contract, so that true means "header placed outside the nursery".

The learning about not reloading pointers after allocation applies to try_gc_alloc_stable/try_gc_alloc_stable_raw only, because those never collect; it does not cover this collecting allocator. Based on learnings.


1089-1095: LGTM!


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 09665c49-d189-47f6-8250-f079bb5b3a3a

📥 Commits

Reviewing files that changed from the base of the PR and between 603b914 and 2ddf6ef.

📒 Files selected for processing (1)
  • pyre/pyre-object/src/listobject.rs

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
pyre/pyre-interpreter/src/module/_socket/interp_socket.rs (4)

1020-1031: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Copy the fallback address before the next resolver call.

first_addr points into the process-global hostent returned by gethostbyname. The later gethostbyaddr call can overwrite that resolver storage while it reads addr_ptr. Copy the address bytes into caller-owned storage before calling gethostbyaddr.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-interpreter/src/module/_socket/interp_socket.rs` around lines 1020
- 1031, In the resolver flow around first_addr and the subsequent gethostbyaddr
call, copy the h.h_length bytes from first_addr into caller-owned storage before
invoking gethostbyaddr, then pass the copied buffer as addr_ptr. Preserve the
existing address type, length, and empty-address-list error handling.

55-56: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Handle null pointer arrays before pointer arithmetic.

gethostbyname calls this helper before it checks h_addr_list for an empty entry. If the resolver supplies a null h_addr_list, array.add(0) has undefined behavior before read_unaligned runs. Return a null pointer when array.is_null().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-interpreter/src/module/_socket/interp_socket.rs` around lines 55 -
56, Update hostent_pointer_at to check array.is_null() before performing pointer
arithmetic, returning a null character pointer for a null array; retain the
existing unaligned read behavior for non-null arrays.

2062-2082: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Preserve the timeout deadline across EINTR.

Each EINTR retries poll with the original full timeout. A signal handler that returns normally can extend a finite socket timeout indefinitely. Compute a monotonic deadline once and poll only for the remaining duration.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-interpreter/src/module/_socket/interp_socket.rs` around lines 2062
- 2082, Update the polling loop around the socket timeout logic to compute a
monotonic deadline once before entering the loop, then recalculate and pass only
the remaining timeout to libc::poll after EINTR retries. Preserve immediate
timeout errors when the deadline is reached, while retaining signal checking and
existing error handling for non-EINTR failures.

2582-2593: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Close the descriptor before invoking py_repr_wtf8.

py_repr_wtf8(obj) can run a subclass __repr__. That code can close the socket and reuse fd before Line 2592 closes the stale saved value. Mark _fd closed and close the saved descriptor before formatting the warning.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-interpreter/src/module/_socket/interp_socket.rs` around lines 2582
- 2593, Update the socket cleanup block around socket_get_attr_i64 and
py_repr_wtf8 to mark the object’s _fd as closed and close the saved fd before
invoking py_repr_wtf8. Then format and emit the ResourceWarning using the
already-closed object state, preserving the existing warning behavior without
closing a stale descriptor.
♻️ Duplicate comments (1)
pyre/pyre-object/src/listobject.rs (1)

1060-1094: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Reload items_block before the boxed fallback.

try_gc_alloc_collecting_rooted can collect and relocate the rooted items block, then still return null. In that case lines 1078-1090 build the boxed header from the pre-collection items_block address. Move the block_root reload above the raw.is_null() branch.

Proposed fix
     .filter(|p| !p.is_null())
     .unwrap_or(std::ptr::null_mut());
+    // Re-read the (possibly relocated) nursery items block after the header alloc.
+    if let Some(s) = block_root {
+        items_block = crate::gc_roots::shadow_stack_get(s) as *mut ItemsBlock;
+    }
     storage.reload_typed_blocks();
@@
-    // Re-read the (possibly relocated) nursery items block after the header alloc.
-    if let Some(s) = block_root {
-        items_block = crate::gc_roots::shadow_stack_get(s) as *mut ItemsBlock;
-    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-object/src/listobject.rs` around lines 1060 - 1094, Move the
block_root reload of items_block to immediately after
try_gc_alloc_collecting_rooted returns, before the raw.is_null() fallback
branch. Ensure both the boxed W_ListObject construction and the non-null
allocation path use the potentially relocated ItemsBlock pointer.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pyre/pyre-jit-trace/src/jitcode_dispatch/specialize.rs`:
- Around line 10099-10107: Update the call to w_list_switch_to_strategy_for to
consume its returned relocated (list, value) pair and use those values when
setting the concrete oprefs, replacing the discarded result and redundant
shadow-stack reloads while preserving the existing tracing behavior.

In `@pyre/pyre-object/src/listobject.rs`:
- Around line 1040-1058: Update switch_to_object_strategy to root list before
boxing typed values with w_int_new or w_float_new, then reload it from the
caller’s shadow-stack slot after conversion. Ensure the typed append and insert
paths use this refreshed list reference before calling object_push or
recursively invoking w_list_insert.

---

Outside diff comments:
In `@pyre/pyre-interpreter/src/module/_socket/interp_socket.rs`:
- Around line 1020-1031: In the resolver flow around first_addr and the
subsequent gethostbyaddr call, copy the h.h_length bytes from first_addr into
caller-owned storage before invoking gethostbyaddr, then pass the copied buffer
as addr_ptr. Preserve the existing address type, length, and empty-address-list
error handling.
- Around line 55-56: Update hostent_pointer_at to check array.is_null() before
performing pointer arithmetic, returning a null character pointer for a null
array; retain the existing unaligned read behavior for non-null arrays.
- Around line 2062-2082: Update the polling loop around the socket timeout logic
to compute a monotonic deadline once before entering the loop, then recalculate
and pass only the remaining timeout to libc::poll after EINTR retries. Preserve
immediate timeout errors when the deadline is reached, while retaining signal
checking and existing error handling for non-EINTR failures.
- Around line 2582-2593: Update the socket cleanup block around
socket_get_attr_i64 and py_repr_wtf8 to mark the object’s _fd as closed and
close the saved fd before invoking py_repr_wtf8. Then format and emit the
ResourceWarning using the already-closed object state, preserving the existing
warning behavior without closing a stale descriptor.

---

Duplicate comments:
In `@pyre/pyre-object/src/listobject.rs`:
- Around line 1060-1094: Move the block_root reload of items_block to
immediately after try_gc_alloc_collecting_rooted returns, before the
raw.is_null() fallback branch. Ensure both the boxed W_ListObject construction
and the non-null allocation path use the potentially relocated ItemsBlock
pointer.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 97a4f69f-88ba-4653-8a36-041c4f1bf7b0

📥 Commits

Reviewing files that changed from the base of the PR and between 2ddf6ef and 0d7b624.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • Cargo.toml
  • majit/majit-metainterp/src/optimizeopt/virtualize.rs
  • majit/majit-metainterp/src/resume.rs
  • pyre/pyre-interpreter/src/baseobjspace.rs
  • pyre/pyre-interpreter/src/importing.rs
  • pyre/pyre-interpreter/src/module/_socket/interp_socket.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/fbw_state.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/specialize.rs
  • pyre/pyre-object/src/listobject.rs

Comment on lines +10099 to +10107
let _ = unsafe { pyre_object::w_list_switch_to_strategy_for(inner_self, value) };
inner_self = pyre_object::gc_roots::shadow_stack_get(root_base);
value = pyre_object::gc_roots::shadow_stack_get(root_base + 1);
ctx.trace_ctx.set_opref_concrete(
self_ref,
majit_ir::Value::Ref(majit_ir::GcRef(inner_self as usize)),
);
ctx.trace_ctx
.set_opref_concrete(value_op, Value::Ref(majit_ir::GcRef(value as usize)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider using the returned relocated pair.

w_list_switch_to_strategy_for now returns the forwarded (list, value) pair, and this call discards it with let _ =. The shadow-slot reload produces the same addresses, so behavior is equivalent. Consuming the return value keeps the new API contract visible at the call site and makes a future divergence between the two sources impossible.

Proposed refactor
-        let _ = unsafe { pyre_object::w_list_switch_to_strategy_for(inner_self, value) };
-        inner_self = pyre_object::gc_roots::shadow_stack_get(root_base);
-        value = pyre_object::gc_roots::shadow_stack_get(root_base + 1);
+        (inner_self, value) =
+            unsafe { pyre_object::w_list_switch_to_strategy_for(inner_self, value) };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let _ = unsafe { pyre_object::w_list_switch_to_strategy_for(inner_self, value) };
inner_self = pyre_object::gc_roots::shadow_stack_get(root_base);
value = pyre_object::gc_roots::shadow_stack_get(root_base + 1);
ctx.trace_ctx.set_opref_concrete(
self_ref,
majit_ir::Value::Ref(majit_ir::GcRef(inner_self as usize)),
);
ctx.trace_ctx
.set_opref_concrete(value_op, Value::Ref(majit_ir::GcRef(value as usize)));
(inner_self, value) =
unsafe { pyre_object::w_list_switch_to_strategy_for(inner_self, value) };
ctx.trace_ctx.set_opref_concrete(
self_ref,
majit_ir::Value::Ref(majit_ir::GcRef(inner_self as usize)),
);
ctx.trace_ctx
.set_opref_concrete(value_op, Value::Ref(majit_ir::GcRef(value as usize)));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-jit-trace/src/jitcode_dispatch/specialize.rs` around lines 10099 -
10107, Update the call to w_list_switch_to_strategy_for to consume its returned
relocated (list, value) pair and use those values when setting the concrete
oprefs, replacing the discarded result and redundant shadow-stack reloads while
preserving the existing tracing behavior.

Comment thread pyre/pyre-object/src/listobject.rs

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pyre/pyre-interpreter/src/builtins.rs (2)

7624-7626: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Use a prebuilt text for the empty result.

PrebuiltText::get is valid for Python return values. It lazily creates one immortal W_UnicodeObject with w_str_new and returns the same object on later calls. Replace the repeated allocation in the len == 0 branch with a function-local static PrebuiltText.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-interpreter/src/builtins.rs` around lines 7624 - 7626, Update the
len == 0 branch in the surrounding builtin function to use a function-local
static PrebuiltText initialized with w_str_new, returning PrebuiltText::get()
instead of allocating a new empty string on each call. Preserve the existing Ok
return behavior.

9434-9443: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Root and reload the exception receiver across formatting dispatch

exc_user_dunder_obj calls call_and_check, while exception_kind_str_wtf8 calls py_repr_wtf8 and py_str_wtf8. These calls can execute Python and trigger GC. Root and reload the receiver before later accesses:

  • builtins.rs#L9434-L9443: reload obj before passing it to exception_str_method.
  • builtins.rs#L7651-L7660: pass the reloaded receiver to base_exception_str_method, not the original args slice.
  • display.rs#L1505-L1513: reload obj after exc_user_dunder_obj before reading its kind or fields.
  • Apply the same reload pattern inside exception_kind_str_wtf8 after formatting calls and before subsequent exception-slot accesses.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-interpreter/src/builtins.rs` around lines 9434 - 9443, Root and
reload exception receivers after Python-executing formatting calls before
subsequent access: in builtins.rs lines 9434-9443, reload obj before passing it
to exception_str_method; in builtins.rs lines 7651-7660, pass the reloaded
receiver to base_exception_str_method instead of the original args slice and
apply the same reload pattern in exception_kind_str_wtf8 after formatting calls;
in display.rs lines 1505-1513, reload obj after exc_user_dunder_obj before
reading its kind or fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pyre/bench/synth/str_fstring.dynasm.jitstats`:
- Line 11: Restore the shared guard_failures baseline in
str_fstring.dynasm.jitstats to 658, and leave 659 only in the Darwin GitHub
Actions overlay file.

---

Outside diff comments:
In `@pyre/pyre-interpreter/src/builtins.rs`:
- Around line 7624-7626: Update the len == 0 branch in the surrounding builtin
function to use a function-local static PrebuiltText initialized with w_str_new,
returning PrebuiltText::get() instead of allocating a new empty string on each
call. Preserve the existing Ok return behavior.
- Around line 9434-9443: Root and reload exception receivers after
Python-executing formatting calls before subsequent access: in builtins.rs lines
9434-9443, reload obj before passing it to exception_str_method; in builtins.rs
lines 7651-7660, pass the reloaded receiver to base_exception_str_method instead
of the original args slice and apply the same reload pattern in
exception_kind_str_wtf8 after formatting calls; in display.rs lines 1505-1513,
reload obj after exc_user_dunder_obj before reading its kind or fields.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 35093457-2530-49a3-b930-d4544a8b958d

📥 Commits

Reviewing files that changed from the base of the PR and between 0d7b624 and 21e2c99.

📒 Files selected for processing (3)
  • pyre/bench/synth/str_fstring.cranelift.jitstats
  • pyre/bench/synth/str_fstring.dynasm.jitstats
  • pyre/pyre-interpreter/src/builtins.rs

field_pos_attached_misplaced=0
field_pos_spec_misplaced=0
guard_failures=658
guard_failures=659

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- target file ---'
cat -n pyre/bench/synth/str_fstring.dynasm.jitstats
printf '%s\n' '--- baseline selection references ---'
rg -n -C 8 'jitstats|guard_failures|platform|macos|ubuntu|windows' pyre/check.py
printf '%s\n' '--- related baseline files ---'
find pyre/bench/synth -maxdepth 2 -type f -name '*.jitstats' -print | sort

Repository: youknowone/pyre

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- str_fstring baseline variants ---'
find pyre/bench -type f -name 'str_fstring*.jitstats' -print -exec sh -c 'echo "--- $1"; cat -n "$1"' sh {} \;
printf '%s\n' '--- relevant selection and comparison code ---'
sed -n '1531,1582p' pyre/check.py
sed -n '1610,1663p' pyre/check.py
printf '%s\n' '--- benchmark call sites for str_fstring ---'
rg -n -C 4 'str_fstring' pyre/check.py pyre/bench

Repository: youknowone/pyre

Length of output: 11967


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- jit-stats comparison semantics ---'
sed -n '919,1006p' pyre/check.py
printf '%s\n' '--- baseline selection behavior for representative runners ---'
python3 - <<'PY'
from pathlib import Path
import os

source = Path("pyre/bench/synth/str_fstring.py")
backend = "dynasm"
for github, platform in [
    ("true", "linux"),
    ("true", "win32"),
    ("true", "darwin"),
    ("false", "linux"),
    ("false", "darwin"),
]:
    candidates = []
    if github == "true":
        candidates.append(source.with_name(
            f"{source.stem}.{backend}.{platform}.github-actions.jitstats"
        ))
    candidates.append(source.with_name(
        f"{source.stem}.{backend}.{platform}.jitstats"
    ))
    candidates.append(source.with_name(
        f"{source.stem}.{backend}.jitstats"
    ))
    chosen = next((p for p in candidates if p.exists()), candidates[-1])
    value = None
    if chosen.exists():
        for line in chosen.read_text().splitlines():
            if line.startswith("guard_failures="):
                value = line.split("=", 1)[1]
    print(f"GITHUB_ACTIONS={github} sys.platform={platform}: {chosen} guard_failures={value}")
PY

Repository: youknowone/pyre

Length of output: 5401


Restore the shared DynASM baseline to 658.

pyre/check.py uses this file on ubuntu-24.04 and windows-latest; both report guard_failures=658. The macOS GitHub Actions overlay reports 659. With the shared value set to 659, common runners classify their 658 result as a regression, and a later 659 result can hide drift from the measured baseline.

Keep 659 only in pyre/bench/synth/str_fstring.dynasm.darwin.github-actions.jitstats.

Proposed correction
-guard_failures=659
+guard_failures=658
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
guard_failures=659
guard_failures=658
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/bench/synth/str_fstring.dynasm.jitstats` at line 11, Restore the shared
guard_failures baseline in str_fstring.dynasm.jitstats to 658, and leave 659
only in the Darwin GitHub Actions overlay file.

@youknowone
youknowone force-pushed the import branch 2 times, most recently from 2be9988 to 1b8c6ce Compare August 12, 2026 18:28

@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

https://github.com/youknowone/pyre/blob/1b8c6ce3c9dde0c51c7e52f5a72716e465eaa724/pyre-object/src/listobject.rs#L762-L764
P1 Badge Reload the item after pinning it

Once another mutator has existed, either pin_root call can wait behind a minor collection; the collector and pin_root update the shadow-stack slot, but not the raw w_item local. The subsequent is_plain_int1(w_item) and is_float_strategy_item(w_item) therefore dereference the evacuated nursery address during an empty-list append or insert, potentially selecting the wrong strategy or accessing reused memory. Reload w_item from root_base + 1 before performing these type checks.

ℹ️ 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".

@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

https://github.com/youknowone/pyre/blob/0bc57490c393de7f580de60ce1d6a079babf7d1d/pyre-object/src/listobject.rs#L1068-L1069
P1 Badge Preserve managed allocation failures instead of boxing

When the collecting GC hook is installed but returns null, this collapses Some(null) together with None and takes the unmanaged Box fallback. The hook contract in gc_hook.rs explicitly distinguishes these cases: Some(null) means the active GC failed and must abort, because a headerless object must not enter its managed graph. Moreover, the failed collecting attempt may already have relocated the Object-strategy items block, while the fallback stores the stale pre-collection items_block because its root is reloaded only after this branch. Under allocation pressure this can therefore construct a list with reclaimed storage rather than reporting allocation failure; classify the result with GcAllocOutcome::from_hook(...).allocated_or_abort(...) and reserve boxing for NoRoute.

ℹ️ 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".

@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: 2f1759938c

ℹ️ 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".

Comment thread pyre/pyrex/src/lib.rs Outdated
Comment on lines +1280 to +1281
if !unsafe { pyre_object::is_list(path_hooks) } {
return Ok(false);

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 Honor iterable sys.path_hooks replacements

Once site is imported before this probe, a sitecustomize that replaces sys.path_hooks with a tuple or another iterable causes this exact-list gate to return false without invoking any hooks. PyPy uses generic iteration at pypy/interpreter/app_main.py:1054, so the directory or ZIP should still be accepted; here it instead falls into read_script_source and attempts to execute the target itself as source. Iterate through the Python iterator protocol rather than requiring W_ListObject.

AGENTS.md reference: AGENTS.md:L231-L233

Useful? React with 👍 / 👎.

@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: 992e1aea6e

ℹ️ 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".

Comment thread pyre/pyrex/src/lib.rs Outdated
hook,
&[shadow_stack_get(filename_slot)],
) {
Ok(_) => return Ok(true),

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 Treat None results from path hooks as rejection

When a path hook returns None, this branch marks the target as accepted and later runs runpy against it. PyPy's app_main.py:1054-1062 stores the hook result in importer and treats None as no importer, so a custom hook that explicitly declines this way should allow an ordinary source file to follow the source-execution path; here it instead becomes sys.path[0] and fails looking for __main__. Check the returned object for None before returning true.

AGENTS.md reference: AGENTS.md:L231-L233

Useful? React with 👍 / 👎.

Comment thread pyre/pyre-interpreter/src/builtins.rs Outdated
Comment on lines +16172 to +16173
if pos > data.len() {
data.resize(pos, 0);

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 Make sparse-position buffer growth fallible

On the non-fd, non-Unix pathname fallback, Python can seek to a very large valid offset and then write a byte. This infallible Vec::resize attempts to allocate the entire hole and can panic or abort the interpreter instead of raising a Python exception; the subsequent checked_add runs too late to protect it. Validate the position and use fallible reservation before resizing.

Useful? React with 👍 / 👎.

@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

https://github.com/youknowone/pyre/blob/180b2cae2a4b98e8d3e9cec63f59dce34e9ebd09/pyre-interpreter/src/builtins.rs#L16210
P2 Badge Avoid extending files on empty writes

When an in-memory pathname stream seeks beyond EOF and writes an empty buffer, end == pos, so this branch resizes the backing buffer and flushes a zero-filled hole even though a zero-byte write must leave the file size unchanged (PyPy's interp_bytesio.py:123-126 returns before writing, while FileIO delegates the empty buffer to os.write). Return without growing when bytes.is_empty(), while preserving the current position.

AGENTS.md reference: AGENTS.md:L231-L232

ℹ️ 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".

@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: 7ed438bf80

ℹ️ 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".

Comment thread pyre/pyrex/src/lib.rs Outdated
// `for hook in sys.path_hooks` is a plain iteration, so a `sitecustomize`
// that replaces the list with a tuple or any other iterable still gets its
// hooks called.
let hooks = pyre_interpreter::baseobjspace::unpackiterable(path_hooks, -1)?;

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 Stop consuming hooks after the first accepted hook

When sys.path_hooks is a lazy iterable, such as a generator installed by sitecustomize, the generic-iterable follow-up now exhausts it with unpackiterable before calling any hook. For example, if it yields an accepting hook first and raises on the next iteration, PyPy calls the first hook and breaks at app_main.py:1054-1057, while this code raises before the accepting hook runs and aborts target startup. Iterate and invoke hooks interleaved so acceptance stops iteration immediately.

AGENTS.md reference: AGENTS.md:L231-L233

Useful? React with 👍 / 👎.

@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: 21ce002a6c

ℹ️ 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".

Comment thread pyre/pyrex/src/lib.rs
Comment on lines +1830 to +1831
import_site(no_site, canonical, ec_ptr);
if let Err(e) = runpy_run_module_as_main(canonical, ec_ptr, "__main__", false) {

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 Import runpy before prepending the package target

When a directory or ZIP target contains a top-level runpy.py, import_site first consumes the restaged entry via add_sys_path_0, and the following runpy_run_module_as_main imports runpy through the now-shadowed live sys.path. This executes the target's runpy.py or fails when it lacks _run_module_as_main, instead of running __main__.py. PyPy imports the standard-library runpy at app_main.py:1102 before inserting the target at line 1103, so preserve that ordering.

AGENTS.md reference: AGENTS.md:L231-L232

Useful? React with 👍 / 👎.

`RunMode::Script` read and compiled the file before the interpreter was up, so
a directory exited with `cannot open '<path>': Is a directory` and a zipfile
was decoded as source text. Both oracles instead put the path on `sys.path[0]`
and run the `__main__` module it contains.

Choosing between the two requires `sys.path_hooks`, which only exists after
`init_importlib_bootstrap`. The script run now creates `__main__`'s globals
with `fresh_module_globals`, imports `sys` and installs the bootstrap, and only
then walks `sys.path_hooks` with the absolutized filename, as
`app_main.py:1054-1105` does; the read and compile follow on the branch that
needs them. `PyFrame::new_with_context_and_globals` builds the frame over the
globals the bootstrap already ran in, and `new_with_context` delegates to it.

A hook that accepts the path restages the pending `sys.path[0]` entry to it and
runs `runpy._run_module_as_main("__main__", False)`. Only `ImportError` moves
on to the next hook. The restaged entry is set even under the safe-path flags,
which suppress the entry for an ordinary script.

`is_keyboard_interrupt` and the new `is_import_error` share
`raised_is_instance_of`.

test_zipimport_support: `FAILED (failures=2)` -> `Ran 4 tests, OK`.

Assisted-by: Claude
… statuses

22 modules were recorded `dynasm: PASS` with no cranelift entry, so a
cranelift-backed gate run deselected them. Each was run under cranelift and
re-confirmed at the nightly's own `--timeout 120`.

test.test_datetime is the one module of those 23 left unrecorded: it aborts at
`minor_custom_trace_target` during a nursery collection entered from cranelift
code, but not on every run — the same binary and environment gave rc=1 under
the runner and rc=134 standalone.

test.test_zipimport and test.test_zipimport_support were both recorded
IMPORTERROR. They import: the support module now passes (4 tests, three
consecutive runs), and test_zipimport runs all 91 tests with one error,
`testZip64LargeFile`.

Assisted-by: Claude
`interp_func.py:405-411` takes a bytes name as it stands and fsencodes a str
one, so a byte with no UTF-8 spelling reaches the syscall as itself; anything
else is a TypeError naming those two types. `fsencode_w` also accepts a
`__fspath__` object, which this entry point does not.

The pinned RustPython rev this commit used to carry is now behind the base's
own, which contains it, so only this hunk remains.

Assisted-by: Claude
Left as None, `test.support.use_resources` enables every resource, so the
module's Zip64 arms build archives past 4 GiB: it took 290s and over 6 GB of
RSS against the runner's 300s timeout. With the empty set libregrtest and
PyPy's conftest use, it runs 91 tests in 0.3s and passes on both backends,
which the baseline now records.

Assisted-by: Claude
`grow_list_items_block_gc` asked `try_gc_owns_object` whether the old
block was GC-owned before rooting it. That query's cross-thread path can
wait behind a collection, which relocates the block; the copy then read
reclaimed nursery slots and installed stale item pointers in the new
block, which a later remembered-set walk read as an invalid type_id.

Root `old` unconditionally instead. The shadow-stack walker ignores
non-GC addresses, so rooting the `std::alloc` fallback is safe and
removes the ownership-query safepoint entirely.

Assisted-by: Claude
The non-fd file fallback appended every write. `zipfile` writes a
provisional local header, then seeks back and patches it, so appending
left the provisional bytes in place and produced an archive whose
central directory pointed at a non-`PK\x03\x04` local header;
`zipimport._get_data` then rejected it as a bad local file header.

Track the write position and overwrite at it, keeping append mode on
the end-of-data path. `file_write_at` is target-neutral so the
seek-back behavior is covered by the ordinary test build.

Assisted-by: Claude
`w_str_new` allocates its value with `malloc_raw`, which carries no GC
header and is never paired with a `Box::from_raw`, so every string a
per-call function returned leaked its payload. `category`,
`bidirectional`, `east_asian_width`, `decomposition`, `name` and
`lookup` build a fresh string on each call, so they take
`w_str_new_managed`; the module-level version attributes stay immortal.

test_unicodedata peaks at 1379 MB rather than 2086 MB, with its 15
failures and 1 skip unchanged.

Assisted-by: Claude
The win32 dynasm leg reports 658 where the recorded baseline holds 659,
matching the cranelift baseline already re-recorded for this branch.

Assisted-by: Claude
`app_main.py:1054-1062` walks `for hook in sys.path_hooks` and keeps
`importer = hook(filename)` from the first hook that does not raise
`ImportError`, treating `importer is None` as "no importer claimed the
path". The probe instead required `sys.path_hooks` to be an exact list,
so a `sitecustomize` replacing it with another iterable silently skipped
every hook, and it accepted any non-raising hook, including one that
declines by returning None.

Assisted-by: Claude
Seeking to a large offset and writing one byte asks the fallback backing
to materialize the whole hole. The infallible growth aborts the process;
reserve first so the request raises MemoryError.

Assisted-by: Claude
A hook call runs arbitrary Python and can drive a collection that moves
the hook objects. The unpacked hooks lived in a Rust vector, which the
root walker does not scan, so publish each one in a shadow-stack slot and
read it back for the call.

Assisted-by: Claude
`file_write_at` resized the backing buffer up to the seek position for a
zero-length write, so writing `b''` past the end zero-filled the hole and
changed the file size. `interp_bytesio.py:124-125` returns before writing
when the buffer is empty.

Assisted-by: Claude
…ckage

`run.py` refuses to enumerate the suite unless every script carries
`# CPython-suite gap:` and `# parity-tests reason:` in its first 20 lines,
so the whole parity run aborted with a RuntimeError.

Assisted-by: Claude
`path_hook_accepts` drained the iterable with `unpackiterable` before
calling any hook, so an iterable that raises after yielding an accepting
hook aborted startup. `app_main.py:1054-1057` breaks out of the `for` on the
first hook that does not raise `ImportError`, without asking the iterator
for another item.

Assisted-by: Claude
The directory/zipfile arm reached `import site` with `__main__` carrying only
`__name__`, so a `sitecustomize` that reads `__main__.__loader__` raised.
`app_main.py:869-870` binds it at module creation, ahead of the
`app_main.py:875-882` site import.

Assisted-by: Claude
…refix

`canonicalize` answers in the `\\?\` form on Windows, so `sys.path[0]` for a
script carried a prefix no upstream entry has — `resolvedirof`
(`initpath.py:66-78`) builds it with `rabspath`. A program comparing the entry
against `os.path.dirname(__file__)` saw two different spellings.

Assisted-by: Claude
@youknowone
youknowone merged commit 3f4a685 into main Aug 13, 2026
13 of 17 checks passed
@youknowone
youknowone deleted the import branch August 13, 2026 22:58
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