| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info ⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Plus Run ID: facf520a-6186-4010-82c9-56e8a01639e1 📥 CommitsReviewing files that changed from the base of the PR and between a707729 and 410844f. 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 Walkthrough Walkthroughexpandtabs now removes tabs for a zero tab size instead of allocating an oversized space run. Rust and Python tests cover zero, negative, and positive tab sizes. Python tests also cover empty-pattern replacement. ChangesExpandtabs zero-tab-size handling
Empty-pattern replacement coverage
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to 41084 This change prevents process termination for zero or negative tab sizes and adds focused coverage; no actionable merge-blocking risk remains after normal checks and review. Suggested reviewers: youknowone 🚥 Pre-merge checks | ✅ 5 ✅ Passed checks (5 passed)
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. ❤️ ShareComment @coderabbitai help to get the list of available commands. |
Sorry, something went wrong.
`"a\tb".expandtabs(0)` panicked with a capacity overflow. CPython returns `'ab'`: with no width to advance to, the tabs come out and nothing else moves. `expandtabs(-1)` is the same call, since `ExpandTabsArgs::tabsize` sends every negative value to 0. `expandtabs` keeps the tab stop in `tab_size` and the current column in `col_count`, and on a tab it does `tab_size - col_count`. With a tab size of zero both start at 0, the first character makes `col_count` 1 while `tab_size` stays 0, and the subtraction underflows. The run of spaces asked for next is `usize::MAX`, and the allocation aborts the process. A tab has to follow something on the line to reach it: `"\ta".expandtabs(0)` subtracts 0 from 0 and comes out right by accident. `BytesInner::expandtabs` already returns early for this and filters the tabs out. The string version now does the same. Assisted-by: Claude Code:claude-opus-5
There was a problem hiding this comment.
👍
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
"a\tb".expandtabs(0) takes the interpreter down:
$ rustpython -c 'print("a\tb".expandtabs(0))' thread 'main' panicked at library/alloc/src/raw_vec/mod.rs:28:5: capacity overflowCPython returns 'ab': with no width to advance to, the tabs come out and nothing else moves. expandtabs(-1) is the same, because ExpandTabsArgs::tabsize sends every negative value to 0.
rustpython_common::str::expandtabs walks the string with the tab stop in tab_size and the current column in col_count, and on a tab it does tab_size - col_count. Both start at zero, so the first character makes col_count 1 while tab_size stays 0, and the subtraction underflows. The run of spaces asked for next is usize::MAX, and the allocation aborts the process. That is why a tab has to follow something: "\ta".expandtabs(0) starts the tab at column 0, subtracts 0 from 0, and comes out right by accident.
BytesInner::expandtabs already returns early for this, filtering the tabs out. The string version now does the same thing.
Reachable from any Python code, no C API and no unusual build needed:
Checked against CPython 3.14.7 over 23 subjects by 10 tab sizes by str, bytes and bytearray, 460 cases. All 460 agree now. Without the change 42 of them abort the process, and the bytes half is not among them, which is where the shape of the fix came from.
Tests are in crates/common/src/str.rs next to the function and in extra_tests/snippets/builtin_str.py alongside the expandtabs overflow cases that landed in #8524. Both cover the zero and negative sizes, ASCII and non-ASCII, tabs after a newline and after a carriage return, and a set of ordinary tab sizes so a fix that reached too far would show up.
Lib/test/string_tests.py has no case for a zero tab size, so test_str and test_bytes pass either way. They still pass here, along with test_textwrap, 523 tests.
Summary by CodeRabbit
Bug Fixes
Tests