diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 5d150eca00ed8..1f4092ad73847 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -296,7 +296,6 @@ pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _; pub const STATUS_PENDING: NTSTATUS = 0x103 as _; pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _; -pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _; // Equivalent to the `NT_SUCCESS` C preprocessor macro. // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values @@ -1282,6 +1281,46 @@ extern "system" { ) -> NTSTATUS; } +#[link(name = "ntdll")] +extern "system" { + pub fn NtCreateFile( + FileHandle: *mut HANDLE, + DesiredAccess: ACCESS_MASK, + ObjectAttributes: *const OBJECT_ATTRIBUTES, + IoStatusBlock: *mut IO_STATUS_BLOCK, + AllocationSize: *mut i64, + FileAttributes: ULONG, + ShareAccess: ULONG, + CreateDisposition: ULONG, + CreateOptions: ULONG, + EaBuffer: *mut c_void, + EaLength: ULONG, + ) -> NTSTATUS; + pub fn NtReadFile( + FileHandle: BorrowedHandle<'_>, + Event: HANDLE, + ApcRoutine: Option, + ApcContext: *mut c_void, + IoStatusBlock: &mut IO_STATUS_BLOCK, + Buffer: *mut crate::mem::MaybeUninit, + Length: ULONG, + ByteOffset: Option<&LARGE_INTEGER>, + Key: Option<&ULONG>, + ) -> NTSTATUS; + pub fn NtWriteFile( + FileHandle: BorrowedHandle<'_>, + Event: HANDLE, + ApcRoutine: Option, + ApcContext: *mut c_void, + IoStatusBlock: &mut IO_STATUS_BLOCK, + Buffer: *const u8, + Length: ULONG, + ByteOffset: Option<&LARGE_INTEGER>, + Key: Option<&ULONG>, + ) -> NTSTATUS; + pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> ULONG; +} + // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn_with_fallback! { @@ -1322,52 +1361,6 @@ compat_fn_optional! { compat_fn_with_fallback! { pub static NTDLL: &CStr = ansi_str!("ntdll"); - pub fn NtCreateFile( - FileHandle: *mut HANDLE, - DesiredAccess: ACCESS_MASK, - ObjectAttributes: *const OBJECT_ATTRIBUTES, - IoStatusBlock: *mut IO_STATUS_BLOCK, - AllocationSize: *mut i64, - FileAttributes: ULONG, - ShareAccess: ULONG, - CreateDisposition: ULONG, - CreateOptions: ULONG, - EaBuffer: *mut c_void, - EaLength: ULONG - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - pub fn NtReadFile( - FileHandle: BorrowedHandle<'_>, - Event: HANDLE, - ApcRoutine: Option, - ApcContext: *mut c_void, - IoStatusBlock: &mut IO_STATUS_BLOCK, - Buffer: *mut crate::mem::MaybeUninit, - Length: ULONG, - ByteOffset: Option<&LARGE_INTEGER>, - Key: Option<&ULONG> - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - pub fn NtWriteFile( - FileHandle: BorrowedHandle<'_>, - Event: HANDLE, - ApcRoutine: Option, - ApcContext: *mut c_void, - IoStatusBlock: &mut IO_STATUS_BLOCK, - Buffer: *const u8, - Length: ULONG, - ByteOffset: Option<&LARGE_INTEGER>, - Key: Option<&ULONG> - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - pub fn RtlNtStatusToDosError( - Status: NTSTATUS - ) -> ULONG { - Status as ULONG - } pub fn NtCreateKeyedEvent( KeyedEventHandle: LPHANDLE, DesiredAccess: ACCESS_MASK, diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index a3d9cb3e10c21..dceb4bd1b893c 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -210,6 +210,8 @@ fn make_win_dist( rustc_dlls.push("libgcc_s_seh-1.dll"); } + // Libraries necessary to link the windows-gnu toolchains. + // System libraries will be preferred if they are available (see #67429). let target_libs = [ //MinGW libs "libgcc.a", @@ -223,6 +225,7 @@ fn make_win_dist( "libmoldname.a", "libpthread.a", //Windows import libs + //This should contain only the set of libraries necessary to link the standard library. "libadvapi32.a", "libbcrypt.a", "libcomctl32.a", @@ -236,6 +239,7 @@ fn make_win_dist( "libkernel32.a", "libmsimg32.a", "libmsvcrt.a", + "libntdll.a", "libodbc32.a", "libole32.a", "liboleaut32.a", diff --git a/src/tools/miri/src/shims/windows/dlsym.rs b/src/tools/miri/src/shims/windows/dlsym.rs index 60dd299c43813..7e2051fc98a0e 100644 --- a/src/tools/miri/src/shims/windows/dlsym.rs +++ b/src/tools/miri/src/shims/windows/dlsym.rs @@ -1,5 +1,4 @@ use rustc_middle::mir; -use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use log::trace; @@ -11,7 +10,6 @@ use crate::*; #[derive(Debug, Copy, Clone)] pub enum Dlsym { - NtWriteFile, SetThreadDescription, WaitOnAddress, WakeByAddressSingle, @@ -23,7 +21,6 @@ impl Dlsym { pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { "GetSystemTimePreciseAsFileTime" => None, - "NtWriteFile" => Some(Dlsym::NtWriteFile), "SetThreadDescription" => Some(Dlsym::SetThreadDescription), "WaitOnAddress" => Some(Dlsym::WaitOnAddress), "WakeByAddressSingle" => Some(Dlsym::WakeByAddressSingle), @@ -49,72 +46,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.check_abi(abi, Abi::System { unwind: false })?; match dlsym { - Dlsym::NtWriteFile => { - if !this.frame_in_std() { - throw_unsup_format!( - "`NtWriteFile` support is crude and just enough for stdout to work" - ); - } - - let [ - handle, - _event, - _apc_routine, - _apc_context, - io_status_block, - buf, - n, - byte_offset, - _key, - ] = check_arg_count(args)?; - let handle = this.read_target_isize(handle)?; - let buf = this.read_pointer(buf)?; - let n = this.read_scalar(n)?.to_u32()?; - let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer - let io_status_block = this.deref_operand(io_status_block)?; - - if byte_offset != 0 { - throw_unsup_format!( - "`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported" - ); - } - - let written = if handle == -11 || handle == -12 { - // stdout/stderr - use std::io::{self, Write}; - - let buf_cont = - this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?; - let res = if this.machine.mute_stdout_stderr { - Ok(buf_cont.len()) - } else if handle == -11 { - io::stdout().write(buf_cont) - } else { - io::stderr().write(buf_cont) - }; - // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that. - res.ok().map(|n| u32::try_from(n).unwrap()) - } else { - throw_unsup_format!( - "on Windows, writing to anything except stdout/stderr is not supported" - ) - }; - // We have to put the result into io_status_block. - if let Some(n) = written { - let io_status_information = - this.mplace_field_named(&io_status_block, "Information")?; - this.write_scalar( - Scalar::from_target_usize(n.into(), this), - &io_status_information.into(), - )?; - } - // Return whether this was a success. >= 0 is success. - // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. - this.write_scalar( - Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }), - dest, - )?; - } Dlsym::SetThreadDescription => { let [handle, name] = check_arg_count(args)?; diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index a3d7176a97686..665c7ed438f3d 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -69,6 +69,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(result, dest)?; } + // File related shims + "NtWriteFile" => { + if !this.frame_in_std() { + throw_unsup_format!( + "`NtWriteFile` support is crude and just enough for stdout to work" + ); + } + + let [ + handle, + _event, + _apc_routine, + _apc_context, + io_status_block, + buf, + n, + byte_offset, + _key, + ] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let handle = this.read_target_isize(handle)?; + let buf = this.read_pointer(buf)?; + let n = this.read_scalar(n)?.to_u32()?; + let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer + let io_status_block = this.deref_operand(io_status_block)?; + + if byte_offset != 0 { + throw_unsup_format!( + "`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported" + ); + } + + let written = if handle == -11 || handle == -12 { + // stdout/stderr + use std::io::{self, Write}; + + let buf_cont = + this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?; + let res = if this.machine.mute_stdout_stderr { + Ok(buf_cont.len()) + } else if handle == -11 { + io::stdout().write(buf_cont) + } else { + io::stderr().write(buf_cont) + }; + // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that. + res.ok().map(|n| u32::try_from(n).unwrap()) + } else { + throw_unsup_format!( + "on Windows, writing to anything except stdout/stderr is not supported" + ) + }; + // We have to put the result into io_status_block. + if let Some(n) = written { + let io_status_information = + this.mplace_field_named(&io_status_block, "Information")?; + this.write_scalar( + Scalar::from_target_usize(n.into(), this), + &io_status_information.into(), + )?; + } + // Return whether this was a success. >= 0 is success. + // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. + this.write_scalar( + Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }), + dest, + )?; + } + // Allocation "HeapAlloc" => { let [handle, flags, size] = diff --git a/tests/run-make-fulldeps/tools.mk b/tests/run-make-fulldeps/tools.mk index 0f5425daa1684..ea06b620c4cff 100644 --- a/tests/run-make-fulldeps/tools.mk +++ b/tests/run-make-fulldeps/tools.mk @@ -112,9 +112,9 @@ endif # Extra flags needed to compile a working executable with the standard library ifdef IS_WINDOWS ifdef IS_MSVC - EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib + EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib else - EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt + EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll EXTRACXXFLAGS := -lstdc++ # So this is a bit hacky: we can't use the DLL version of libstdc++ because # it pulls in the DLL version of libgcc, which means that we end up with 2