Skip to content

Use memchr consistently for NUL checks#8372

Open
joshuamegnauth54 wants to merge 1 commit into
RustPython:mainfrom
joshuamegnauth54:use-memchr-consistently
Open

Use memchr consistently for NUL checks#8372
joshuamegnauth54 wants to merge 1 commit into
RustPython:mainfrom
joshuamegnauth54:use-memchr-consistently

Conversation

@joshuamegnauth54

@joshuamegnauth54 joshuamegnauth54 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

memchr is used throughout RustPython for searching through bytes expediently. However, for NUL checks, it's scantily used. Instead, our NUL checks either use contains or memchr.

I switched all of the contains(b'\0') I could find to using memchr instead. I marked the failure paths as cold to hint to LLVM that interior NULs are truly exceptional. This should help branch prediction a bit which is nice for string/bytes functions since they are likely called a lot.

Summary

  • Use memchr more as it's specialized for searching through bytes.
  • Hint to LLVM and the branch predictor that interior NULs are exceptional, so the error branch should remain out of the hot path.

Summary by CodeRabbit

  • Bug Fixes
    • Improved and standardized embedded NUL detection across string/bytes handling, environment variable validation, SSL/hostname/cipher setup, codecs lookup, file I/O wrapper checks, path conversions, process execution, and system database lookups.
    • Unix semaphore name errors are now surfaced more precisely (including interior-NUL cases), improving the reported exception for invalid semaphore names.
  • Performance
    • More efficient NUL scanning and more clearly marked rarely taken error paths to reduce overhead in the common case.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 40e61df6-3aef-4c97-b6b5-7d29ee1205fc

📥 Commits

Reviewing files that changed from the base of the PR and between 6788a1e and 70a29fa.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (20)
  • crates/host_env/Cargo.toml
  • crates/host_env/src/multiprocessing.rs
  • crates/host_env/src/time.rs
  • crates/host_env/src/winapi.rs
  • crates/stdlib/src/grp.rs
  • crates/stdlib/src/mmap.rs
  • crates/stdlib/src/multiprocessing.rs
  • crates/stdlib/src/openssl.rs
  • crates/stdlib/src/ssl.rs
  • crates/vm/src/builtins/bytes.rs
  • crates/vm/src/builtins/str.rs
  • crates/vm/src/bytes_inner.rs
  • crates/vm/src/function/fspath.rs
  • crates/vm/src/ospath.rs
  • crates/vm/src/stdlib/_codecs.rs
  • crates/vm/src/stdlib/_io.rs
  • crates/vm/src/stdlib/nt.rs
  • crates/vm/src/stdlib/os.rs
  • crates/vm/src/stdlib/pwd.rs
  • crates/vm/src/utils.rs
💤 Files with no reviewable changes (1)
  • crates/vm/src/utils.rs
🚧 Files skipped from review as they are similar to previous changes (15)
  • crates/vm/src/builtins/bytes.rs
  • crates/vm/src/ospath.rs
  • crates/vm/src/stdlib/_codecs.rs
  • crates/stdlib/src/multiprocessing.rs
  • crates/stdlib/src/ssl.rs
  • crates/host_env/src/time.rs
  • crates/stdlib/src/openssl.rs
  • crates/vm/src/stdlib/_io.rs
  • crates/vm/src/stdlib/pwd.rs
  • crates/vm/src/builtins/str.rs
  • crates/vm/src/function/fspath.rs
  • crates/host_env/src/winapi.rs
  • crates/vm/src/stdlib/nt.rs
  • crates/host_env/src/multiprocessing.rs
  • crates/vm/src/bytes_inner.rs

📝 Walkthrough

Walkthrough

The change centralizes NUL-byte detection through Python string and byte helpers, marks validation failures as cold paths, propagates Unix semaphore interior-NUL errors explicitly, and updates host and standard-library integrations.

Changes

NUL validation and error propagation

Layer / File(s) Summary
Shared NUL primitives and conversions
crates/vm/src/builtins/{bytes.rs,str.rs}, crates/vm/src/bytes_inner.rs, crates/vm/src/utils.rs
Adds shared contains_nuls() helpers, makes byte accessors const, and removes the separate ToCString::ensure_no_nul validation.
Runtime path and environment validation
crates/vm/src/function/fspath.rs, crates/vm/src/ospath.rs, crates/vm/src/stdlib/{_codecs.rs,_io.rs,nt.rs,os.rs,pwd.rs}
Updates path, codec, I/O, process, environment, and account-name validation to use shared NUL checks and cold error branches.
Standard-library API validation
crates/stdlib/src/{grp.rs,mmap.rs,multiprocessing.rs,openssl.rs,ssl.rs}
Applies shared NUL detection to standard-library APIs, preserves InteriorNul semaphore errors, and centralizes SSL hostname validation.
Host-platform error boundaries
crates/host_env/{Cargo.toml,src/{multiprocessing.rs,time.rs,winapi.rs}}
Propagates Unix semaphore interior-NUL errors and updates Windows wide-string, dependency, and environment-block NUL handling.

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

Possibly related PRs

Suggested reviewers: youknowone, shaharnaveh

🚥 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 matches the main change: replacing NUL-byte checks with memchr across the codebase.
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
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@joshuamegnauth54
joshuamegnauth54 force-pushed the use-memchr-consistently branch from 8549281 to 6788a1e Compare July 25, 2026 19:48

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
crates/stdlib/src/multiprocessing.rs (1)

805-822: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing cold_path() on the SemError::InteriorNul branches.

Every other NUL-error return site touched by this PR (grp.rs, openssl.rs::set_ciphers/new_py_ssl_socket, mmap.rs, nt.rs::execve, ssl.rs::validate_hostname) calls cold_path() immediately before returning the interior-NUL error, per the PR's stated goal of marking these exceptional paths cold. These two branches in py_new and sem_unlink return exceptions::nul_char_error(vm) on SemError::InteriorNul without a cold_path() call, leaving this file's semaphore error paths on the "hot" path unlike everywhere else.

♻️ Add cold_path() to match the cohort convention
+use core::hint::cold_path;
...
             SemHandle::create(&args.name, value, args.unlink).map_err(|err| {
                 if err == SemError::InteriorNul {
+                    cold_path();
                     exceptions::nul_char_error(vm)
                 } else {
                     os_error(vm, err)
                 }
             })?;
...
     fn sem_unlink(name: String, vm: &VirtualMachine) -> PyResult<()> {
         host_multiprocessing::sem_unlink(&name).map_err(|err| {
             if err == SemError::InteriorNul {
+                cold_path();
                 exceptions::nul_char_error(vm)
             } else {
                 os_error(vm, err)
             }
         })
     }

Also applies to: 838-847

🤖 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 `@crates/stdlib/src/multiprocessing.rs` around lines 805 - 822, Add cold_path()
immediately before returning exceptions::nul_char_error(vm) in both the
SemError::InteriorNul branch of py_new and the corresponding branch in
sem_unlink. Keep the existing non-NUL error handling unchanged and match the
cold-path convention used by the other touched NUL-error sites.
🤖 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 `@crates/host_env/src/winapi.rs`:
- Around line 312-315: Update the NUL-check condition in the environment-block
validation flow to call .is_some() on both memchr results before combining them
with ||. Keep the existing cold_path() and
BuildEnvironmentBlockError::ContainsNul return behavior unchanged.

In `@crates/stdlib/src/multiprocessing.rs`:
- Around line 13-16: Remove the unused cold_path import from the core imports in
the Windows-only multiprocessing module. Keep the AtomicI32, AtomicU32, and
Ordering imports unchanged.

In `@crates/vm/src/stdlib/nt.rs`:
- Around line 555-558: Update the NUL checks in the affected code path to call
contains_nuls() on both key and value PyStrRef instances instead of
contains_null(), preserving the existing cold_path() and nul_char_error return
behavior.

---

Nitpick comments:
In `@crates/stdlib/src/multiprocessing.rs`:
- Around line 805-822: Add cold_path() immediately before returning
exceptions::nul_char_error(vm) in both the SemError::InteriorNul branch of
py_new and the corresponding branch in sem_unlink. Keep the existing non-NUL
error handling unchanged and match the cold-path convention used by the other
touched NUL-error sites.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9548f16e-55a1-4f9c-b3d5-72ded4122018

📥 Commits

Reviewing files that changed from the base of the PR and between 003ebec and 8549281.

📒 Files selected for processing (19)
  • crates/host_env/src/multiprocessing.rs
  • crates/host_env/src/time.rs
  • crates/host_env/src/winapi.rs
  • crates/stdlib/src/grp.rs
  • crates/stdlib/src/mmap.rs
  • crates/stdlib/src/multiprocessing.rs
  • crates/stdlib/src/openssl.rs
  • crates/stdlib/src/ssl.rs
  • crates/vm/src/builtins/bytes.rs
  • crates/vm/src/builtins/str.rs
  • crates/vm/src/bytes_inner.rs
  • crates/vm/src/function/fspath.rs
  • crates/vm/src/ospath.rs
  • crates/vm/src/stdlib/_codecs.rs
  • crates/vm/src/stdlib/_io.rs
  • crates/vm/src/stdlib/nt.rs
  • crates/vm/src/stdlib/os.rs
  • crates/vm/src/stdlib/pwd.rs
  • crates/vm/src/utils.rs
💤 Files with no reviewable changes (1)
  • crates/vm/src/utils.rs

Comment thread crates/host_env/src/winapi.rs
Comment on lines +13 to +16
use core::{
hint::cold_path,
sync::atomic::{AtomicI32, AtomicU32, Ordering},
};

Copy link
Copy Markdown
Contributor

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

Unused cold_path import in this Windows-only module.

cold_path is imported here but never called anywhere in this mod _multiprocessing (the Windows implementation has no NUL-check branch that uses it). This will trigger an unused_imports warning under cargo clippy.

As per coding guidelines, "Always run clippy to lint code with cargo clippy... and fix any warnings or lints introduced by changes."

🤖 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 `@crates/stdlib/src/multiprocessing.rs` around lines 13 - 16, Remove the unused
cold_path import from the core imports in the Windows-only multiprocessing
module. Keep the AtomicI32, AtomicU32, and Ordering imports unchanged.

Source: Coding guidelines

Comment thread crates/vm/src/stdlib/nt.rs Outdated
Comment on lines 555 to 558
if key.contains_null() || value.contains_null() {
cold_path();
return Err(exceptions::nul_char_error(vm));
}

Copy link
Copy Markdown
Contributor

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
# Check the actual method name(s) defined for NUL detection on PyStr/PyStrRef
ast-grep run --pattern 'fn contains_nul$_($$$) -> $_' --lang rust crates/vm/src/builtins/str.rs crates/vm/src/bytes_inner.rs crates/vm/src/builtins/bytes.rs
rg -n 'fn contains_nul' crates/vm/src/builtins/str.rs crates/vm/src/bytes_inner.rs crates/vm/src/builtins/bytes.rs
rg -n 'contains_null\(\)|contains_nuls\(\)' crates/vm/src -g '!target'

Repository: RustPython/RustPython

Length of output: 1692


Call contains_nuls() for NUL checks on PyStrRef.

PyStr/PyStrRef only define contains_nuls(), so key.contains_null() / value.contains_null() will not compile.

🤖 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 `@crates/vm/src/stdlib/nt.rs` around lines 555 - 558, Update the NUL checks in
the affected code path to call contains_nuls() on both key and value PyStrRef
instances instead of contains_null(), preserving the existing cold_path() and
nul_char_error return behavior.

`memchr` is used throughout RustPython for searching through bytes
expediently. However, for NUL checks, it's scantily used. Instead, our
NUL checks either use `contains` or `memchr`.

I switched all of the `contains(b'\0')` I could find to using memchr
instead. I marked the failure paths as cold to hint to LLVM that
interior NULs are truly exceptional. This should help branch prediction
a bit which is nice for string/bytes functions since they are likely
called a lot.
@joshuamegnauth54
joshuamegnauth54 force-pushed the use-memchr-consistently branch from 6788a1e to 70a29fa Compare July 26, 2026 04:13
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