Skip to content

Commit a3425b4

Browse files
Copilotyouknowonegithub-actions[bot]
authored
Track symbol table cursors to avoid exhaustion (#6670)
* Handle missing symbol table without panic * Update symbol table error message * Track symbol table cursors to avoid exhaustion --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent bf80d27 commit a3425b4

File tree

2 files changed

+35
-40
lines changed

2 files changed

+35
-40
lines changed

crates/codegen/src/compile.rs

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -637,25 +637,29 @@ impl Compiler {
637637
}
638638

639639
/// Push the next symbol table on to the stack
640-
fn push_symbol_table(&mut self) -> &SymbolTable {
640+
fn push_symbol_table(&mut self) -> CompileResult<&SymbolTable> {
641641
// Look up the next table contained in the scope of the current table
642642
let current_table = self
643643
.symbol_table_stack
644644
.last_mut()
645645
.expect("no current symbol table");
646646

647-
if current_table.sub_tables.is_empty() {
648-
panic!(
649-
"push_symbol_table: no sub_tables available in {} (type: {:?})",
650-
current_table.name, current_table.typ
651-
);
647+
if current_table.next_sub_table >= current_table.sub_tables.len() {
648+
let name = current_table.name.clone();
649+
let typ = current_table.typ;
650+
return Err(self.error(CodegenErrorType::SyntaxError(format!(
651+
"no symbol table available in {} (type: {:?})",
652+
name, typ
653+
))));
652654
}
653655

654-
let table = current_table.sub_tables.remove(0);
656+
let idx = current_table.next_sub_table;
657+
current_table.next_sub_table += 1;
658+
let table = current_table.sub_tables[idx].clone();
655659

656660
// Push the next table onto the stack
657661
self.symbol_table_stack.push(table);
658-
self.current_symbol_table()
662+
Ok(self.current_symbol_table())
659663
}
660664

661665
/// Pop the current symbol table off the stack
@@ -853,9 +857,9 @@ impl Compiler {
853857
arg_count: u32,
854858
kwonlyarg_count: u32,
855859
obj_name: String,
856-
) {
860+
) -> CompileResult<()> {
857861
// First push the symbol table
858-
let table = self.push_symbol_table();
862+
let table = self.push_symbol_table()?;
859863
let scope_type = table.typ;
860864

861865
// The key is the current position in the symbol table stack
@@ -865,11 +869,7 @@ impl Compiler {
865869
let lineno = self.get_source_line_number().get();
866870

867871
// Call enter_scope which does most of the work
868-
if let Err(e) = self.enter_scope(&obj_name, scope_type, key, lineno.to_u32()) {
869-
// In the current implementation, push_output doesn't return an error,
870-
// so we panic here. This maintains the same behavior.
871-
panic!("enter_scope failed: {e:?}");
872-
}
872+
self.enter_scope(&obj_name, scope_type, key, lineno.to_u32())?;
873873

874874
// Override the values that push_output sets explicitly
875875
// enter_scope sets default values based on scope_type, but push_output
@@ -880,6 +880,7 @@ impl Compiler {
880880
info.metadata.posonlyargcount = posonlyarg_count;
881881
info.metadata.kwonlyargcount = kwonlyarg_count;
882882
}
883+
Ok(())
883884
}
884885

885886
// compiler_exit_scope
@@ -1984,7 +1985,7 @@ impl Compiler {
19841985

19851986
if let Some(type_params) = type_params {
19861987
// For TypeAlias, we need to use push_symbol_table to properly handle the TypeAlias scope
1987-
self.push_symbol_table();
1988+
self.push_symbol_table()?;
19881989

19891990
// Compile type params and push to stack
19901991
self.compile_type_params(type_params)?;
@@ -2067,7 +2068,7 @@ impl Compiler {
20672068
(parameters.posonlyargs.len() + parameters.args.len()).to_u32(),
20682069
parameters.kwonlyargs.len().to_u32(),
20692070
name.to_owned(),
2070-
);
2071+
)?;
20712072

20722073
let args_iter = core::iter::empty()
20732074
.chain(&parameters.posonlyargs)
@@ -2113,7 +2114,7 @@ impl Compiler {
21132114
allow_starred: bool,
21142115
) -> CompileResult<()> {
21152116
// Push the next symbol table onto the stack
2116-
self.push_symbol_table();
2117+
self.push_symbol_table()?;
21172118

21182119
// Get the current symbol table
21192120
let key = self.symbol_table_stack.len() - 1;
@@ -2332,13 +2333,8 @@ impl Compiler {
23322333

23332334
// Snapshot sub_tables before first finally compilation
23342335
// This allows us to restore them for the second compilation (exception path)
2335-
let sub_tables_snapshot = if !finalbody.is_empty() && finally_except_block.is_some() {
2336-
Some(
2337-
self.symbol_table_stack
2338-
.last()
2339-
.map(|t| t.sub_tables.clone())
2340-
.unwrap_or_default(),
2341-
)
2336+
let sub_table_cursor = if !finalbody.is_empty() && finally_except_block.is_some() {
2337+
self.symbol_table_stack.last().map(|t| t.next_sub_table)
23422338
} else {
23432339
None
23442340
};
@@ -2353,10 +2349,10 @@ impl Compiler {
23532349

23542350
if let Some(finally_except) = finally_except_block {
23552351
// Restore sub_tables for exception path compilation
2356-
if let Some(snapshot) = sub_tables_snapshot
2352+
if let Some(cursor) = sub_table_cursor
23572353
&& let Some(current_table) = self.symbol_table_stack.last_mut()
23582354
{
2359-
current_table.sub_tables = snapshot;
2355+
current_table.next_sub_table = cursor;
23602356
}
23612357

23622358
self.switch_to_block(finally_except);
@@ -2617,13 +2613,8 @@ impl Compiler {
26172613
}
26182614

26192615
// Snapshot sub_tables before first finally compilation (for double compilation issue)
2620-
let sub_tables_snapshot = if !finalbody.is_empty() && finally_except_block.is_some() {
2621-
Some(
2622-
self.symbol_table_stack
2623-
.last()
2624-
.map(|t| t.sub_tables.clone())
2625-
.unwrap_or_default(),
2626-
)
2616+
let sub_table_cursor = if !finalbody.is_empty() && finally_except_block.is_some() {
2617+
self.symbol_table_stack.last().map(|t| t.next_sub_table)
26272618
} else {
26282619
None
26292620
};
@@ -2642,10 +2633,10 @@ impl Compiler {
26422633
// Stack at entry: [lasti, exc] (from exception table with preserve_lasti=true)
26432634
if let Some(finally_except) = finally_except_block {
26442635
// Restore sub_tables for exception path compilation
2645-
if let Some(snapshot) = sub_tables_snapshot
2636+
if let Some(cursor) = sub_table_cursor
26462637
&& let Some(current_table) = self.symbol_table_stack.last_mut()
26472638
{
2648-
current_table.sub_tables = snapshot;
2639+
current_table.next_sub_table = cursor;
26492640
}
26502641

26512642
self.switch_to_block(finally_except);
@@ -3246,7 +3237,7 @@ impl Compiler {
32463237
num_typeparam_args as u32,
32473238
0,
32483239
type_params_name,
3249-
);
3240+
)?;
32503241

32513242
// Add parameter names to varnames for the type params scope
32523243
// These will be passed as arguments when the closure is called
@@ -3554,7 +3545,7 @@ impl Compiler {
35543545
) -> CompileResult<CodeObject> {
35553546
// 1. Enter class scope
35563547
let key = self.symbol_table_stack.len();
3557-
self.push_symbol_table();
3548+
self.push_symbol_table()?;
35583549
self.enter_scope(name, CompilerScope::Class, key, firstlineno)?;
35593550

35603551
// Set qualname using the new method
@@ -3660,7 +3651,7 @@ impl Compiler {
36603651
0,
36613652
0,
36623653
type_params_name,
3663-
);
3654+
)?;
36643655

36653656
// Set private name for name mangling
36663657
self.code_stack.last_mut().unwrap().private = Some(name.to_owned());
@@ -6322,7 +6313,7 @@ impl Compiler {
63226313
};
63236314

63246315
// Create magnificent function <listcomp>:
6325-
self.push_output(flags, 1, 1, 0, name.to_owned());
6316+
self.push_output(flags, 1, 1, 0, name.to_owned())?;
63266317

63276318
// Mark that we're in an inlined comprehension
63286319
self.current_code_info().in_inlined_comp = true;

crates/codegen/src/symboltable.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ pub struct SymbolTable {
4444
/// AST nodes.
4545
pub sub_tables: Vec<SymbolTable>,
4646

47+
/// Cursor pointing to the next sub-table to consume during compilation.
48+
pub next_sub_table: usize,
49+
4750
/// Variable names in definition order (parameters first, then locals)
4851
pub varnames: Vec<String>,
4952

@@ -70,6 +73,7 @@ impl SymbolTable {
7073
is_nested,
7174
symbols: IndexMap::default(),
7275
sub_tables: vec![],
76+
next_sub_table: 0,
7377
varnames: Vec::new(),
7478
needs_class_closure: false,
7579
needs_classdict: false,

0 commit comments

Comments
 (0)