Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use raw-dylib in the std for non-x86 Windows #102327

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions library/std/src/sys/windows/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ 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 _;
#[cfg(target_arch = "x86")]
pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _;

// Equivalent to the `NT_SUCCESS` C preprocessor macro.
Expand Down Expand Up @@ -843,7 +844,8 @@ if #[cfg(not(target_vendor = "uwp"))] {
) -> BOOL;
}

#[link(name = "userenv")]
#[cfg_attr(not(target_arch = "x86"), link(name = "userenv", kind = "raw-dylib"))]
#[cfg_attr(target_arch = "x86", link(name = "userenv"))]
extern "system" {
// Allowed but unused by UWP
pub fn GetUserProfileDirectoryW(
Expand Down Expand Up @@ -1158,7 +1160,8 @@ extern "system" {
pub fn GetFileAttributesW(lpFileName: LPCWSTR) -> DWORD;
}

#[link(name = "ws2_32")]
#[cfg_attr(not(target_arch = "x86"), link(name = "ws2_32", kind = "raw-dylib"))]
#[cfg_attr(target_arch = "x86", link(name = "ws2_32"))]
extern "system" {
pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int;
pub fn WSACleanup() -> c_int;
Expand Down Expand Up @@ -1251,7 +1254,8 @@ extern "system" {
) -> c_int;
}

#[link(name = "bcrypt")]
#[cfg_attr(not(target_arch = "x86"), link(name = "bcrypt", kind = "raw-dylib"))]
#[cfg_attr(target_arch = "x86", link(name = "bcrypt"))]
extern "system" {
// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
Expand All @@ -1270,6 +1274,47 @@ extern "system" {
pub fn BCryptCloseAlgorithmProvider(hAlgorithm: BCRYPT_ALG_HANDLE, dwFlags: ULONG) -> NTSTATUS;
}

#[cfg(not(target_arch = "x86"))]
#[link(name = "ntdll", kind = "raw-dylib")]
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<IO_APC_ROUTINE>,
ApcContext: *mut c_void,
IoStatusBlock: &mut IO_STATUS_BLOCK,
Buffer: *mut crate::mem::MaybeUninit<u8>,
Length: ULONG,
ByteOffset: Option<&LARGE_INTEGER>,
Key: Option<&ULONG>,
) -> NTSTATUS;
pub fn NtWriteFile(
FileHandle: BorrowedHandle<'_>,
Event: HANDLE,
ApcRoutine: Option<IO_APC_ROUTINE>,
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! {
Expand Down Expand Up @@ -1310,6 +1355,7 @@ compat_fn_optional! {
compat_fn_with_fallback! {
pub static NTDLL: &CStr = ansi_str!("ntdll");

#[cfg(target_arch = "x86")]
pub fn NtCreateFile(
FileHandle: *mut HANDLE,
DesiredAccess: ACCESS_MASK,
Expand All @@ -1325,6 +1371,7 @@ compat_fn_with_fallback! {
) -> NTSTATUS {
STATUS_NOT_IMPLEMENTED
}
#[cfg(target_arch = "x86")]
pub fn NtReadFile(
FileHandle: BorrowedHandle<'_>,
Event: HANDLE,
Expand All @@ -1338,6 +1385,7 @@ compat_fn_with_fallback! {
) -> NTSTATUS {
STATUS_NOT_IMPLEMENTED
}
#[cfg(target_arch = "x86")]
pub fn NtWriteFile(
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
FileHandle: BorrowedHandle<'_>,
Event: HANDLE,
Expand All @@ -1351,6 +1399,7 @@ compat_fn_with_fallback! {
) -> NTSTATUS {
STATUS_NOT_IMPLEMENTED
}
#[cfg(target_arch = "x86")]
pub fn RtlNtStatusToDosError(
Status: NTSTATUS
) -> ULONG {
Expand Down
61 changes: 2 additions & 59 deletions src/tools/miri/src/shims/windows/dlsym.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::foreign_items::nt_write_file;
use rustc_middle::mir;
use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi;

use log::trace;
Expand Down Expand Up @@ -56,64 +56,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
);
}

let [
handle,
_event,
_apc_routine,
_apc_context,
io_status_block,
buf,
n,
byte_offset,
_key,
] = check_arg_count(args)?;
let handle = this.read_scalar(handle)?.to_machine_isize(this)?;
let buf = this.read_pointer(buf)?;
let n = this.read_scalar(n)?.to_u32()?;
let byte_offset = this.read_scalar(byte_offset)?.to_machine_usize(this)?; // 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_machine_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,
)?;
nt_write_file(this, args, dest)?;
}
Dlsym::SetThreadDescription => {
let [handle, name] = check_arg_count(args)?;
Expand Down
61 changes: 61 additions & 0 deletions src/tools/miri/src/shims/windows/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use rustc_span::Symbol;
use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi;

use crate::helpers::check_arg_count;
use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle};
Expand Down Expand Up @@ -453,10 +454,70 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// FIXME: this should return a nonzero value if this call does result in switching to another thread.
this.write_null(dest)?;
}
"NtWriteFile" if this.frame_in_std() => {
this.check_abi_and_shim_symbol_clash(
abi,
Abi::System { unwind: false },
link_name,
)?;
nt_write_file(this, args, dest)?;
}

_ => return Ok(EmulateByNameResult::NotSupported),
}

Ok(EmulateByNameResult::NeedsJumping)
}
}

// Incomplete implementation of `NtWriteFile`.
pub(super) fn nt_write_file<'a, 'mir, 'tcx>(
this: &'a mut MiriInterpCx<'mir, 'tcx>,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ()> {
let [handle, _event, _apc_routine, _apc_context, io_status_block, buf, n, byte_offset, _key] =
check_arg_count(args)?;

let handle = this.read_scalar(handle)?.to_machine_isize(this)?;
let buf = this.read_pointer(buf)?;
let n = this.read_scalar(n)?.to_u32()?;
let byte_offset = this.read_scalar(byte_offset)?.to_machine_usize(this)?; // 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_machine_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)?;
Ok(())
}