Skip to content

Guard out-of-range shift counts in integer opcodes#559

Open
uwezkhan wants to merge 1 commit into
pydata:masterfrom
uwezkhan:shift-count-guard
Open

Guard out-of-range shift counts in integer opcodes#559
uwezkhan wants to merge 1 commit into
pydata:masterfrom
uwezkhan:shift-count-guard

Conversation

@uwezkhan

Copy link
Copy Markdown

The integer shift opcodes hand the per-element shift count straight to C++ <</>>. When a<<b or a>>b runs with a count that is negative or at least the operand width (32 for int, 64 for long long) the shift is undefined behavior. On arm64 `evaluate("a<<b")" with b=100 returns 80 because the hardware masks the count, while NumPy returns 0, and a UBSAN build traps right at the shift. Both int and long long, left and right, hit this.

After the change an out-of-range left shift yields 0 and an out-of-range right shift clamps the count to width-1 so the sign bit fills, which is the result NumPy gives. The guard sits in the opcode next to the existing div/mod guards because the count is only known per element at run time, so a caller-side check could not cover array shift counts. Tradeoff is one extra unsigned compare per element; in-range counts keep the same value and the branch is well predicted.

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