Skip to content

Compiler crashes with panic instead of SyntaxError due to empty symbol table stack #8008

@alok-108

Description

@alok-108

I found a bug in the RustPython compiler.

Sometimes, for some reason, the internal symbol_table_stack becomes completely empty. Then the compiler tries to take an item out of that stack using .expect("compiler bug"). That means if the stack is empty, the whole RustPython process will crash. And that's exactly what happens.

I ran a specific test – the test is called assert_without_message_raises_class_directly. When that test runs, the compiler crashes and shows this error:

thread 'compile::tests::assert_without_message_raises_class_directly' (23444) panicked at crates\codegen\src\compile.rs:1016:39:
compiler bug
stack backtrace:
0: std::panicking::panic_handler
1: core::panicking::panic_fmt
2: core::panicking::panic_display
3: core::option::expect_failed

This is wrong. The compiler should never crash like this. Even if its internal state gets corrupted, it should log an error or show a proper Python-style error (like "Internal compiler error, please report"), but it should not kill the whole process.

My environment

Windows 11
Rust stable
Latest RustPython main branch
I reproduced this crash on my own machine.

What I expect

When this situation happens, the compiler should NOT panic. It should have a fallback – for example, create a dummy scope, print an error message, and continue. It should not stop.

Steps to reproduce

  1. Clone the RustPython repository.
  2. Run this command: cargo test -p rustpython-codegen -- --nocapture
  3. The test mentioned above will fail and show the panic.

Proposed fix

This way the compiler won't crash – it will just create a dummy scope and keep going. If there are any real errors, they will show up later.
In the file crates/codegen/src/compile.rs, around line 1016, there is this line:

let parent_scope = self.symbol_table_stack.pop().expect("compiler bug");

Change it to something like this:
let parent_scope = match self.symbol_table_stack.pop() {
    Some(scope) => scope,
    None => {
        log::error!("Compiler bug: popped empty symbol table stack. Creating dummy scope.");
        SymbolTable::new(ScopeType::Function, None)
    }
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions