Skip to content

Commit d0dee6c

Browse files
committed
fix: Make sure that panic! is handled according to policy (either disable or abort)
1 parent a49c8bf commit d0dee6c

File tree

2 files changed

+136
-106
lines changed

2 files changed

+136
-106
lines changed

codetracer-python-recorder/src/ffi.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ where
4646
}
4747

4848
/// Convert a captured panic into a `PyInternalError` while logging the payload.
49+
pub(crate) fn panic_to_pyerr(label: &'static str, payload: Box<dyn Any + Send>) -> PyErr {
50+
handle_panic(label, payload)
51+
}
52+
4953
fn handle_panic(label: &'static str, payload: Box<dyn Any + Send>) -> PyErr {
5054
let message = panic_payload_to_string(&payload);
5155
logging::record_panic(label);

codetracer-python-recorder/src/monitoring/tracer.rs

Lines changed: 132 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Tracer trait and sys.monitoring callback plumbing.
22
33
use std::any::Any;
4+
use std::panic::{catch_unwind, AssertUnwindSafe};
45
use std::sync::Mutex;
56

67
use crate::code_object::{CodeObjectRegistry, CodeObjectWrapper};
@@ -264,6 +265,32 @@ struct Global {
264265

265266
static GLOBAL: Mutex<Option<Global>> = Mutex::new(None);
266267

268+
fn catch_callback<F>(label: &'static str, callback: F) -> CallbackResult
269+
where
270+
F: FnOnce() -> CallbackResult,
271+
{
272+
match catch_unwind(AssertUnwindSafe(callback)) {
273+
Ok(result) => result,
274+
Err(payload) => Err(ffi::panic_to_pyerr(label, payload)),
275+
}
276+
}
277+
278+
fn call_tracer_with_code<'py, F>(
279+
py: Python<'py>,
280+
guard: &mut Option<Global>,
281+
code: &Bound<'py, PyCode>,
282+
label: &'static str,
283+
callback: F,
284+
) -> CallbackResult
285+
where
286+
F: FnOnce(&mut dyn Tracer, &CodeObjectWrapper) -> CallbackResult,
287+
{
288+
let global = guard.as_mut().expect("tracer installed");
289+
let wrapper = global.registry.get_or_insert(py, code);
290+
let tracer = global.tracer.as_mut();
291+
catch_callback(label, || callback(tracer, &wrapper))
292+
}
293+
267294
fn handle_callback_result(
268295
py: Python<'_>,
269296
guard: &mut Option<Global>,
@@ -519,13 +546,10 @@ fn callback_call(
519546
if guard.is_none() {
520547
return Ok(py.None());
521548
}
522-
let result = {
523-
let global = guard.as_mut().expect("tracer installed");
524-
let wrapper = global.registry.get_or_insert(py, &code);
525-
global
526-
.tracer
527-
.on_call(py, &wrapper, offset, &callable, arg0.as_ref())
528-
};
549+
let result =
550+
call_tracer_with_code(py, &mut guard, &code, "callback_call", |tracer, wrapper| {
551+
tracer.on_call(py, wrapper, offset, &callable, arg0.as_ref())
552+
});
529553
handle_callback_result(py, &mut guard, result)
530554
})
531555
}
@@ -537,11 +561,10 @@ fn callback_line(py: Python<'_>, code: Bound<'_, PyCode>, lineno: u32) -> PyResu
537561
if guard.is_none() {
538562
return Ok(py.None());
539563
}
540-
let result = {
541-
let global = guard.as_mut().expect("tracer installed");
542-
let wrapper = global.registry.get_or_insert(py, &code);
543-
global.tracer.on_line(py, &wrapper, lineno)
544-
};
564+
let result =
565+
call_tracer_with_code(py, &mut guard, &code, "callback_line", |tracer, wrapper| {
566+
tracer.on_line(py, wrapper, lineno)
567+
});
545568
handle_callback_result(py, &mut guard, result)
546569
})
547570
}
@@ -557,13 +580,13 @@ fn callback_instruction(
557580
if guard.is_none() {
558581
return Ok(py.None());
559582
}
560-
let result = {
561-
let global = guard.as_mut().expect("tracer installed");
562-
let wrapper = global.registry.get_or_insert(py, &code);
563-
global
564-
.tracer
565-
.on_instruction(py, &wrapper, instruction_offset)
566-
};
583+
let result = call_tracer_with_code(
584+
py,
585+
&mut guard,
586+
&code,
587+
"callback_instruction",
588+
|tracer, wrapper| tracer.on_instruction(py, wrapper, instruction_offset),
589+
);
567590
handle_callback_result(py, &mut guard, result)
568591
})
569592
}
@@ -580,13 +603,10 @@ fn callback_jump(
580603
if guard.is_none() {
581604
return Ok(py.None());
582605
}
583-
let result = {
584-
let global = guard.as_mut().expect("tracer installed");
585-
let wrapper = global.registry.get_or_insert(py, &code);
586-
global
587-
.tracer
588-
.on_jump(py, &wrapper, instruction_offset, destination_offset)
589-
};
606+
let result =
607+
call_tracer_with_code(py, &mut guard, &code, "callback_jump", |tracer, wrapper| {
608+
tracer.on_jump(py, wrapper, instruction_offset, destination_offset)
609+
});
590610
handle_callback_result(py, &mut guard, result)
591611
})
592612
}
@@ -603,13 +623,13 @@ fn callback_branch(
603623
if guard.is_none() {
604624
return Ok(py.None());
605625
}
606-
let result = {
607-
let global = guard.as_mut().expect("tracer installed");
608-
let wrapper = global.registry.get_or_insert(py, &code);
609-
global
610-
.tracer
611-
.on_branch(py, &wrapper, instruction_offset, destination_offset)
612-
};
626+
let result = call_tracer_with_code(
627+
py,
628+
&mut guard,
629+
&code,
630+
"callback_branch",
631+
|tracer, wrapper| tracer.on_branch(py, wrapper, instruction_offset, destination_offset),
632+
);
613633
handle_callback_result(py, &mut guard, result)
614634
})
615635
}
@@ -625,11 +645,13 @@ fn callback_py_start(
625645
if guard.is_none() {
626646
return Ok(py.None());
627647
}
628-
let result = {
629-
let global = guard.as_mut().expect("tracer installed");
630-
let wrapper = global.registry.get_or_insert(py, &code);
631-
global.tracer.on_py_start(py, &wrapper, instruction_offset)
632-
};
648+
let result = call_tracer_with_code(
649+
py,
650+
&mut guard,
651+
&code,
652+
"callback_py_start",
653+
|tracer, wrapper| tracer.on_py_start(py, wrapper, instruction_offset),
654+
);
633655
handle_callback_result(py, &mut guard, result)
634656
})
635657
}
@@ -645,11 +667,13 @@ fn callback_py_resume(
645667
if guard.is_none() {
646668
return Ok(py.None());
647669
}
648-
let result = {
649-
let global = guard.as_mut().expect("tracer installed");
650-
let wrapper = global.registry.get_or_insert(py, &code);
651-
global.tracer.on_py_resume(py, &wrapper, instruction_offset)
652-
};
670+
let result = call_tracer_with_code(
671+
py,
672+
&mut guard,
673+
&code,
674+
"callback_py_resume",
675+
|tracer, wrapper| tracer.on_py_resume(py, wrapper, instruction_offset),
676+
);
653677
handle_callback_result(py, &mut guard, result)
654678
})
655679
}
@@ -666,13 +690,13 @@ fn callback_py_return(
666690
if guard.is_none() {
667691
return Ok(py.None());
668692
}
669-
let result = {
670-
let global = guard.as_mut().expect("tracer installed");
671-
let wrapper = global.registry.get_or_insert(py, &code);
672-
global
673-
.tracer
674-
.on_py_return(py, &wrapper, instruction_offset, &retval)
675-
};
693+
let result = call_tracer_with_code(
694+
py,
695+
&mut guard,
696+
&code,
697+
"callback_py_return",
698+
|tracer, wrapper| tracer.on_py_return(py, wrapper, instruction_offset, &retval),
699+
);
676700
handle_callback_result(py, &mut guard, result)
677701
})
678702
}
@@ -689,13 +713,13 @@ fn callback_py_yield(
689713
if guard.is_none() {
690714
return Ok(py.None());
691715
}
692-
let result = {
693-
let global = guard.as_mut().expect("tracer installed");
694-
let wrapper = global.registry.get_or_insert(py, &code);
695-
global
696-
.tracer
697-
.on_py_yield(py, &wrapper, instruction_offset, &retval)
698-
};
716+
let result = call_tracer_with_code(
717+
py,
718+
&mut guard,
719+
&code,
720+
"callback_py_yield",
721+
|tracer, wrapper| tracer.on_py_yield(py, wrapper, instruction_offset, &retval),
722+
);
699723
handle_callback_result(py, &mut guard, result)
700724
})
701725
}
@@ -712,13 +736,13 @@ fn callback_py_throw(
712736
if guard.is_none() {
713737
return Ok(py.None());
714738
}
715-
let result = {
716-
let global = guard.as_mut().expect("tracer installed");
717-
let wrapper = global.registry.get_or_insert(py, &code);
718-
global
719-
.tracer
720-
.on_py_throw(py, &wrapper, instruction_offset, &exception)
721-
};
739+
let result = call_tracer_with_code(
740+
py,
741+
&mut guard,
742+
&code,
743+
"callback_py_throw",
744+
|tracer, wrapper| tracer.on_py_throw(py, wrapper, instruction_offset, &exception),
745+
);
722746
handle_callback_result(py, &mut guard, result)
723747
})
724748
}
@@ -735,13 +759,13 @@ fn callback_py_unwind(
735759
if guard.is_none() {
736760
return Ok(py.None());
737761
}
738-
let result = {
739-
let global = guard.as_mut().expect("tracer installed");
740-
let wrapper = global.registry.get_or_insert(py, &code);
741-
global
742-
.tracer
743-
.on_py_unwind(py, &wrapper, instruction_offset, &exception)
744-
};
762+
let result = call_tracer_with_code(
763+
py,
764+
&mut guard,
765+
&code,
766+
"callback_py_unwind",
767+
|tracer, wrapper| tracer.on_py_unwind(py, wrapper, instruction_offset, &exception),
768+
);
745769
handle_callback_result(py, &mut guard, result)
746770
})
747771
}
@@ -758,13 +782,13 @@ fn callback_raise(
758782
if guard.is_none() {
759783
return Ok(py.None());
760784
}
761-
let result = {
762-
let global = guard.as_mut().expect("tracer installed");
763-
let wrapper = global.registry.get_or_insert(py, &code);
764-
global
765-
.tracer
766-
.on_raise(py, &wrapper, instruction_offset, &exception)
767-
};
785+
let result = call_tracer_with_code(
786+
py,
787+
&mut guard,
788+
&code,
789+
"callback_raise",
790+
|tracer, wrapper| tracer.on_raise(py, wrapper, instruction_offset, &exception),
791+
);
768792
handle_callback_result(py, &mut guard, result)
769793
})
770794
}
@@ -781,13 +805,13 @@ fn callback_reraise(
781805
if guard.is_none() {
782806
return Ok(py.None());
783807
}
784-
let result = {
785-
let global = guard.as_mut().expect("tracer installed");
786-
let wrapper = global.registry.get_or_insert(py, &code);
787-
global
788-
.tracer
789-
.on_reraise(py, &wrapper, instruction_offset, &exception)
790-
};
808+
let result = call_tracer_with_code(
809+
py,
810+
&mut guard,
811+
&code,
812+
"callback_reraise",
813+
|tracer, wrapper| tracer.on_reraise(py, wrapper, instruction_offset, &exception),
814+
);
791815
handle_callback_result(py, &mut guard, result)
792816
})
793817
}
@@ -804,13 +828,15 @@ fn callback_exception_handled(
804828
if guard.is_none() {
805829
return Ok(py.None());
806830
}
807-
let result = {
808-
let global = guard.as_mut().expect("tracer installed");
809-
let wrapper = global.registry.get_or_insert(py, &code);
810-
global
811-
.tracer
812-
.on_exception_handled(py, &wrapper, instruction_offset, &exception)
813-
};
831+
let result = call_tracer_with_code(
832+
py,
833+
&mut guard,
834+
&code,
835+
"callback_exception_handled",
836+
|tracer, wrapper| {
837+
tracer.on_exception_handled(py, wrapper, instruction_offset, &exception)
838+
},
839+
);
814840
handle_callback_result(py, &mut guard, result)
815841
})
816842
}
@@ -844,13 +870,13 @@ fn callback_c_return(
844870
if guard.is_none() {
845871
return Ok(py.None());
846872
}
847-
let result = {
848-
let global = guard.as_mut().expect("tracer installed");
849-
let wrapper = global.registry.get_or_insert(py, &code);
850-
global
851-
.tracer
852-
.on_c_return(py, &wrapper, offset, &callable, arg0.as_ref())
853-
};
873+
let result = call_tracer_with_code(
874+
py,
875+
&mut guard,
876+
&code,
877+
"callback_c_return",
878+
|tracer, wrapper| tracer.on_c_return(py, wrapper, offset, &callable, arg0.as_ref()),
879+
);
854880
handle_callback_result(py, &mut guard, result)
855881
})
856882
}
@@ -868,13 +894,13 @@ fn callback_c_raise(
868894
if guard.is_none() {
869895
return Ok(py.None());
870896
}
871-
let result = {
872-
let global = guard.as_mut().expect("tracer installed");
873-
let wrapper = global.registry.get_or_insert(py, &code);
874-
global
875-
.tracer
876-
.on_c_raise(py, &wrapper, offset, &callable, arg0.as_ref())
877-
};
897+
let result = call_tracer_with_code(
898+
py,
899+
&mut guard,
900+
&code,
901+
"callback_c_raise",
902+
|tracer, wrapper| tracer.on_c_raise(py, wrapper, offset, &callable, arg0.as_ref()),
903+
);
878904
handle_callback_result(py, &mut guard, result)
879905
})
880906
}

0 commit comments

Comments
 (0)