diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 5c297ebfadbfd..336934354e11b 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -34,7 +34,9 @@ pub(crate) fn unsized_info<'tcx>( { let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); - if data_a.principal_def_id() == data_b.principal_def_id() { + let b_principal_def_id = data_b.principal_def_id(); + if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() { + // A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables. debug_assert!( validate_trivial_unsize(fx.tcx, data_a, data_b), "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index d91c0f0790d9d..f3d9a7d37e6cc 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -147,7 +147,7 @@ pub fn validate_trivial_unsize<'tcx>( infcx.leak_check(universe, None).is_ok() }) } - (None, None) => true, + (_, None) => true, _ => false, } } @@ -175,7 +175,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( { let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); - if data_a.principal_def_id() == data_b.principal_def_id() { + let b_principal_def_id = data_b.principal_def_id(); + if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() { // Codegen takes advantage of the additional assumption, where if the // principal trait def id of what's being casted doesn't change, // then we don't need to adjust the vtable at all. This diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 99c673b021a90..a4a69ae95144e 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -499,8 +499,11 @@ impl<'a> CrateLocator<'a> { dylibs: FxIndexMap, ) -> Result, CrateError> { let mut slot = None; - // Order here matters, rmeta should come first. See comment in - // `extract_one` below. + // Order here matters, rmeta should come first. + // + // Make sure there's at most one rlib and at most one dylib. + // + // See comment in `extract_one` below. let source = CrateSource { rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?, rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?, @@ -706,54 +709,58 @@ impl<'a> CrateLocator<'a> { let mut rmetas = FxIndexMap::default(); let mut dylibs = FxIndexMap::default(); for loc in &self.exact_paths { - if !loc.canonicalized().exists() { - return Err(CrateError::ExternLocationNotExist( - self.crate_name, - loc.original().clone(), - )); + let loc_canon = loc.canonicalized(); + let loc_orig = loc.original(); + if !loc_canon.exists() { + return Err(CrateError::ExternLocationNotExist(self.crate_name, loc_orig.clone())); } - if !loc.original().is_file() { - return Err(CrateError::ExternLocationNotFile( - self.crate_name, - loc.original().clone(), - )); + if !loc_orig.is_file() { + return Err(CrateError::ExternLocationNotFile(self.crate_name, loc_orig.clone())); } - let Some(file) = loc.original().file_name().and_then(|s| s.to_str()) else { - return Err(CrateError::ExternLocationNotFile( - self.crate_name, - loc.original().clone(), - )); + // Note to take care and match against the non-canonicalized name: + // some systems save build artifacts into content-addressed stores + // that do not preserve extensions, and then link to them using + // e.g. symbolic links. If we canonicalize too early, we resolve + // the symlink, the file type is lost and we might treat rlibs and + // rmetas as dylibs. + let Some(file) = loc_orig.file_name().and_then(|s| s.to_str()) else { + return Err(CrateError::ExternLocationNotFile(self.crate_name, loc_orig.clone())); }; - - if file.starts_with("lib") && (file.ends_with(".rlib") || file.ends_with(".rmeta")) - || file.starts_with(self.target.dll_prefix.as_ref()) - && file.ends_with(self.target.dll_suffix.as_ref()) - { - // Make sure there's at most one rlib and at most one dylib. - // Note to take care and match against the non-canonicalized name: - // some systems save build artifacts into content-addressed stores - // that do not preserve extensions, and then link to them using - // e.g. symbolic links. If we canonicalize too early, we resolve - // the symlink, the file type is lost and we might treat rlibs and - // rmetas as dylibs. - let loc_canon = loc.canonicalized().clone(); - let loc = loc.original(); - if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") { - rlibs.insert(loc_canon, PathKind::ExternFlag); - } else if loc.file_name().unwrap().to_str().unwrap().ends_with(".rmeta") { - rmetas.insert(loc_canon, PathKind::ExternFlag); - } else { - dylibs.insert(loc_canon, PathKind::ExternFlag); + // FnMut cannot return reference to captured value, so references + // must be taken outside the closure. + let rlibs = &mut rlibs; + let rmetas = &mut rmetas; + let dylibs = &mut dylibs; + let type_via_filename = (|| { + if file.starts_with("lib") { + if file.ends_with(".rlib") { + return Some(rlibs); + } + if file.ends_with(".rmeta") { + return Some(rmetas); + } + } + let dll_prefix = self.target.dll_prefix.as_ref(); + let dll_suffix = self.target.dll_suffix.as_ref(); + if file.starts_with(dll_prefix) && file.ends_with(dll_suffix) { + return Some(dylibs); + } + None + })(); + match type_via_filename { + Some(type_via_filename) => { + type_via_filename.insert(loc_canon.clone(), PathKind::ExternFlag); + } + None => { + self.crate_rejections + .via_filename + .push(CrateMismatch { path: loc_orig.clone(), got: String::new() }); } - } else { - self.crate_rejections - .via_filename - .push(CrateMismatch { path: loc.original().clone(), got: String::new() }); } } // Extract the dylib/rlib/rmeta triple. - Ok(self.extract_lib(rlibs, rmetas, dylibs)?.map(|(_, lib)| lib)) + self.extract_lib(rlibs, rmetas, dylibs).map(|opt| opt.map(|(_, lib)| lib)) } pub(crate) fn into_error(self, root: Option) -> CrateError { diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 5828b2ecf34d5..2cbed0bceb2d9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -785,7 +785,8 @@ where let mut responses = vec![]; // If the principal def ids match (or are both none), then we're not doing // trait upcasting. We're just removing auto traits (or shortening the lifetime). - if a_data.principal_def_id() == b_data.principal_def_id() { + let b_principal_def_id = b_data.principal_def_id(); + if a_data.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() { responses.extend(self.consider_builtin_upcast_to_principal( goal, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 52048ca79f92f..aa313a526c1db 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -1018,7 +1018,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // #2 (region bounds). let principal_def_id_a = a_data.principal_def_id(); let principal_def_id_b = b_data.principal_def_id(); - if principal_def_id_a == principal_def_id_b { + if principal_def_id_a == principal_def_id_b || principal_def_id_b.is_none() { // We may upcast to auto traits that are either explicitly listed in // the object type's bounds, or implied by the principal trait ref's // supertraits. diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index cc5c7532b5053..0ba3b4e6e5518 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -1153,6 +1153,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. let iter = data_a .principal() + .filter(|_| { + // optionally drop the principal, if we're unsizing to no principal + data_b.principal().is_some() + }) .map(|b| b.map_bound(ty::ExistentialPredicate::Trait)) .into_iter() .chain( diff --git a/library/Cargo.lock b/library/Cargo.lock index 59b76d8d4427d..ed9e7dddf5208 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -124,9 +124,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.30.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.159" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" dependencies = [ "rustc-std-workspace-core", ] @@ -406,12 +406,12 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc55842d0db6329a669d55a623c674b02d677b16bfb2d24857d4089d41eba882" +checksum = "637d511437df708cee34bdec7ba2f1548d256b7acf3ff20e0a1c559f9bf3a987" dependencies = [ "compiler_builtins", - "gimli 0.30.0", + "gimli 0.31.1", "rustc-std-workspace-core", ] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 6a4f2af10efc6..771c2d31b60e0 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1550,7 +1550,7 @@ pub(crate) mod builtin { /// MODE is any of Forward, Reverse, ForwardFirst, ReverseFirst. /// INPUT_ACTIVITIES consists of one valid activity for each input parameter. /// OUTPUT_ACTIVITY must not be set if we implicitely return nothing (or explicitely return - /// `-> ()`. Otherwise it must be set to one of the allowed activities. + /// `-> ()`). Otherwise it must be set to one of the allowed activities. #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 358bd25ff1bc6..5f8dcde189bcf 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -39,7 +39,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false } addr2line = { version = "0.22.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] -libc = { version = "0.2.159", default-features = false, features = [ +libc = { version = "0.2.161", default-features = false, features = [ 'rustc-dep-of-std', ], public = true } diff --git a/library/std/src/os/xous/ffi.rs b/library/std/src/os/xous/ffi.rs index 1a4a940bf358a..1db314e9ddad7 100644 --- a/library/std/src/os/xous/ffi.rs +++ b/library/std/src/os/xous/ffi.rs @@ -615,7 +615,7 @@ pub(crate) fn thread_id() -> Result { /// An error is generated if the `knob` is not a valid limit, or if the call /// would not succeed. pub(crate) fn adjust_limit(knob: Limits, current: usize, new: usize) -> Result { - let mut a0 = Syscall::JoinThread as usize; + let mut a0 = Syscall::AdjustProcessLimit as usize; let mut a1 = knob as usize; let a2 = current; let a3 = new; diff --git a/library/std/src/sys/alloc/xous.rs b/library/std/src/sys/alloc/xous.rs index 9ea43445d0206..321d30e0b11b2 100644 --- a/library/std/src/sys/alloc/xous.rs +++ b/library/std/src/sys/alloc/xous.rs @@ -1,3 +1,6 @@ +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + use crate::alloc::{GlobalAlloc, Layout, System}; #[cfg(not(test))] diff --git a/library/std/src/sys/pal/xous/args.rs b/library/std/src/sys/pal/xous/args.rs new file mode 100644 index 0000000000000..00c44ca220a9e --- /dev/null +++ b/library/std/src/sys/pal/xous/args.rs @@ -0,0 +1,53 @@ +use crate::ffi::OsString; +use crate::sys::pal::xous::os::get_application_parameters; +use crate::sys::pal::xous::os::params::ArgumentList; +use crate::{fmt, vec}; + +pub struct Args { + parsed_args_list: vec::IntoIter, +} + +pub fn args() -> Args { + let Some(params) = get_application_parameters() else { + return Args { parsed_args_list: vec![].into_iter() }; + }; + + for param in params { + if let Ok(args) = ArgumentList::try_from(¶m) { + let mut parsed_args = vec![]; + for arg in args { + parsed_args.push(arg.into()); + } + return Args { parsed_args_list: parsed_args.into_iter() }; + } + } + Args { parsed_args_list: vec![].into_iter() } +} + +impl fmt::Debug for Args { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.parsed_args_list.as_slice().fmt(f) + } +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option { + self.parsed_args_list.next() + } + fn size_hint(&self) -> (usize, Option) { + self.parsed_args_list.size_hint() + } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + self.parsed_args_list.next_back() + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { + self.parsed_args_list.len() + } +} diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index b211e94db65d6..a64cd06856006 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -1,6 +1,5 @@ #![forbid(unsafe_op_in_unsafe_fn)] -#[path = "../unsupported/args.rs"] pub mod args; #[path = "../unsupported/env.rs"] pub mod env; diff --git a/library/std/src/sys/pal/xous/net/dns.rs b/library/std/src/sys/pal/xous/net/dns.rs index d0083c6183793..1a2b56b4da5d3 100644 --- a/library/std/src/sys/pal/xous/net/dns.rs +++ b/library/std/src/sys/pal/xous/net/dns.rs @@ -6,6 +6,7 @@ use crate::os::xous::ffi::lend_mut; use crate::os::xous::services::{DnsLendMut, dns_server}; pub struct DnsError { + #[allow(dead_code)] pub code: u8, } diff --git a/library/std/src/sys/pal/xous/net/mod.rs b/library/std/src/sys/pal/xous/net/mod.rs index dd8b765aa74ae..3e18ed24208d3 100644 --- a/library/std/src/sys/pal/xous/net/mod.rs +++ b/library/std/src/sys/pal/xous/net/mod.rs @@ -60,6 +60,7 @@ pub mod netc { #[derive(Copy, Clone)] pub struct sockaddr_in { + #[allow(dead_code)] pub sin_family: sa_family_t, pub sin_port: u16, pub sin_addr: in_addr, @@ -72,6 +73,7 @@ pub mod netc { #[derive(Copy, Clone)] pub struct sockaddr_in6 { + #[allow(dead_code)] pub sin6_family: sa_family_t, pub sin6_port: u16, pub sin6_addr: in6_addr, diff --git a/library/std/src/sys/pal/xous/os.rs b/library/std/src/sys/pal/xous/os.rs index 8f8f35428c487..b0ab01a6383d2 100644 --- a/library/std/src/sys/pal/xous/os.rs +++ b/library/std/src/sys/pal/xous/os.rs @@ -1,29 +1,35 @@ use super::unsupported; +use crate::collections::HashMap; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::os::xous::ffi::Error as XousError; use crate::path::{self, PathBuf}; -use crate::{fmt, io}; +use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; +use crate::sync::{Mutex, Once}; +use crate::{fmt, io, vec}; + +pub(crate) mod params; + +static PARAMS_ADDRESS: AtomicPtr = AtomicPtr::new(core::ptr::null_mut()); #[cfg(not(test))] #[cfg(feature = "panic_unwind")] mod eh_unwinding { - pub(crate) struct EhFrameFinder(usize /* eh_frame */); - pub(crate) static mut EH_FRAME_SETTINGS: EhFrameFinder = EhFrameFinder(0); - impl EhFrameFinder { - pub(crate) unsafe fn init(&mut self, eh_frame: usize) { - unsafe { - EH_FRAME_SETTINGS.0 = eh_frame; - } - } - } + pub(crate) struct EhFrameFinder; + pub(crate) static mut EH_FRAME_ADDRESS: usize = 0; + pub(crate) static EH_FRAME_SETTINGS: EhFrameFinder = EhFrameFinder; + unsafe impl unwind::EhFrameFinder for EhFrameFinder { fn find(&self, _pc: usize) -> Option { - Some(unwind::FrameInfo { - text_base: None, - kind: unwind::FrameInfoKind::EhFrame(self.0), - }) + if unsafe { EH_FRAME_ADDRESS == 0 } { + None + } else { + Some(unwind::FrameInfo { + text_base: None, + kind: unwind::FrameInfoKind::EhFrame(unsafe { EH_FRAME_ADDRESS }), + }) + } } } } @@ -41,12 +47,21 @@ mod c_compat { } #[no_mangle] - pub extern "C" fn _start(eh_frame: usize) { + pub extern "C" fn _start(eh_frame: usize, params_address: usize) { #[cfg(feature = "panic_unwind")] - unsafe { - super::eh_unwinding::EH_FRAME_SETTINGS.init(eh_frame); + { + unsafe { super::eh_unwinding::EH_FRAME_ADDRESS = eh_frame }; unwind::set_custom_eh_frame_finder(&super::eh_unwinding::EH_FRAME_SETTINGS).ok(); } + + if params_address != 0 { + let params_address = crate::ptr::with_exposed_provenance_mut::(params_address); + if unsafe { + super::params::ApplicationParameters::new_from_ptr(params_address).is_some() + } { + super::PARAMS_ADDRESS.store(params_address, core::sync::atomic::Ordering::Relaxed); + } + } exit(unsafe { main() }); } @@ -116,44 +131,103 @@ pub fn current_exe() -> io::Result { unsupported() } -pub struct Env(!); +pub(crate) fn get_application_parameters() -> Option { + let params_address = PARAMS_ADDRESS.load(Ordering::Relaxed); + unsafe { params::ApplicationParameters::new_from_ptr(params_address) } +} + +// ---------- Environment handling ---------- // +static ENV: AtomicUsize = AtomicUsize::new(0); +static ENV_INIT: Once = Once::new(); +type EnvStore = Mutex>; + +fn get_env_store() -> &'static EnvStore { + ENV_INIT.call_once(|| { + let env_store = EnvStore::default(); + if let Some(params) = get_application_parameters() { + for param in params { + if let Ok(envs) = params::EnvironmentBlock::try_from(¶m) { + let mut env_store = env_store.lock().unwrap(); + for env in envs { + env_store.insert(env.key.into(), env.value.into()); + } + break; + } + } + } + ENV.store(Box::into_raw(Box::new(env_store)) as _, Ordering::Relaxed) + }); + unsafe { &*core::ptr::with_exposed_provenance::(ENV.load(Ordering::Relaxed)) } +} + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { slice } = self; + f.debug_list() + .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} impl Env { // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self(inner) = self; - match *inner {} + let Self { iter } = self; + EnvStrDebug { slice: iter.as_slice() } } } impl fmt::Debug for Env { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self(inner) = self; - match *inner {} + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + f.debug_list().entries(iter.as_slice()).finish() } } +impl !Send for Env {} +impl !Sync for Env {} + impl Iterator for Env { type Item = (OsString, OsString); fn next(&mut self) -> Option<(OsString, OsString)> { - self.0 + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() } } pub fn env() -> Env { - panic!("not supported on this platform") + let clone_to_vec = |map: &HashMap| -> Vec<_> { + map.iter().map(|(k, v)| (k.clone(), v.clone())).collect() + }; + + let iter = clone_to_vec(&*get_env_store().lock().unwrap()).into_iter(); + Env { iter } } -pub fn getenv(_: &OsStr) -> Option { - None +pub fn getenv(k: &OsStr) -> Option { + get_env_store().lock().unwrap().get(k).cloned() } -pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let (k, v) = (k.to_owned(), v.to_owned()); + get_env_store().lock().unwrap().insert(k, v); + Ok(()) } -pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) +pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { + get_env_store().lock().unwrap().remove(k); + Ok(()) } pub fn temp_dir() -> PathBuf { diff --git a/library/std/src/sys/pal/xous/os/params.rs b/library/std/src/sys/pal/xous/os/params.rs new file mode 100644 index 0000000000000..0d02cf35477f9 --- /dev/null +++ b/library/std/src/sys/pal/xous/os/params.rs @@ -0,0 +1,271 @@ +/// Xous passes a pointer to the parameter block as the second argument. +/// This is used for passing flags such as environment variables. The +/// format of the argument block is: +/// +/// #[repr(C)] +/// struct BlockHeader { +/// /// Magic number that identifies this block. Must be printable ASCII. +/// magic: [u8; 4], +/// +/// /// The size of the data block. Does not include this header. May be 0. +/// size: u32, +/// +/// /// The contents of this block. Varies depending on the block type. +/// data: [u8; 0], +/// } +/// +/// There is a BlockHeader at the start that has magic `AppP`, and the data +/// that follows is the number of blocks present: +/// +/// #[repr(C)] +/// struct ApplicationParameters { +/// magic: b"AppP", +/// size: 4u32, +/// +/// /// The size of the entire application slice, in bytes, including all headers +/// length: u32, +/// +/// /// Number of application parameters present. Must be at least 1 (this block) +/// entries: (parameter_count as u32).to_bytes_le(), +/// } +/// +/// #[repr(C)] +/// struct EnvironmentBlock { +/// magic: b"EnvB", +/// +/// /// Total number of bytes, excluding this header +/// size: 2+data.len(), +/// +/// /// The number of environment variables +/// count: u16, +/// +/// /// Environment variable iteration +/// data: [u8; 0], +/// } +/// +/// Environment variables are present in an `EnvB` block. The `data` section is +/// a sequence of bytes of the form: +/// +/// (u16 /* key_len */; [0u8; key_len as usize] /* key */, +/// u16 /* val_len */ [0u8; val_len as usize]) +/// +/// #[repr(C)] +/// struct ArgumentList { +/// magic: b"ArgL", +/// +/// /// Total number of bytes, excluding this header +/// size: 2+data.len(), +/// +/// /// The number of arguments variables +/// count: u16, +/// +/// /// Argument variable iteration +/// data: [u8; 0], +/// } +/// +/// Args are just an array of strings that represent command line arguments. +/// They are a sequence of the form: +/// +/// (u16 /* val_len */ [0u8; val_len as usize]) +use core::slice; + +use crate::ffi::OsString; + +/// Magic number indicating we have an environment block +const ENV_MAGIC: [u8; 4] = *b"EnvB"; + +/// Command line arguments list +const ARGS_MAGIC: [u8; 4] = *b"ArgL"; + +/// Magic number indicating the loader has passed application parameters +const PARAMS_MAGIC: [u8; 4] = *b"AppP"; + +#[cfg(test)] +mod tests; + +pub(crate) struct ApplicationParameters { + data: &'static [u8], + offset: usize, + _entries: usize, +} + +impl ApplicationParameters { + pub(crate) unsafe fn new_from_ptr(data: *const u8) -> Option { + if data.is_null() { + return None; + } + + let magic = unsafe { core::slice::from_raw_parts(data, 4) }; + let block_length = unsafe { + u32::from_le_bytes(slice::from_raw_parts(data.add(4), 4).try_into().ok()?) as usize + }; + let data_length = unsafe { + u32::from_le_bytes(slice::from_raw_parts(data.add(8), 4).try_into().ok()?) as usize + }; + let entries = unsafe { + u32::from_le_bytes(slice::from_raw_parts(data.add(12), 4).try_into().ok()?) as usize + }; + + // Check for the main header + if data_length < 16 || magic != PARAMS_MAGIC || block_length != 8 { + return None; + } + + let data = unsafe { slice::from_raw_parts(data, data_length) }; + + Some(ApplicationParameters { data, offset: 0, _entries: entries }) + } +} + +impl Iterator for ApplicationParameters { + type Item = ApplicationParameter; + + fn next(&mut self) -> Option { + // Fetch magic, ensuring we don't run off the end + if self.offset + 4 > self.data.len() { + return None; + } + let magic = &self.data[self.offset..self.offset + 4]; + self.offset += 4; + + // Fetch header size + if self.offset + 4 > self.data.len() { + return None; + } + let size = u32::from_le_bytes(self.data[self.offset..self.offset + 4].try_into().unwrap()) + as usize; + self.offset += 4; + + // Fetch data contents + if self.offset + size > self.data.len() { + return None; + } + let data = &self.data[self.offset..self.offset + size]; + self.offset += size; + + Some(ApplicationParameter { data, magic: magic.try_into().unwrap() }) + } +} + +pub(crate) struct ApplicationParameter { + data: &'static [u8], + magic: [u8; 4], +} + +pub(crate) struct ApplicationParameterError; + +pub(crate) struct EnvironmentBlock { + _count: usize, + data: &'static [u8], + offset: usize, +} + +impl TryFrom<&ApplicationParameter> for EnvironmentBlock { + type Error = ApplicationParameterError; + + fn try_from(value: &ApplicationParameter) -> Result { + if value.data.len() < 2 || value.magic != ENV_MAGIC { + return Err(ApplicationParameterError); + } + + let count = u16::from_le_bytes(value.data[0..2].try_into().unwrap()) as usize; + + Ok(EnvironmentBlock { data: &value.data[2..], offset: 0, _count: count }) + } +} + +pub(crate) struct EnvironmentEntry { + pub key: &'static str, + pub value: &'static str, +} + +impl Iterator for EnvironmentBlock { + type Item = EnvironmentEntry; + + fn next(&mut self) -> Option { + if self.offset + 2 > self.data.len() { + return None; + } + let key_len = + u16::from_le_bytes(self.data[self.offset..self.offset + 2].try_into().ok()?) as usize; + self.offset += 2; + + if self.offset + key_len > self.data.len() { + return None; + } + let key = core::str::from_utf8(&self.data[self.offset..self.offset + key_len]).ok()?; + self.offset += key_len; + + if self.offset + 2 > self.data.len() { + return None; + } + let value_len = + u16::from_le_bytes(self.data[self.offset..self.offset + 2].try_into().ok()?) as usize; + self.offset += 2; + + if self.offset + value_len > self.data.len() { + return None; + } + let value = core::str::from_utf8(&self.data[self.offset..self.offset + value_len]).ok()?; + self.offset += value_len; + + Some(EnvironmentEntry { key, value }) + } +} + +pub(crate) struct ArgumentList { + data: &'static [u8], + _count: usize, + offset: usize, +} + +impl TryFrom<&ApplicationParameter> for ArgumentList { + type Error = ApplicationParameterError; + + fn try_from(value: &ApplicationParameter) -> Result { + if value.data.len() < 2 || value.magic != ARGS_MAGIC { + return Err(ApplicationParameterError); + } + let count = + u16::from_le_bytes(value.data[0..2].try_into().or(Err(ApplicationParameterError))?) + as usize; + Ok(ArgumentList { data: &value.data[2..], _count: count, offset: 0 }) + } +} + +pub(crate) struct ArgumentEntry { + value: &'static str, +} + +impl Into<&str> for ArgumentEntry { + fn into(self) -> &'static str { + self.value + } +} + +impl Into for ArgumentEntry { + fn into(self) -> OsString { + self.value.into() + } +} + +impl Iterator for ArgumentList { + type Item = ArgumentEntry; + + fn next(&mut self) -> Option { + if self.offset + 2 > self.data.len() { + return None; + } + let value_len = + u16::from_le_bytes(self.data[self.offset..self.offset + 2].try_into().ok()?) as usize; + self.offset += 2; + + if self.offset + value_len > self.data.len() { + return None; + } + let value = core::str::from_utf8(&self.data[self.offset..self.offset + value_len]).ok()?; + self.offset += value_len; + + Some(ArgumentEntry { value }) + } +} diff --git a/library/std/src/sys/pal/xous/os/params/tests.rs b/library/std/src/sys/pal/xous/os/params/tests.rs new file mode 100644 index 0000000000000..0ef04ee30919f --- /dev/null +++ b/library/std/src/sys/pal/xous/os/params/tests.rs @@ -0,0 +1,75 @@ +use super::*; +use crate::collections::HashMap; +use crate::io::Write; + +fn create_args_test() -> std::io::Result> { + let mut sample_data = vec![]; + let mut h = HashMap::new(); + + h.insert("foo", "bar"); + h.insert("baz", "qux"); + h.insert("some", "val"); + + // Magic number + sample_data.write_all(&PARAMS_MAGIC)?; + // Size of the AppP block + sample_data.write_all(&4u32.to_le_bytes())?; + // Number of blocks + sample_data.write_all(&2u32.to_le_bytes())?; + + // Magic number + sample_data.write_all(&ENV_MAGIC)?; + let mut data = vec![]; + for (key, value) in h.iter() { + data.extend_from_slice(&(key.len() as u16).to_le_bytes()); + data.extend_from_slice(key.as_bytes()); + data.extend_from_slice(&(value.len() as u16).to_le_bytes()); + data.extend_from_slice(value.as_bytes()); + } + // Size of the EnvB block + sample_data.write_all(&(data.len() as u32 + 2).to_le_bytes())?; + + // Number of environment variables + sample_data.write_all(&(h.len() as u16).to_le_bytes())?; + + // Environment variables + sample_data.write_all(&data)?; + + // Write command line arguments + let args = vec!["some", "command", "line variable", "entries"]; + sample_data.write_all(&ARGS_MAGIC)?; + let mut args_size = 0; + for entry in args.iter() { + args_size += entry.len() + 2; + } + sample_data.write_all(&(args_size as u32 + 2).to_le_bytes())?; + sample_data.write_all(&(args.len() as u16).to_le_bytes())?; + for entry in args { + sample_data.write_all(&(entry.len() as u16).to_le_bytes())?; + sample_data.write_all(entry.as_bytes())?; + } + + Ok(sample_data) +} + +#[test] +fn basic_arg_parsing() { + let arg_data = create_args_test().expect("couldn't create test data"); + for byte in &arg_data { + print!("{:02x} ", byte); + } + println!(); + + let args = ApplicationParameters::new(&arg_data).expect("Unable to parse arguments"); + for arg in args { + if let Ok(env) = EnvironmentBlock::try_from(&arg) { + for env in env { + println!("{}={}", env.key, env.value); + } + } else if let Ok(args) = ArgumentList::try_from(&arg) { + for arg in args { + println!("Arg: {}", arg.value); + } + } + } +} diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index 590de31a678ca..569a1b3299e5f 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -22,7 +22,7 @@ cfg-if = "1.0" libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false } [target.'cfg(target_os = "xous")'.dependencies] -unwinding = { version = "0.2.1", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } +unwinding = { version = "0.2.3", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } [features] diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs index ff995f38196fa..306e9ab9c6715 100644 --- a/src/tools/miri/tests/pass/dyn-upcast.rs +++ b/src/tools/miri/tests/pass/dyn-upcast.rs @@ -9,6 +9,7 @@ fn main() { struct_(); replace_vptr(); vtable_nop_cast(); + drop_principal(); } fn vtable_nop_cast() { @@ -430,3 +431,53 @@ fn replace_vptr() { let s = S(42); invoke_outer(&s); } + +fn drop_principal() { + use std::{alloc::Layout, any::Any}; + + const fn yeet_principal(x: Box) -> Box { + x + } + + trait Bar: Send + Sync {} + + impl Bar for T {} + + const fn yeet_principal_2(x: Box) -> Box { + x + } + + struct CallMe(Option); + + impl CallMe { + fn new(f: F) -> Self { + CallMe(Some(f)) + } + } + + impl Drop for CallMe { + fn drop(&mut self) { + (self.0.take().unwrap())(); + } + } + + fn goodbye() { + println!("goodbye"); + } + + let x = Box::new(CallMe::new(goodbye)) as Box; + let x_layout = Layout::for_value(&*x); + let y = yeet_principal(x); + let y_layout = Layout::for_value(&*y); + assert_eq!(x_layout, y_layout); + println!("before"); + drop(y); + + let x = Box::new(CallMe::new(goodbye)) as Box; + let x_layout = Layout::for_value(&*x); + let y = yeet_principal_2(x); + let y_layout = Layout::for_value(&*y); + assert_eq!(x_layout, y_layout); + println!("before"); + drop(y); +} diff --git a/src/tools/miri/tests/pass/dyn-upcast.stdout b/src/tools/miri/tests/pass/dyn-upcast.stdout new file mode 100644 index 0000000000000..edd99a114a112 --- /dev/null +++ b/src/tools/miri/tests/pass/dyn-upcast.stdout @@ -0,0 +1,4 @@ +before +goodbye +before +goodbye diff --git a/tests/ui/impl-trait/unsized_coercion5.next.stderr b/tests/ui/impl-trait/unsized_coercion5.next.stderr deleted file mode 100644 index 5644ac7ab04bc..0000000000000 --- a/tests/ui/impl-trait/unsized_coercion5.next.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/unsized_coercion5.rs:16:32 - | -LL | let y: Box = x as Box; - | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `Send`, found trait `Trait + Send` - | | - | expected due to this - | - = note: expected struct `Box` - found struct `Box` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/unsized_coercion5.old.stderr b/tests/ui/impl-trait/unsized_coercion5.old.stderr index 06ad54b1f1d8b..e56c026b037c6 100644 --- a/tests/ui/impl-trait/unsized_coercion5.old.stderr +++ b/tests/ui/impl-trait/unsized_coercion5.old.stderr @@ -1,16 +1,5 @@ -error[E0308]: mismatched types - --> $DIR/unsized_coercion5.rs:16:32 - | -LL | let y: Box = x as Box; - | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `Send`, found trait `Trait + Send` - | | - | expected due to this - | - = note: expected struct `Box` - found struct `Box` - error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time - --> $DIR/unsized_coercion5.rs:16:32 + --> $DIR/unsized_coercion5.rs:17:32 | LL | let y: Box = x as Box; | ^ doesn't have a size known at compile-time @@ -18,7 +7,6 @@ LL | let y: Box = x as Box; = help: the trait `Sized` is not implemented for `impl Trait + ?Sized` = note: required for the cast from `Box` to `Box` -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/unsized_coercion5.rs b/tests/ui/impl-trait/unsized_coercion5.rs index 85d313caa1355..81f8a6afe9ac1 100644 --- a/tests/ui/impl-trait/unsized_coercion5.rs +++ b/tests/ui/impl-trait/unsized_coercion5.rs @@ -3,6 +3,7 @@ //@ revisions: next old //@[next] compile-flags: -Znext-solver +//@[next] check-pass #![feature(trait_upcasting)] @@ -15,7 +16,6 @@ fn hello() -> Box { let x = hello(); let y: Box = x as Box; //[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know - //~^^ ERROR: mismatched types } Box::new(1u32) } diff --git a/tests/ui/traits/dyn-drop-principal.rs b/tests/ui/traits/dyn-drop-principal.rs new file mode 100644 index 0000000000000..c233127e43d2d --- /dev/null +++ b/tests/ui/traits/dyn-drop-principal.rs @@ -0,0 +1,68 @@ +//@ run-pass +//@ check-run-results + +use std::{alloc::Layout, any::Any}; + +const fn yeet_principal(x: Box) -> Box { + x +} + +trait Bar: Send + Sync {} + +impl Bar for T {} + +const fn yeet_principal_2(x: Box) -> Box { + x +} + +struct CallMe(Option); + +impl CallMe { + fn new(f: F) -> Self { + CallMe(Some(f)) + } +} + +impl Drop for CallMe { + fn drop(&mut self) { + (self.0.take().unwrap())(); + } +} + +fn goodbye() { + println!("goodbye"); +} + +fn main() { + let x = Box::new(CallMe::new(goodbye)) as Box; + let x_layout = Layout::for_value(&*x); + let y = yeet_principal(x); + let y_layout = Layout::for_value(&*y); + assert_eq!(x_layout, y_layout); + println!("before"); + drop(y); + + let x = Box::new(CallMe::new(goodbye)) as Box; + let x_layout = Layout::for_value(&*x); + let y = yeet_principal_2(x); + let y_layout = Layout::for_value(&*y); + assert_eq!(x_layout, y_layout); + println!("before"); + drop(y); +} + +// Test that upcast works in `const` + +const fn yeet_principal_3(x: &(dyn Any + Send + Sync)) -> &(dyn Send + Sync) { + x +} + +#[used] +pub static FOO: &(dyn Send + Sync) = yeet_principal_3(&false); + +const fn yeet_principal_4(x: &dyn Bar) -> &(dyn Send + Sync) { + x +} + +#[used] +pub static BAR: &(dyn Send + Sync) = yeet_principal_4(&false); diff --git a/tests/ui/traits/dyn-drop-principal.run.stdout b/tests/ui/traits/dyn-drop-principal.run.stdout new file mode 100644 index 0000000000000..edd99a114a112 --- /dev/null +++ b/tests/ui/traits/dyn-drop-principal.run.stdout @@ -0,0 +1,4 @@ +before +goodbye +before +goodbye diff --git a/tests/ui/traits/dyn-star-drop-principal.rs b/tests/ui/traits/dyn-star-drop-principal.rs new file mode 100644 index 0000000000000..1ad99070339ad --- /dev/null +++ b/tests/ui/traits/dyn-star-drop-principal.rs @@ -0,0 +1,12 @@ +#![feature(dyn_star)] +#![allow(incomplete_features)] + +trait Trait {} +impl Trait for usize {} + +fn main() { + // We allow &dyn Trait + Send -> &dyn Send (i.e. dropping principal), + // but we don't (currently?) allow the same for dyn* + let x: dyn* Trait + Send = 1usize; + x as dyn* Send; //~ error: `dyn* Trait + Send` needs to have the same ABI as a pointer +} diff --git a/tests/ui/traits/dyn-star-drop-principal.stderr b/tests/ui/traits/dyn-star-drop-principal.stderr new file mode 100644 index 0000000000000..721ae7e191ef0 --- /dev/null +++ b/tests/ui/traits/dyn-star-drop-principal.stderr @@ -0,0 +1,11 @@ +error[E0277]: `dyn* Trait + Send` needs to have the same ABI as a pointer + --> $DIR/dyn-star-drop-principal.rs:11:5 + | +LL | x as dyn* Send; + | ^ `dyn* Trait + Send` needs to be a pointer-like type + | + = help: the trait `PointerLike` is not implemented for `dyn* Trait + Send` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.