diff --git a/src/byte_literal.rs b/src/byte_literal.rs index 22857223f1..10f8976bd4 100644 --- a/src/byte_literal.rs +++ b/src/byte_literal.rs @@ -1,15 +1,30 @@ use crate::platform::types::c_char; +/// An abstraction over a byte literal to provide a method to convert safely +/// to a `c_char`. +/// +/// The abstraction is required so we can contain architecture specific code +/// in a central location. pub struct ByteLiteral; impl ByteLiteral { - pub fn cast_unchecked(input: u8) -> c_char { + /// Casts a byte literal (`u8`) to a `c_char` without using `as`. + /// + /// # Panics + /// If `input` is not within the following range of ascii characters: + /// - Octal: `040`..=`176` + /// - Decimal: `30`..=`126` + /// - Hexadecimal: `20`..=`7E` + /// - Byte literals: b` `..=b`~` + pub fn cast_cchar(input: u8) -> c_char { match input { b' '..=b'~' => { + // `c_char` is an `i8` on these arches #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] { input.cast_signed() } + // `c_char` is already a `u8` on these arches #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] { input.into() diff --git a/src/header/fmtmsg/mod.rs b/src/header/fmtmsg/mod.rs index 6021b0629d..dd64dde670 100644 --- a/src/header/fmtmsg/mod.rs +++ b/src/header/fmtmsg/mod.rs @@ -78,7 +78,7 @@ unsafe fn strcolcmp(mut lstr: *const c_char, mut bstr: *const c_char) -> c_int { lstr = lstr.add(1); bstr = bstr.add(1); } - if *lstr != 0 || (*bstr != 0 && *bstr != ByteLiteral::cast_unchecked(b':')) { + if *lstr != 0 || (*bstr != 0 && *bstr != ByteLiteral::cast_cchar(b':')) { 1 } else { 0 diff --git a/src/header/getopt/mod.rs b/src/header/getopt/mod.rs index 0630510a02..ecc8074b65 100644 --- a/src/header/getopt/mod.rs +++ b/src/header/getopt/mod.rs @@ -62,7 +62,7 @@ pub unsafe extern "C" fn getopt_long( let current_arg = unsafe { *argv.offset(optind as isize) }; if unsafe { current_arg.is_null() - || *current_arg != ByteLiteral::cast_unchecked(b'-') + || *current_arg != ByteLiteral::cast_cchar(b'-') || *current_arg.offset(1) == 0 } { -1 @@ -75,9 +75,7 @@ pub unsafe extern "C" fn getopt_long( // remove the '-' let current_arg = unsafe { current_arg.offset(1) }; - if unsafe { *current_arg == ByteLiteral::cast_unchecked(b'-') } - && !longopts.is_null() - { + if unsafe { *current_arg == ByteLiteral::cast_cchar(b'-') } && !longopts.is_null() { let current_arg = unsafe { current_arg.offset(1) }; // is a long option for i in 0.. { @@ -89,7 +87,7 @@ pub unsafe extern "C" fn getopt_long( let mut end = 0; while { let c = unsafe { *current_arg.offset(end) }; - c != 0 && c != ByteLiteral::cast_unchecked(b'=') + c != 0 && c != ByteLiteral::cast_cchar(b'=') } { end += 1; } @@ -104,20 +102,18 @@ pub unsafe extern "C" fn getopt_long( if opt.has_arg == optional_argument { unsafe { - if *current_arg.offset(end) == ByteLiteral::cast_unchecked(b'=') - { + if *current_arg.offset(end) == ByteLiteral::cast_cchar(b'=') { optarg = current_arg.offset(end + 1); } } } else if opt.has_arg == required_argument { unsafe { - if *current_arg.offset(end) == ByteLiteral::cast_unchecked(b'=') - { + if *current_arg.offset(end) == ByteLiteral::cast_cchar(b'=') { optarg = current_arg.offset(end + 1); } else if optind < argc { optarg = *argv.offset(optind as isize); optind += 1; - } else if *optstring == ByteLiteral::cast_unchecked(b':') { + } else if *optstring == ByteLiteral::cast_cchar(b':') { return c_int::from(b':'); } else { stdio::fputs((*argv).cast_const(), &raw mut *stdio::stderr); @@ -188,7 +184,7 @@ unsafe fn parse_arg( CURRENT_OPT = ptr::null_mut(); optopt = c_int::from(*current_arg); - let errch = if *optstring == ByteLiteral::cast_unchecked(b':') { + let errch = if *optstring == ByteLiteral::cast_cchar(b':') { b':' } else { if opterr != 0 { @@ -236,8 +232,7 @@ unsafe fn find_option(ch: c_char, optstring: *const c_char) -> Option *mut c_char { return c".".as_ptr().cast_mut(); } let mut end = unsafe { strlen(str) as isize - 1 }; - while end >= 0 && unsafe { *str.offset(end) == ByteLiteral::cast_unchecked(b'/') } { + while end >= 0 && unsafe { *str.offset(end) == ByteLiteral::cast_cchar(b'/') } { end -= 1; } if end == -1 { return c"/".as_ptr().cast_mut(); } let mut begin = end; - while begin >= 0 && unsafe { *str.offset(begin) != ByteLiteral::cast_unchecked(b'/') } { + while begin >= 0 && unsafe { *str.offset(begin) != ByteLiteral::cast_cchar(b'/') } { begin -= 1; } unsafe { @@ -34,13 +34,13 @@ pub unsafe extern "C" fn dirname(str: *mut c_char) -> *mut c_char { return c".".as_ptr().cast_mut(); } let mut end = unsafe { strlen(str) as isize - 1 }; - while end > 0 && unsafe { *str.offset(end) == ByteLiteral::cast_unchecked(b'/') } { + while end > 0 && unsafe { *str.offset(end) == ByteLiteral::cast_cchar(b'/') } { end -= 1; } - while end >= 0 && unsafe { *str.offset(end) != ByteLiteral::cast_unchecked(b'/') } { + while end >= 0 && unsafe { *str.offset(end) != ByteLiteral::cast_cchar(b'/') } { end -= 1; } - while end > 0 && unsafe { *str.offset(end) == ByteLiteral::cast_unchecked(b'/') } { + while end > 0 && unsafe { *str.offset(end) == ByteLiteral::cast_cchar(b'/') } { end -= 1; } if end == -1 { diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs index e0bee9995e..0330cbe500 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -554,9 +554,9 @@ pub unsafe extern "C" fn flockfile(file: *mut FILE) { #[unsafe(no_mangle)] pub unsafe extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE { let initial_mode = unsafe { *mode }; - if initial_mode != ByteLiteral::cast_unchecked(b'r') - && initial_mode != ByteLiteral::cast_unchecked(b'w') - && initial_mode != ByteLiteral::cast_unchecked(b'a') + if initial_mode != ByteLiteral::cast_cchar(b'r') + && initial_mode != ByteLiteral::cast_cchar(b'w') + && initial_mode != ByteLiteral::cast_cchar(b'a') { platform::ERRNO.set(errno::EINVAL); return ptr::null_mut(); @@ -1292,7 +1292,7 @@ pub unsafe extern "C" fn tempnam(dir: *const c_char, pfx: *const c_char) -> *mut if !out_buf.is_null() { // copy the directory name and prefix into the allocated buffer unsafe { out_buf.copy_from_nonoverlapping(dirname, dirname_len) }; - unsafe { *out_buf.add(dirname_len) = ByteLiteral::cast_unchecked(b'/') }; + unsafe { *out_buf.add(dirname_len) = ByteLiteral::cast_cchar(b'/') }; unsafe { out_buf .add(dirname_len + 1) @@ -1351,7 +1351,7 @@ pub unsafe extern "C" fn tmpnam(s: *mut c_char) -> *mut c_char { s }; - unsafe { *buf = ByteLiteral::cast_unchecked(b'/') }; + unsafe { *buf = ByteLiteral::cast_cchar(b'/') }; unsafe { #[allow(deprecated)] tmpnam_inner(buf, 1) diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 02bee148bc..d6b3a2d944 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -423,13 +423,13 @@ unsafe fn find_env(search: *const c_char) -> Option<(usize, *mut c_char)> { let mut search = search; loop { let end_of_query = - unsafe { *search } == 0 || unsafe { *search } == ByteLiteral::cast_unchecked(b'='); + unsafe { *search } == 0 || unsafe { *search } == ByteLiteral::cast_cchar(b'='); if unsafe { *item } == 0 { //TODO: environ has an item without value, is this a problem? break; } - if unsafe { *item } == ByteLiteral::cast_unchecked(b'=') || end_of_query { - if unsafe { *item } == ByteLiteral::cast_unchecked(b'=') && end_of_query { + if unsafe { *item } == ByteLiteral::cast_cchar(b'=') || end_of_query { + if unsafe { *item } == ByteLiteral::cast_cchar(b'=') && end_of_query { // Both keys env here return Some((i, unsafe { item.add(1) })); } else { @@ -477,7 +477,7 @@ pub unsafe extern "C" fn getsubopt( let mut found_comma = false; while unsafe { *cursor } != 0 { - if unsafe { *cursor } == ByteLiteral::cast_unchecked(b',') { + if unsafe { *cursor } == ByteLiteral::cast_cchar(b',') { unsafe { *cursor = 0 }; unsafe { *optionp = cursor.add(1) }; found_comma = true; @@ -498,7 +498,7 @@ pub unsafe extern "C" fn getsubopt( if unsafe { strncmp(start, token, token_len) } == 0 { let suffix_char = unsafe { *start.add(token_len) }; - if suffix_char == ByteLiteral::cast_unchecked(b'=') { + if suffix_char == ByteLiteral::cast_cchar(b'=') { unsafe { *valuep = start.add(token_len + 1) }; return i as c_int; } else if suffix_char == 0 { @@ -756,7 +756,7 @@ where } for i in (len - suffix_len - 6)..(len - suffix_len) { - if unsafe { *name.offset(i as isize) } != ByteLiteral::cast_unchecked(b'X') { + if unsafe { *name.offset(i as isize) } != ByteLiteral::cast_cchar(b'X') { platform::ERRNO.set(errno::EINVAL); return None; } @@ -1260,7 +1260,7 @@ unsafe fn copy_kv( value_len: usize, ) { unsafe { core::ptr::copy_nonoverlapping(key, existing, key_len) }; - unsafe { core::ptr::write(existing.add(key_len), ByteLiteral::cast_unchecked(b'=')) }; + unsafe { core::ptr::write(existing.add(key_len), ByteLiteral::cast_cchar(b'=')) }; unsafe { core::ptr::copy_nonoverlapping(value, existing.add(key_len + 1), value_len) }; unsafe { core::ptr::write(existing.add(key_len + 1 + value_len), 0) }; } @@ -1367,8 +1367,8 @@ pub unsafe extern "C" fn srandom(seed: c_uint) { pub fn is_positive(ch: c_char) -> Option<(bool, isize)> { match ch { 0 => None, - ch if ch == ByteLiteral::cast_unchecked(b'+') => Some((true, 1)), - ch if ch == ByteLiteral::cast_unchecked(b'-') => Some((false, 1)), + ch if ch == ByteLiteral::cast_cchar(b'+') => Some((true, 1)), + ch if ch == ByteLiteral::cast_cchar(b'-') => Some((false, 1)), _ => Some((true, 0)), } } @@ -1393,7 +1393,7 @@ pub unsafe fn detect_base(s: *const c_char) -> Option<(c_int, isize)> { } pub unsafe fn convert_octal(s: *const c_char) -> Option<(c_ulong, isize, bool)> { - if unsafe { *s } != 0 && unsafe { *s } == ByteLiteral::cast_unchecked(b'0') { + if unsafe { *s } != 0 && unsafe { *s } == ByteLiteral::cast_cchar(b'0') { if let Some((val, idx, overflow)) = unsafe { convert_integer(s.offset(1), 8) } { Some((val, idx + 1, overflow)) } else { @@ -1406,10 +1406,10 @@ pub unsafe fn convert_octal(s: *const c_char) -> Option<(c_ulong, isize, bool)> } pub unsafe fn convert_hex(s: *const c_char) -> Option<(c_ulong, isize, bool)> { - if (unsafe { *s } != 0 && unsafe { *s } == ByteLiteral::cast_unchecked(b'0')) + if (unsafe { *s } != 0 && unsafe { *s } == ByteLiteral::cast_cchar(b'0')) && (unsafe { *s.offset(1) } != 0 - && (unsafe { *s.offset(1) } == ByteLiteral::cast_unchecked(b'x') - || unsafe { *s.offset(1) } == ByteLiteral::cast_unchecked(b'X'))) + && (unsafe { *s.offset(1) } == ByteLiteral::cast_cchar(b'x') + || unsafe { *s.offset(1) } == ByteLiteral::cast_cchar(b'X'))) { unsafe { convert_integer(s.offset(2), 16) } .map(|(val, idx, overflow)| (val, idx + 2, overflow))