diff --git a/src/byte_literal.rs b/src/byte_literal.rs new file mode 100644 index 0000000000..10f8976bd4 --- /dev/null +++ b/src/byte_literal.rs @@ -0,0 +1,36 @@ +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 { + /// 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() + } + } + _ => panic!("Not a printable ascii character!"), + } + } +} diff --git a/src/header/fmtmsg/mod.rs b/src/header/fmtmsg/mod.rs index 235ea40068..dd64dde670 100644 --- a/src/header/fmtmsg/mod.rs +++ b/src/header/fmtmsg/mod.rs @@ -6,6 +6,7 @@ //! See use crate::{ + byte_literal::ByteLiteral, header::{ fcntl::{O_WRONLY, open}, pthread::{PTHREAD_CANCEL_DISABLE, pthread_setcancelstate}, @@ -77,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 != b':' as c_char) { + 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 1cc310a677..ecc8074b65 100644 --- a/src/header/getopt/mod.rs +++ b/src/header/getopt/mod.rs @@ -3,6 +3,7 @@ //! Non-POSIX, see . use crate::{ + byte_literal::ByteLiteral, header::{ stdio, string, unistd::{optarg, opterr, optind, optopt}, @@ -61,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 != b'-' as c_char + || *current_arg != ByteLiteral::cast_cchar(b'-') || *current_arg.offset(1) == 0 } { -1 @@ -74,7 +75,7 @@ pub unsafe extern "C" fn getopt_long( // remove the '-' let current_arg = unsafe { current_arg.offset(1) }; - if unsafe { *current_arg == b'-' as c_char } && !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.. { @@ -86,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 != b'=' as c_char + c != 0 && c != ByteLiteral::cast_cchar(b'=') } { end += 1; } @@ -101,18 +102,18 @@ pub unsafe extern "C" fn getopt_long( if opt.has_arg == optional_argument { unsafe { - if *current_arg.offset(end) == b'=' as c_char { + 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) == b'=' as c_char { + 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 == b':' as c_char { + } else if *optstring == ByteLiteral::cast_cchar(b':') { return c_int::from(b':'); } else { stdio::fputs((*argv).cast_const(), &raw mut *stdio::stderr); @@ -183,7 +184,7 @@ unsafe fn parse_arg( CURRENT_OPT = ptr::null_mut(); optopt = c_int::from(*current_arg); - let errch = if *optstring == b':' as c_char { + let errch = if *optstring == ByteLiteral::cast_cchar(b':') { b':' } else { if opterr != 0 { @@ -231,7 +232,7 @@ unsafe fn find_option(ch: c_char, optstring: *const c_char) -> Option. -use crate::platform::types::c_char; - -use crate::header::string::strlen; +use crate::{byte_literal::ByteLiteral, header::string::strlen, platform::types::c_char}; /// See . #[unsafe(no_mangle)] @@ -13,14 +11,14 @@ pub unsafe extern "C" fn basename(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) == b'/' as c_char } { + 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) != b'/' as c_char } { + while begin >= 0 && unsafe { *str.offset(begin) != ByteLiteral::cast_cchar(b'/') } { begin -= 1; } unsafe { @@ -36,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) == b'/' as c_char } { + while end > 0 && unsafe { *str.offset(end) == ByteLiteral::cast_cchar(b'/') } { end -= 1; } - while end >= 0 && unsafe { *str.offset(end) != b'/' as c_char } { + while end >= 0 && unsafe { *str.offset(end) != ByteLiteral::cast_cchar(b'/') } { end -= 1; } - while end > 0 && unsafe { *str.offset(end) == b'/' as c_char } { + 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 0a3442a929..cdac484372 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -17,6 +17,7 @@ use core::{ }; use crate::{ + byte_literal::ByteLiteral, c_str::{CStr, Thin}, c_vec::CVec, error::{ResultExt, ResultExtPtrMut}, @@ -551,9 +552,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 != b'r' as c_char - && initial_mode != b'w' as c_char - && initial_mode != b'a' as c_char + 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(); @@ -1289,7 +1290,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) = b'/' as _ }; + unsafe { *out_buf.add(dirname_len) = ByteLiteral::cast_cchar(b'/') }; unsafe { out_buf .add(dirname_len + 1) @@ -1348,7 +1349,7 @@ pub unsafe extern "C" fn tmpnam(s: *mut c_char) -> *mut c_char { s }; - unsafe { *buf = b'/' as _ }; + 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 5477101ea1..d6b3a2d944 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -11,6 +11,7 @@ use rand_jitter::JitterRng; use rand_xorshift::XorShiftRng; use crate::{ + byte_literal::ByteLiteral, c_str::CStr, error::{Errno, ResultExt}, fs::File, @@ -421,13 +422,14 @@ unsafe fn find_env(search: *const c_char) -> Option<(usize, *mut c_char)> { for (i, mut item) in platform::environ_iter().enumerate() { let mut search = search; loop { - let end_of_query = unsafe { *search } == 0 || unsafe { *search } == b'=' as c_char; + let end_of_query = + 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 } == b'=' as c_char || end_of_query { - if unsafe { *item } == b'=' as c_char && 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 { @@ -475,7 +477,7 @@ pub unsafe extern "C" fn getsubopt( let mut found_comma = false; while unsafe { *cursor } != 0 { - if unsafe { *cursor } == b',' as c_char { + if unsafe { *cursor } == ByteLiteral::cast_cchar(b',') { unsafe { *cursor = 0 }; unsafe { *optionp = cursor.add(1) }; found_comma = true; @@ -496,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 == b'=' as c_char { + if suffix_char == ByteLiteral::cast_cchar(b'=') { unsafe { *valuep = start.add(token_len + 1) }; return i as c_int; } else if suffix_char == 0 { @@ -754,7 +756,7 @@ where } for i in (len - suffix_len - 6)..(len - suffix_len) { - if unsafe { *name.offset(i as isize) } != b'X' as c_char { + if unsafe { *name.offset(i as isize) } != ByteLiteral::cast_cchar(b'X') { platform::ERRNO.set(errno::EINVAL); return None; } @@ -1258,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), b'=' as c_char) }; + 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) }; } @@ -1365,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 == b'+' as c_char => Some((true, 1)), - ch if ch == b'-' as c_char => 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)), } } @@ -1391,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 } == b'0' as c_char { + 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 { @@ -1404,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 } == b'0' as c_char) + if (unsafe { *s } != 0 && unsafe { *s } == ByteLiteral::cast_cchar(b'0')) && (unsafe { *s.offset(1) } != 0 - && (unsafe { *s.offset(1) } == b'x' as c_char - || unsafe { *s.offset(1) } == b'X' as c_char)) + && (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)) diff --git a/src/lib.rs b/src/lib.rs index 7b971e5362..d9fcffe841 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,6 +36,7 @@ extern crate syscall; #[macro_use] mod macros; +pub mod byte_literal; pub mod c_str; pub mod c_vec; pub mod cxa;