Skip to content

Commit

Permalink
src/templ.rs: fix handling of C string slices
Browse files Browse the repository at this point in the history
CommandLineParser is currently misbehaving due to improper data in
its input argv parameter. The problem is caused by a blind cast of
argv entries from &str into a C-like string, which does not offer the
null termination guarantees. To fix that, create an actual CString
and hold it while the pointer is in use.

It's worth noting that the mutable version of the macro still relies
on undefined behavior, but this time of CString which does not
guarantee correctness if its data is written into.
  • Loading branch information
niemeyer committed Sep 2, 2024
1 parent c2ff7dc commit c8205ea
Showing 1 changed file with 11 additions and 2 deletions.
13 changes: 11 additions & 2 deletions src/templ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,26 @@ macro_rules! string_array_arg {
($name: ident) => {
let $name = $name
.iter()
.map(|x| x.as_ptr().cast::<::std::ffi::c_char>())
.map(|x| ::std::ffi::CString::new(*x).expect("invalid C string"))
.collect::<::std::vec::Vec<_>>();
let $name = $name
.iter()
.map(|x| x.as_ptr())
.collect::<::std::vec::Vec<_>>();
};
}

#[allow(unused_macros)]
macro_rules! string_array_arg_mut {
($name: ident) => {
let $name = $name
.iter()
.map(|x| ::std::ffi::CString::new(*x).expect("invalid C string"))
.collect::<::std::vec::Vec<_>>();
// Casting to mut below trusts on undefined CString behavior.
let mut $name = $name
.iter()
.map(|x| x.as_ptr().cast::<::std::ffi::c_char>().cast_mut())
.map(|x| x.as_ptr().cast_mut())
.collect::<::std::vec::Vec<_>>();
};
}
Expand Down

0 comments on commit c8205ea

Please sign in to comment.