sanpii / libpq.rs

Rust safe binding for libpq

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Incorrect use of CString::from_vec_unchecked

zopsicle opened this issue · comments

CString::from_vec_unchecked requires that the argument does not contain interior nuls.

The function to_cstr does not guard against interior nuls in the argument:

libpq.rs/src/ffi.rs

Lines 3 to 5 in 9e161c3

pub(crate) fn to_cstr(s: &str) -> std::ffi::CString {
unsafe { std::ffi::CString::from_vec_unchecked(s.as_bytes().to_vec()) }
}

This function is called on user input in several places, such as here:

let c_name = crate::ffi::to_cstr(name.unwrap_or_default());
let c_query = crate::ffi::to_cstr(query);

Which means the safety requirement of CString::from_vec_unchecked can be violated by passing e.g. "\0" to Connection::prepare.

The function new_cstring likewise violates the safety requirement when given any non-zero argument.

commented

I don’t understand why CString::from_vec_unchecked has marked as unsafe, all called functions internally are safe.

Calling Connection::exec with a string containing a null bit work as expected:

fn main() {
    let conn = libpq::Connection::new("host=localhost").unwrap();
    let results = conn.exec("\0select 1;");
    assert_eq!(results.status(), libpq::Status::EmptyQuery);
}

The old behavior is to panic. From my point of view it seems less acceptable.

According to this, this call is marked as unsafe due to a design contract and this is not related to memory safety: CString is guaranteed to not have interior nulls, as the documentation states that CString is "A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the middle."

IMHO, This clarification renders this issue safe to be closed.

Thank you.