@@ -163,10 +163,13 @@ const _: () = {
163163impl LocalsPlus {
164164 /// Create a new heap-backed LocalsPlus. All slots start as None (0).
165165 fn new ( nlocalsplus : usize , stacksize : usize ) -> Self {
166- let capacity = nlocalsplus + stacksize;
166+ let capacity = nlocalsplus
167+ . checked_add ( stacksize)
168+ . expect ( "LocalsPlus capacity overflow" ) ;
169+ let nlocalsplus_u32 = u32:: try_from ( nlocalsplus) . expect ( "nlocalsplus exceeds u32" ) ;
167170 Self {
168171 data : LocalsPlusData :: Heap ( vec ! [ 0usize ; capacity] . into_boxed_slice ( ) ) ,
169- nlocalsplus : nlocalsplus as u32 ,
172+ nlocalsplus : nlocalsplus_u32 ,
170173 stack_top : 0 ,
171174 }
172175 }
@@ -177,14 +180,19 @@ impl LocalsPlus {
177180 /// The caller must call `materialize_localsplus()` when the frame finishes
178181 /// to migrate data to the heap, then `datastack_pop()` to free the memory.
179182 fn new_on_datastack ( nlocalsplus : usize , stacksize : usize , vm : & VirtualMachine ) -> Self {
180- let capacity = nlocalsplus + stacksize;
181- let byte_size = capacity * core:: mem:: size_of :: < usize > ( ) ;
183+ let capacity = nlocalsplus
184+ . checked_add ( stacksize)
185+ . expect ( "LocalsPlus capacity overflow" ) ;
186+ let byte_size = capacity
187+ . checked_mul ( core:: mem:: size_of :: < usize > ( ) )
188+ . expect ( "LocalsPlus byte size overflow" ) ;
189+ let nlocalsplus_u32 = u32:: try_from ( nlocalsplus) . expect ( "nlocalsplus exceeds u32" ) ;
182190 let ptr = vm. datastack_push ( byte_size) as * mut usize ;
183191 // Zero-initialize all slots (0 = None for both PyObjectRef and PyStackRef).
184192 unsafe { core:: ptr:: write_bytes ( ptr, 0 , capacity) } ;
185193 Self {
186194 data : LocalsPlusData :: DataStack { ptr, capacity } ,
187- nlocalsplus : nlocalsplus as u32 ,
195+ nlocalsplus : nlocalsplus_u32 ,
188196 stack_top : 0 ,
189197 }
190198 }
@@ -2362,18 +2370,16 @@ impl ExecutingFrame<'_> {
23622370 // Same as LoadFast but explicitly checks for unbound locals
23632371 // (LoadFast in RustPython already does this check)
23642372 let idx = idx. get ( arg) as usize ;
2365- let x = self . localsplus . fastlocals ( ) [ idx]
2366- . clone ( )
2367- . ok_or_else ( || {
2368- vm. new_exception_msg (
2369- vm. ctx . exceptions . unbound_local_error . to_owned ( ) ,
2370- format ! (
2371- "local variable '{}' referenced before assignment" ,
2372- self . code. varnames[ idx]
2373- )
2374- . into ( ) ,
2373+ let x = self . localsplus . fastlocals ( ) [ idx] . clone ( ) . ok_or_else ( || {
2374+ vm. new_exception_msg (
2375+ vm. ctx . exceptions . unbound_local_error . to_owned ( ) ,
2376+ format ! (
2377+ "local variable '{}' referenced before assignment" ,
2378+ self . code. varnames[ idx]
23752379 )
2376- } ) ?;
2380+ . into ( ) ,
2381+ )
2382+ } ) ?;
23772383 self . push_value ( x) ;
23782384 Ok ( None )
23792385 }
@@ -2413,18 +2419,16 @@ impl ExecutingFrame<'_> {
24132419 // lifetime issues at yield/exception points are resolved.
24142420 Instruction :: LoadFastBorrow { var_num : idx } => {
24152421 let idx = idx. get ( arg) as usize ;
2416- let x = self . localsplus . fastlocals ( ) [ idx]
2417- . clone ( )
2418- . ok_or_else ( || {
2419- vm. new_exception_msg (
2420- vm. ctx . exceptions . unbound_local_error . to_owned ( ) ,
2421- format ! (
2422- "local variable '{}' referenced before assignment" ,
2423- self . code. varnames[ idx]
2424- )
2425- . into ( ) ,
2422+ let x = self . localsplus . fastlocals ( ) [ idx] . clone ( ) . ok_or_else ( || {
2423+ vm. new_exception_msg (
2424+ vm. ctx . exceptions . unbound_local_error . to_owned ( ) ,
2425+ format ! (
2426+ "local variable '{}' referenced before assignment" ,
2427+ self . code. varnames[ idx]
24262428 )
2427- } ) ?;
2429+ . into ( ) ,
2430+ )
2431+ } ) ?;
24282432 self . push_value ( x) ;
24292433 Ok ( None )
24302434 }
@@ -4329,7 +4333,10 @@ impl ExecutingFrame<'_> {
43294333 let nargs: u32 = arg. into ( ) ;
43304334 let callable = self . nth_value ( nargs + 1 ) ;
43314335 let stack_len = self . localsplus . stack_len ( ) ;
4332- let self_or_null_is_some = self . localsplus . stack_index ( stack_len - nargs as usize - 1 ) . is_some ( ) ;
4336+ let self_or_null_is_some = self
4337+ . localsplus
4338+ . stack_index ( stack_len - nargs as usize - 1 )
4339+ . is_some ( ) ;
43334340 if !self_or_null_is_some
43344341 && cached_version != 0
43354342 && let Some ( cls) = callable. downcast_ref :: < PyType > ( )
@@ -6029,11 +6036,21 @@ impl ExecutingFrame<'_> {
60296036 args_vec. push ( self_val) ;
60306037 }
60316038 for stack_idx in args_start..stack_len {
6032- let val = self . localsplus . stack_index_mut ( stack_idx) . take ( ) . unwrap ( ) . to_pyobj ( ) ;
6039+ let val = self
6040+ . localsplus
6041+ . stack_index_mut ( stack_idx)
6042+ . take ( )
6043+ . unwrap ( )
6044+ . to_pyobj ( ) ;
60336045 args_vec. push ( val) ;
60346046 }
60356047
6036- let callable_obj = self . localsplus . stack_index_mut ( callable_idx) . take ( ) . unwrap ( ) . to_pyobj ( ) ;
6048+ let callable_obj = self
6049+ . localsplus
6050+ . stack_index_mut ( callable_idx)
6051+ . take ( )
6052+ . unwrap ( )
6053+ . to_pyobj ( ) ;
60376054 self . localsplus . stack_truncate ( callable_idx) ;
60386055
60396056 let result = callable_obj. vectorcall ( args_vec, effective_nargs, None , vm) ?;
@@ -6109,11 +6126,21 @@ impl ExecutingFrame<'_> {
61096126 args_vec. push ( self_val) ;
61106127 }
61116128 for stack_idx in args_start..stack_len {
6112- let val = self . localsplus . stack_index_mut ( stack_idx) . take ( ) . unwrap ( ) . to_pyobj ( ) ;
6129+ let val = self
6130+ . localsplus
6131+ . stack_index_mut ( stack_idx)
6132+ . take ( )
6133+ . unwrap ( )
6134+ . to_pyobj ( ) ;
61136135 args_vec. push ( val) ;
61146136 }
61156137
6116- let callable_obj = self . localsplus . stack_index_mut ( callable_idx) . take ( ) . unwrap ( ) . to_pyobj ( ) ;
6138+ let callable_obj = self
6139+ . localsplus
6140+ . stack_index_mut ( callable_idx)
6141+ . take ( )
6142+ . unwrap ( )
6143+ . to_pyobj ( ) ;
61176144 self . localsplus . stack_truncate ( callable_idx) ;
61186145
61196146 let kwnames = kwarg_names_tuple. as_slice ( ) ;
0 commit comments