{"record":{"id":"b2bbd61aad004067","repo":"nautechsystems/nautilus_trader","slug":"cstr-from-ptr-failed","errorCode":null,"errorMessage":"CStr::from_ptr failed","messagePattern":"CStr::from_ptr failed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/core/src/ffi/string.rs","lineNumber":72,"sourceCode":"    // SAFETY: Caller guarantees ptr is borrowed from a valid Python UTF-8 str\n    Python::attach(|py| unsafe { Bound::from_borrowed_ptr(py, ptr).to_string() })\n}\n\n/// Convert a C string pointer into an owned `Ustr`.\n///\n/// # Safety\n///\n/// Assumes `ptr` is a valid C string pointer.\n///\n/// # Panics\n///\n/// Panics if `ptr` is null.\n#[must_use]\npub unsafe fn cstr_to_ustr(ptr: *const c_char) -> Ustr {\n    assert!(!ptr.is_null(), \"`ptr` was NULL\");\n    // SAFETY: Caller guarantees ptr is valid per function contract\n    let cstr = unsafe { CStr::from_ptr(ptr) };\n    Ustr::from(cstr.to_str().expect(\"CStr::from_ptr failed\"))\n}\n\n/// Convert a C string pointer into a borrowed byte slice.\n///\n/// # Safety\n///\n/// - Assumes `ptr` is a valid, null-terminated UTF-8 C string pointer.\n/// - The returned slice borrows the underlying allocation; callers must ensure the\n///   C buffer outlives every use of the slice.\n///\n/// # Panics\n///\n/// Panics if `ptr` is null.\n#[must_use]\npub unsafe fn cstr_to_bytes<'a>(ptr: *const c_char) -> &'a [u8] {\n    assert!(!ptr.is_null(), \"`ptr` was NULL\");\n    // SAFETY: Caller guarantees ptr is valid per function contract\n    let cstr = unsafe { CStr::from_ptr(ptr) };","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/core/src/ffi/string.rs#L54-L90","documentation":"cstr_to_ustr in crates/core/src/ffi/string.rs:72 converts a non-null C string pointer into an interned Ustr. It asserts the pointer is non-null first, then converts the CStr bytes to &str with to_str().expect(\"CStr::from_ptr failed\"), panicking when the bytes are not valid UTF-8. (Note: CStr::from_ptr itself only fails on a null pointer, which the assert already rejects — this expect fires on invalid UTF-8 in the buffer.)","triggerScenarios":"Calling cstr_to_ustr (directly or via optional_cstr_to_ustr, OrderDeniedFfi, OrderRejectedFfi deserialization) with a pointer to bytes that are not UTF-8: Latin-1 or GBK-encoded text, partial multi-byte characters cut by a buffer boundary, or random memory not intended as a string.","commonSituations":"A C/Python producer encoding strings in a legacy codepage instead of UTF-8; a struct field written as raw bytes without null-termination rules; truncated UTF-8 after a memcpy of the wrong length.","solutions":["Ensure the producer encodes all strings as UTF-8 before placing them in the buffer (Python: str.encode('utf-8'); C: use UTF-8 literals/sources).","Verify buffer lengths so multi-byte characters are not truncated mid-sequence.","If input encoding is out of your control, use lossy conversion on the producer side or sanitize the string (encode to UTF-8 with replacement) before the FFI call.","Inspect the raw bytes at the pointer to identify the actual encoding and re-encode it."],"exampleFix":"// before (Python producer)\nb\"caf\\xe9\"            # Latin-1 encoded, invalid UTF-8\n// after\n\"café\".encode(\"utf-8\")  # b'caf\\xc3\\xa9', valid UTF-8","handlingStrategy":"validation","validationCode":"# Python producer, before FFI\nraw = text.encode(\"utf-8\")            # raises UnicodeEncodeError if already mojibake\nraw.decode(\"utf-8\")                   # round-trip: guarantees valid UTF-8 bytes","typeGuard":"def is_utf8(b: bytes) -> bool:\n    try:\n        b.decode(\"utf-8\"); return True\n    except UnicodeDecodeError:\n        return False","tryCatchPattern":null,"preventionTips":["Standardize on UTF-8 for every producer writing into FFI buffers.","Decode vendor data with its true encoding, then re-encode to UTF-8.","Check buffer lengths so multi-byte characters are never split.","Test with non-ASCII symbols/labels (e.g. 'café', CJK) to flush out encoding bugs."],"tags":["ffi","utf-8","encoding","panic"],"backgroundTag":"invalid-argument-format","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}