Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 41 additions & 9 deletions crates/vm/src/stdlib/sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod sys {
},
convert::ToPyObject,
frame::FrameRef,
function::{FuncArgs, OptionalArg, PosArgs},
function::{FuncArgs, KwArgs, OptionalArg, PosArgs},
stdlib::{builtins, warnings::warn},
types::PyStructSequence,
version,
Expand Down Expand Up @@ -688,32 +688,64 @@ mod sys {
writeln!(stderr, "{}:", unraisable.err_msg.str(vm)?);
}

// TODO: print received unraisable.exc_traceback
let tb_module = vm.import("traceback", 0)?;
let print_stack = tb_module.get_attr("print_stack", vm)?;
print_stack.call((), vm)?;
// Print traceback (using actual exc_traceback, not current stack)
if !vm.is_none(&unraisable.exc_traceback) {
let tb_module = vm.import("traceback", 0)?;
let print_tb = tb_module.get_attr("print_tb", vm)?;
let stderr_obj = super::get_stderr(vm)?;
let kwargs: KwArgs = [("file".to_string(), stderr_obj)].into_iter().collect();
let _ = print_tb.call(
FuncArgs::new(vec![unraisable.exc_traceback.clone()], kwargs),
vm,
);
}
Comment on lines +691 to +701
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Error propagation may suppress unraisable exception output.

The ? operator on vm.import() and get_attr() will cause the entire _unraisablehook to return early on failure, potentially losing the exception type/value output that follows. Consider catching these errors to ensure the hook remains resilient:

         // Print traceback (using actual exc_traceback, not current stack)
         if !vm.is_none(&unraisable.exc_traceback) {
-            let tb_module = vm.import("traceback", 0)?;
-            let print_tb = tb_module.get_attr("print_tb", vm)?;
-            let stderr_obj = super::get_stderr(vm)?;
-            let kwargs: KwArgs = [("file".to_string(), stderr_obj)].into_iter().collect();
-            let _ = print_tb.call(
-                FuncArgs::new(vec![unraisable.exc_traceback.clone()], kwargs),
-                vm,
-            );
+            if let Ok(tb_module) = vm.import("traceback", 0)
+                && let Ok(print_tb) = tb_module.get_attr("print_tb", vm)
+                && let Ok(stderr_obj) = super::get_stderr(vm)
+            {
+                let kwargs: KwArgs = [("file".to_string(), stderr_obj)].into_iter().collect();
+                let _ = print_tb.call(
+                    FuncArgs::new(vec![unraisable.exc_traceback.clone()], kwargs),
+                    vm,
+                );
+            }
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Print traceback (using actual exc_traceback, not current stack)
if !vm.is_none(&unraisable.exc_traceback) {
let tb_module = vm.import("traceback", 0)?;
let print_tb = tb_module.get_attr("print_tb", vm)?;
let stderr_obj = super::get_stderr(vm)?;
let kwargs: KwArgs = [("file".to_string(), stderr_obj)].into_iter().collect();
let _ = print_tb.call(
FuncArgs::new(vec![unraisable.exc_traceback.clone()], kwargs),
vm,
);
}
// Print traceback (using actual exc_traceback, not current stack)
if !vm.is_none(&unraisable.exc_traceback) {
if let Ok(tb_module) = vm.import("traceback", 0)
&& let Ok(print_tb) = tb_module.get_attr("print_tb", vm)
&& let Ok(stderr_obj) = super::get_stderr(vm)
{
let kwargs: KwArgs = [("file".to_string(), stderr_obj)].into_iter().collect();
let _ = print_tb.call(
FuncArgs::new(vec![unraisable.exc_traceback.clone()], kwargs),
vm,
);
}
}
🤖 Prompt for AI Agents
In crates/vm/src/stdlib/sys.rs around lines 691 to 701, the use of the `?`
operator on `vm.import("traceback", 0)` and `tb_module.get_attr("print_tb", vm)`
can return early and suppress the rest of the unraisable hook output; change
these to explicit error-handling so failures do not propagate out: attempt to
import the "traceback" module with a match/if-let, and if that fails, write a
minimal note or ignore and continue without returning; if import succeeds,
attempt to get the "print_tb" attribute with a match/if-let, and if that fails
similarly continue; only call `print_tb` when both steps succeed, and ensure any
incidental errors are caught (not propagated) and optionally logged to stderr
via `super::get_stderr(vm)?` so the unraisable exception type/value remains
printed.


// Check exc_type
if vm.is_none(unraisable.exc_type.as_object()) {
// TODO: early return, but with what error?
return Ok(());
}
assert!(
unraisable
.exc_type
.fast_issubclass(vm.ctx.exceptions.base_exception_type)
);

// TODO: print module name and qualname
// Print module name (if not builtins or __main__)
let module_name = unraisable.exc_type.__module__(vm);
if let Ok(module_str) = module_name.downcast::<PyStr>() {
let module = module_str.as_str();
if module != "builtins" && module != "__main__" {
write!(stderr, "{}.", module);
}
} else {
write!(stderr, "<unknown>.");
}

// Print qualname
let qualname = unraisable.exc_type.__qualname__(vm);
if let Ok(qualname_str) = qualname.downcast::<PyStr>() {
write!(stderr, "{}", qualname_str.as_str());
} else {
write!(stderr, "{}", unraisable.exc_type.name());
}

// Print exception value
if !vm.is_none(&unraisable.exc_value) {
write!(stderr, "{}: ", unraisable.exc_type);
write!(stderr, ": ");
if let Ok(str) = unraisable.exc_value.str(vm) {
write!(stderr, "{}", str.to_str().unwrap_or("<str with surrogate>"));
} else {
write!(stderr, "<exception str() failed>");
}
}
writeln!(stderr);
// TODO: call file.flush()

// Flush stderr
if let Ok(stderr_obj) = super::get_stderr(vm)
&& let Ok(flush) = stderr_obj.get_attr("flush", vm)
{
let _ = flush.call((), vm);
}

Ok(())
}
Expand Down
Loading