std::ffi::CString segmentation fault

I met a strange CString behavior.
When I call
let source: CString = CString::new("1234567").unwrap();
I get Segmentation Fault 11

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Segmentation fault: 11
Termination Reason:    Namespace SIGNAL, Code 0xb
Terminating Process:   exc handler [0]

But it works when I do
let source: CString = CString::new("12345678").unwrap();
or pass any string with 8 characters at least.

Are you sure you're not using source.as_ptr() value outside scope of the variable anywhere? The temporary validity of the pointer is the common source of crashes here.

@kornel I call as_ptr() before, in other function scope and for other variable.

fn foo() {
    let source: CString = CString::new("
        multiple line string
        blabla
    ").unwrap();
    let srcptr = source.as_ptr();
    bar(srcptr, source.as_bytes().len()); // unsafe block
}

fn main() {
    foo();
    let source: CString = CString::new("1234567").unwrap(); // SegFault here
}

This smells of corruption somewhere. What does bar() do/look like?

@vitalyd Well, this is kind of opengl stuff.

fn bar(....) -> .... {
    unsafe {
        ...
        gl.ShaderSource(shader, 1, &source, &len);
        ...
    }
}

I didn't find other way to pass *const *const GLchar

SOLVED
Inside bar() I call from_raw() breaking the safety rule. I passed a pointer value that was generated by opengl function.
I switched to use String::from_raw_parts instead of CString and the problem has gone.

let mut log: [i8; 512] = [0; 512];
let log_ptr: *mut i8 = &mut log[0];
let length: *mut i32 = &mut 0;
gl.GetShaderInfoLog(shader, 512, length, log_ptr);
// let s = CString::from_raw(log_ptr);
let s = String::from_raw_parts(log_ptr as *mut u8, *length as usize, 512);
println!("{:?}", s);

Yeah, that would do it :slight_smile:. You've probably already seen it, but CStr can be used to view a C string without taking ownership of it (it's basically the &str analog to Rust's String, but for CString).

1 Like

This may crash and cause corruption as well, because Rust will try to free String's pointer using its jemalloc, and you're using stack-allocated object here.

String::from_raw_parts is a risky hack that you shouldn't normally need, and it's probably unsafe to use with anything other than another String or Vec's raw parts, carefully taken.

1 Like