Skip to content

Commit 5373bcc

Browse files
jgarzikclaude
andcommitted
Fix pyobj_to_i64 GMP clamping for huge slice indices
__gmpz_get_si truncates big ints to low bits, returning 0 for 1<<333. This caused del a[9::1<<333] to fail with "step cannot be zero". Fix: check __gmpz_fits_slong_p before get_si. If value doesn't fit, clamp to near-maxsize (positive) or near-minsize (negative) based on __gmpz_cmp_si sign check. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b1d8302 commit 5373bcc

1 file changed

Lines changed: 24 additions & 1 deletion

File tree

src/pyo/slice.asm

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,14 +163,37 @@ pyobj_to_i64:
163163
lea rax, [rel none_singleton]
164164
cmp rdi, rax
165165
je .is_none
166-
; GMP int: use mpz_get_si
166+
; GMP int: check if it fits in i64, clamp if not
167167
push rbp
168168
mov rbp, rsp
169+
push rdi ; save obj ptr
170+
lea rdi, [rdi + PyIntObject.mpz]
171+
extern __gmpz_fits_slong_p
172+
call __gmpz_fits_slong_p wrt ..plt
173+
test eax, eax
174+
jz .gmp_clamp ; doesn't fit → clamp
175+
pop rdi ; restore obj ptr
169176
lea rdi, [rdi + PyIntObject.mpz]
170177
extern __gmpz_get_si
171178
call __gmpz_get_si wrt ..plt
172179
leave
173180
ret
181+
.gmp_clamp:
182+
; Value too large for i64 — clamp based on sign
183+
pop rdi ; restore obj ptr
184+
lea rdi, [rdi + PyIntObject.mpz]
185+
extern __gmpz_cmp_si
186+
xor esi, esi ; compare with 0
187+
call __gmpz_cmp_si wrt ..plt
188+
test eax, eax
189+
js .gmp_clamp_neg
190+
mov rax, 0x7FFFFFFFFFFFFFFE ; positive: clamp to near-maxsize (not sentinel)
191+
leave
192+
ret
193+
.gmp_clamp_neg:
194+
mov rax, 0x8000000000000001 ; negative: clamp to near-minsize
195+
leave
196+
ret
174197
.smallint:
175198
mov rax, rdi
176199
ret

0 commit comments

Comments
 (0)