Skip to content

Commit a330d39

Browse files
jgarzikclaude
andcommitted
Fix except-tuple, list overflow, list kwargs — 3 major infra fixes
1. exc_isinstance: Handle tuple of exception types in except clauses. `except (MemoryError, OverflowError)` now works. Previously only single-type except clauses matched. Supports nested tuples too. 2. list_repeat/list_inplace_repeat: Add overflow checks before huge allocations. `[0] * sys.maxsize` now raises OverflowError instead of fatal OOM. Limit: 256M items (~2GB). 3. list_type_call: Reject keyword arguments. `list(sequence=[])` now raises TypeError("list() takes no keyword arguments"). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4c4d3ef commit a330d39

2 files changed

Lines changed: 77 additions & 2 deletions

File tree

src/pyo/exception.asm

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,17 @@ END_FUNC exc_getattr
448448

449449
; exc_isinstance(PyExceptionObject *exc, PyTypeObject *type) -> int (0/1)
450450
; Check if exception is an instance of type, walking tp_base chain.
451+
; If type is a tuple, checks each element.
452+
extern tuple_type
451453
DEF_FUNC_BARE exc_isinstance
452-
; rdi = exc, rsi = target type
454+
; rdi = exc, rsi = target type (or tuple of types)
455+
; Check if rsi is a tuple
456+
mov rax, [rsi + PyObject.ob_type]
457+
lea rcx, [rel tuple_type]
458+
cmp rax, rcx
459+
je .tuple_match
460+
461+
; Single type: walk tp_base chain
453462
mov rax, [rdi + PyExceptionObject.ob_type]
454463
.walk:
455464
test rax, rax
@@ -464,6 +473,41 @@ DEF_FUNC_BARE exc_isinstance
464473
.not_match:
465474
xor eax, eax
466475
ret
476+
477+
.tuple_match:
478+
; rsi = tuple of types. Check each element.
479+
push rbx
480+
push r12
481+
push r13
482+
mov rbx, rdi ; save exc
483+
mov r12, [rsi + PyTupleObject.ob_item] ; type payloads
484+
mov r13, [rsi + PyTupleObject.ob_size] ; count
485+
xor ecx, ecx
486+
.tuple_loop:
487+
cmp rcx, r13
488+
jge .tuple_no_match
489+
push rcx
490+
mov rdi, rbx ; exc
491+
mov rsi, [r12 + rcx*8] ; type element
492+
; Recursive call for nested tuples
493+
call exc_isinstance
494+
pop rcx
495+
test eax, eax
496+
jnz .tuple_found
497+
inc rcx
498+
jmp .tuple_loop
499+
.tuple_found:
500+
mov eax, 1
501+
pop r13
502+
pop r12
503+
pop rbx
504+
ret
505+
.tuple_no_match:
506+
xor eax, eax
507+
pop r13
508+
pop r12
509+
pop rbx
510+
ret
467511
END_FUNC exc_isinstance
468512

469513
; type_is_exc_subclass(PyTypeObject *type) -> int (0/1)

src/pyo/list.asm

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1660,8 +1660,12 @@ DEF_FUNC list_repeat
16601660
.rep_positive:
16611661

16621662
mov r13, [rbx + PyListObject.ob_size] ; r13 = len(list)
1663-
imul r14, r13, 1 ; r14 = original length
1663+
mov r14, r13
16641664
imul r14, r12 ; r14 = total items
1665+
jo .rep_overflow ; signed overflow → MemoryError
1666+
; Sanity check: total_items * 8 must fit in address space
1667+
cmp r14, 0x10000000 ; 256M items limit (~2GB)
1668+
ja .rep_overflow
16651669

16661670
; Allocate new list
16671671
mov rdi, r14
@@ -1711,6 +1715,12 @@ DEF_FUNC list_repeat
17111715
pop rbx
17121716
leave
17131717
ret
1718+
1719+
.rep_overflow:
1720+
extern exc_OverflowError_type
1721+
lea rdi, [rel exc_OverflowError_type]
1722+
CSTRING rsi, "too many items for list repetition"
1723+
call raise_exception
17141724
END_FUNC list_repeat
17151725

17161726
;; ============================================================================
@@ -1879,6 +1889,9 @@ DEF_FUNC list_inplace_repeat, LIR_FRAME
18791889
; Grow items array: new_cap = old_size * count
18801890
mov r13, rax ; r13 = old_size
18811891
imul rax, r12 ; rax = old_size * count = new_size
1892+
jo .lir_overflow ; signed overflow → OverflowError
1893+
cmp rax, 0x10000000 ; 256M items limit
1894+
ja .lir_overflow
18821895
push rax ; save new_size
18831896

18841897
; Realloc payloads
@@ -1966,6 +1979,11 @@ DEF_FUNC list_inplace_repeat, LIR_FRAME
19661979
pop rbx
19671980
leave
19681981
ret
1982+
.lir_overflow:
1983+
extern exc_OverflowError_type
1984+
lea rdi, [rel exc_OverflowError_type]
1985+
CSTRING rsi, "too many items for list repetition"
1986+
call raise_exception
19691987
END_FUNC list_inplace_repeat
19701988

19711989
;; ============================================================================
@@ -1985,6 +2003,12 @@ DEF_FUNC list_type_call, LTC_FRAME
19852003
mov r12, rsi ; args
19862004
mov r13, rdx ; nargs
19872005

2006+
; Reject keyword arguments
2007+
extern kw_names_pending
2008+
mov rax, [rel kw_names_pending]
2009+
test rax, rax
2010+
jnz .ltc_kwarg_error
2011+
19882012
; list() — no args: return empty list
19892013
test r13, r13
19902014
jz .ltc_empty
@@ -2077,6 +2101,13 @@ DEF_FUNC list_type_call, LTC_FRAME
20772101
lea rdi, [rel exc_TypeError_type]
20782102
CSTRING rsi, "list expected at most 1 argument"
20792103
call raise_exception
2104+
2105+
.ltc_kwarg_error:
2106+
; Clear kw_names_pending to avoid stale state
2107+
mov qword [rel kw_names_pending], 0
2108+
lea rdi, [rel exc_TypeError_type]
2109+
CSTRING rsi, "list() takes no keyword arguments"
2110+
call raise_exception
20802111
END_FUNC list_type_call
20812112

20822113
;; ============================================================================

0 commit comments

Comments
 (0)