Skip to content

Commit c0a8268

Browse files
committed
Dont use Vec
1 parent 411420c commit c0a8268

File tree

1 file changed

+52
-34
lines changed

1 file changed

+52
-34
lines changed

src/native/crashtracker.rs

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,8 @@ static DUMP_TRACEBACK_INIT: std::sync::Once = std::sync::Once::new();
3636
extern "C" {
3737
fn pipe(pipefd: *mut [c_int; 2]) -> c_int;
3838
fn read(fd: c_int, buf: *mut c_void, count: usize) -> isize;
39-
fn write(fd: c_int, buf: *const c_void, count: usize) -> isize;
4039
fn close(fd: c_int) -> c_int;
4140
fn fcntl(fd: c_int, cmd: c_int, arg: c_int) -> c_int;
42-
#[cfg(unix)]
43-
fn PyThreadState_Next(prev: *mut pyo3_ffi::PyThreadState) -> *mut pyo3_ffi::PyThreadState;
4441
}
4542

4643
pub trait RustWrapper {
@@ -358,18 +355,13 @@ const MAX_TRACEBACK_SIZE: usize = 8 * 1024; // 8KB
358355
const FRAME_FUNCTION_CAP: usize = 256;
359356
#[cfg(unix)]
360357
const FRAME_FILE_CAP: usize = 512;
361-
#[cfg(unix)]
362-
const FRAME_TYPE_CAP: usize = 256;
363358

364359
#[cfg(unix)]
365360
static FRAME_COLLECTION_GUARD: AtomicBool = AtomicBool::new(false);
366361

367362
#[cfg(unix)]
368363
unsafe fn capture_frames_via_python(emit_frame: unsafe extern "C" fn(&RuntimeStackFrame)) {
369-
let mut emitted = false;
370-
371364
let current = pyo3_ffi::PyThreadState_Get();
372-
373365
if !current.is_null() {
374366
let _ = collect_and_emit_frames_for_thread(current, emit_frame);
375367
}
@@ -430,60 +422,86 @@ unsafe fn emit_python_frame(
430422
return false;
431423
}
432424

433-
let mut file = get_code_attr_utf8(frame, b"co_filename\0");
434-
if file.len() > FRAME_FILE_CAP {
435-
file.truncate(FRAME_FILE_CAP);
436-
}
437-
438-
let mut function = get_code_attr_utf8(frame, b"co_name\0");
439-
if function.len() > FRAME_FUNCTION_CAP {
440-
function.truncate(FRAME_FUNCTION_CAP);
441-
}
425+
let file_view = get_code_attr_utf8_view(frame, b"co_filename\0");
426+
let function_view = get_code_attr_utf8_view(frame, b"co_name\0");
442427
let line_number = pyo3_ffi::PyFrame_GetLineNumber(frame);
443428

429+
let file_slice = file_view
430+
.as_ref()
431+
.map(|view| view.truncated(FRAME_FILE_CAP))
432+
.unwrap_or(&[]);
433+
let function_slice = function_view
434+
.as_ref()
435+
.map(|view| view.truncated(FRAME_FUNCTION_CAP))
436+
.unwrap_or(&[]);
437+
444438
let runtime_frame = RuntimeStackFrame {
445439
line: if line_number < 0 {
446440
0
447441
} else {
448442
line_number as u32
449443
},
450444
column: 0,
451-
function: function.as_slice(),
452-
file: file.as_slice(),
445+
function: function_slice,
446+
file: file_slice,
453447
type_name: &[],
454448
};
455449

456450
emit_frame(&runtime_frame);
451+
452+
if let Some(view) = file_view {
453+
pyo3_ffi::Py_DecRef(view.obj);
454+
}
455+
if let Some(view) = function_view {
456+
pyo3_ffi::Py_DecRef(view.obj);
457+
}
457458
true
458459
}
459460

461+
struct Utf8View {
462+
ptr: *const u8,
463+
len: usize,
464+
obj: *mut pyo3_ffi::PyObject,
465+
}
466+
467+
impl Utf8View {
468+
/// Safety: caller must ensure the underlying PyObject outlives the returned slice.
469+
/// This should be safe since no garbage collection should be happening while suspended in
470+
/// crash context
471+
fn truncated(&self, cap: usize) -> &[u8] {
472+
let len = cmp::min(self.len, cap);
473+
unsafe { slice::from_raw_parts(self.ptr, len) }
474+
}
475+
}
476+
477+
/// Returns a view into a PyUnicode attribute without allocating; caller must Py_DecRef `obj`.
460478
#[cfg(unix)]
461-
unsafe fn get_code_attr_utf8(frame: *mut pyo3_ffi::PyFrameObject, attr: &[u8]) -> Vec<u8> {
479+
unsafe fn get_code_attr_utf8_view(
480+
frame: *mut pyo3_ffi::PyFrameObject,
481+
attr: &[u8],
482+
) -> Option<Utf8View> {
462483
let code_obj = pyo3_ffi::PyFrame_GetCode(frame) as *mut pyo3_ffi::PyObject;
463484
if code_obj.is_null() {
464-
return Vec::new();
485+
return None;
465486
}
466487
let attr_obj = pyo3_ffi::PyObject_GetAttrString(code_obj, attr.as_ptr() as *const c_char);
467488
pyo3_ffi::Py_DecRef(code_obj);
468489
if attr_obj.is_null() {
469-
return Vec::new();
490+
return None;
470491
}
471-
let data = py_unicode_to_vec(attr_obj);
472-
pyo3_ffi::Py_DecRef(attr_obj);
473-
data
474-
}
475492

476-
#[cfg(unix)]
477-
unsafe fn py_unicode_to_vec(obj: *mut pyo3_ffi::PyObject) -> Vec<u8> {
478-
if obj.is_null() {
479-
return Vec::new();
480-
}
481493
let mut size: pyo3_ffi::Py_ssize_t = 0;
482-
let data = pyo3_ffi::PyUnicode_AsUTF8AndSize(obj, &mut size);
494+
let data = pyo3_ffi::PyUnicode_AsUTF8AndSize(attr_obj, &mut size);
483495
if data.is_null() || size <= 0 {
484-
return Vec::new();
496+
pyo3_ffi::Py_DecRef(attr_obj);
497+
return None;
485498
}
486-
slice::from_raw_parts(data as *const u8, size as usize).to_vec()
499+
500+
Some(Utf8View {
501+
ptr: data as *const u8,
502+
len: size as usize,
503+
obj: attr_obj,
504+
})
487505
}
488506

489507
// Attempt to resolve _Py_DumpTracebackThreads at runtime

0 commit comments

Comments
 (0)