Skip to content
Merged
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
18 changes: 8 additions & 10 deletions crates/host_env/src/fileutils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Python/fileutils.c in CPython
#![allow(non_snake_case)]

use alloc::ffi::CString;

#[cfg(not(windows))]
pub use rustix::fs::Stat as StatStruct;

Expand All @@ -16,9 +18,8 @@ pub fn fstat(fd: crate::crt_fd::Borrowed<'_>) -> std::io::Result<StatStruct> {
pub mod windows {
use crate::crt_fd;
use crate::windows::ToWideString;
use alloc::ffi::CString;
use libc::{S_IFCHR, S_IFDIR, S_IFMT};
use std::ffi::{OsStr, OsString};
use std::ffi::OsStr;
use std::os::windows::io::AsRawHandle;
use std::sync::OnceLock;
use windows_sys::Win32::Foundation::{
Expand All @@ -33,6 +34,7 @@ pub mod windows {
use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryW};
use windows_sys::Win32::System::SystemServices::IO_REPARSE_TAG_SYMLINK;
use windows_sys::core::PCWSTR;
use windows_sys::w;

pub const S_IFIFO: libc::c_int = 0o010000;
pub const S_IFLNK: libc::c_int = 0o120000;
Expand Down Expand Up @@ -302,16 +304,13 @@ pub mod windows {

let GetFileInformationByName = GET_FILE_INFORMATION_BY_NAME
.get_or_init(|| {
let library_name =
OsString::from("api-ms-win-core-file-l2-1-4.dll").to_wide_with_nul();
let module = unsafe { LoadLibraryW(library_name.as_ptr()) };
let library_name = w!("api-ms-win-core-file-l2-1-4.dll");
let module = unsafe { LoadLibraryW(library_name) };
if module.is_null() {
return None;
}
let name = CString::new("GetFileInformationByName").unwrap();
if let Some(proc) =
unsafe { GetProcAddress(module, name.as_bytes_with_nul().as_ptr()) }
{
let name = c"GetFileInformationByName";
if let Some(proc) = unsafe { GetProcAddress(module, name.as_ptr().cast()) } {
Some(unsafe {
core::mem::transmute::<
unsafe extern "system" fn() -> isize,
Expand Down Expand Up @@ -458,7 +457,6 @@ pub unsafe fn fclose(fp: *mut CFile) -> core::ffi::c_int {
reason = "false positive: core::io::ErrorKind is unstable (core_io)"
)]
pub fn fopen(path: &std::path::Path, mode: &str) -> std::io::Result<*mut CFile> {
use alloc::ffi::CString;
use std::fs::File;

// Currently only supports read mode
Expand Down
37 changes: 19 additions & 18 deletions crates/host_env/src/nt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,22 @@ use crate::{
windows::{CheckWin32Bool, CheckWin32Handle, CheckWin32Sentinel, HandleToOwned, ToWideString},
};
use libc::intptr_t;
use windows_sys::Win32::{
Foundation::{
CloseHandle, ERROR_INVALID_HANDLE, GetLastError, HANDLE, INVALID_HANDLE_VALUE, MAX_PATH,
},
Globalization::{CP_UTF8, MultiByteToWideChar, WideCharToMultiByte},
Storage::FileSystem::{
CreateFileW, FILE_BASIC_INFO, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT,
FILE_READ_ATTRIBUTES, FILE_TYPE_UNKNOWN, FileBasicInfo, FindClose, FindFirstFileW,
GetFileAttributesW, GetFileInformationByHandleEx, GetFileType, GetFullPathNameW,
INVALID_FILE_ATTRIBUTES, OPEN_EXISTING, SetFileAttributesW, SetFileInformationByHandle,
WIN32_FIND_DATAW,
use windows_sys::{
Win32::{
Foundation::{
CloseHandle, ERROR_INVALID_HANDLE, GetLastError, HANDLE, INVALID_HANDLE_VALUE, MAX_PATH,
},
Globalization::{CP_UTF8, MultiByteToWideChar, WideCharToMultiByte},
Storage::FileSystem::{
CreateFileW, FILE_BASIC_INFO, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT,
FILE_READ_ATTRIBUTES, FILE_TYPE_UNKNOWN, FileBasicInfo, FindClose, FindFirstFileW,
GetFileAttributesW, GetFileInformationByHandleEx, GetFileType, GetFullPathNameW,
INVALID_FILE_ATTRIBUTES, OPEN_EXISTING, SetFileAttributesW, SetFileInformationByHandle,
WIN32_FIND_DATAW,
},
System::{Console, Threading},
},
System::{Console, Threading},
w,
};

pub type Handle = HANDLE;
Expand Down Expand Up @@ -1172,12 +1175,10 @@ pub fn mkdir(path: &widestring::WideCStr, mode: i32) -> io::Result<()> {
lpSecurityDescriptor: core::ptr::null_mut(),
bInheritHandle: 0,
};
let sddl: Vec<u16> = "D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)\0"
.encode_utf16()
.collect();
let sddl = w!("D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)");
unsafe {
ConvertStringSecurityDescriptorToSecurityDescriptorW(
sddl.as_ptr(),
sddl,
SDDL_REVISION_1,
&mut sec_attr.lpSecurityDescriptor,
core::ptr::null_mut(),
Expand Down Expand Up @@ -1699,10 +1700,10 @@ pub fn get_terminal_size_handle(h: HANDLE) -> io::Result<(usize, usize)> {
if err != windows_sys::Win32::Foundation::ERROR_ACCESS_DENIED {
return Err(io::Error::last_os_error());
}
let conout: Vec<u16> = "CONOUT$\0".encode_utf16().collect();
let conout = w!("CONOUT$");
let console_handle = unsafe {
CreateFileW(
conout.as_ptr(),
conout,
windows_sys::Win32::Foundation::GENERIC_READ
| windows_sys::Win32::Foundation::GENERIC_WRITE,
windows_sys::Win32::Storage::FileSystem::FILE_SHARE_READ
Expand Down
5 changes: 3 additions & 2 deletions crates/host_env/src/winapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ pub use windows_sys::Win32::{
},
UI::WindowsAndMessaging::SW_HIDE,
};
use windows_sys::w;

pub type Handle = HANDLE;
pub type StdHandle = windows_sys::Win32::System::Console::STD_HANDLE;
Expand Down Expand Up @@ -1093,14 +1094,14 @@ where
return Err(MimeRegistryReadError::Os(err));
}

let content_type_key: Vec<u16> = "Content Type\0".encode_utf16().collect();
let content_type_key = w!("Content Type");
let mut type_buf = [0u16; 256];
let mut cb_type = (type_buf.len() * 2) as u32;
let mut reg_type = 0;
let err = unsafe {
RegQueryValueExW(
subkey,
content_type_key.as_ptr(),
content_type_key,
core::ptr::null_mut(),
&mut reg_type,
type_buf.as_mut_ptr().cast(),
Expand Down
43 changes: 23 additions & 20 deletions crates/host_env/src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,27 @@ use std::{
io,
os::windows::ffi::{OsStrExt, OsStringExt},
};
use windows_sys::Win32::{
Foundation::{
E_POINTER, ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_FLAGS, ERROR_NO_UNICODE_TRANSLATION,
MAX_PATH, S_OK,
},
Networking::WinSock::WSAStartup,
Storage::FileSystem::{
GetFileVersionInfoSizeW, GetFileVersionInfoW, VS_FIXEDFILEINFO, VerQueryValueW,
},
System::{
Diagnostics::Debug::{
FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM,
FORMAT_MESSAGE_IGNORE_INSERTS, FormatMessageW,
use windows_sys::{
Win32::{
Foundation::{
E_POINTER, ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_FLAGS,
ERROR_NO_UNICODE_TRANSLATION, MAX_PATH, S_OK,
},
Networking::WinSock::WSAStartup,
Storage::FileSystem::{
GetFileVersionInfoSizeW, GetFileVersionInfoW, VS_FIXEDFILEINFO, VerQueryValueW,
},
System::{
Diagnostics::Debug::{
FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM,
FORMAT_MESSAGE_IGNORE_INSERTS, FormatMessageW,
},
LibraryLoader::{GetModuleFileNameW, GetModuleHandleW},
SystemInformation::{GetVersionExW, OSVERSIONINFOEXW, OSVERSIONINFOW},
Threading::{GetCurrentThreadStackLimits, SetThreadStackGuarantee},
},
LibraryLoader::{GetModuleFileNameW, GetModuleHandleW},
SystemInformation::{GetVersionExW, OSVERSIONINFOEXW, OSVERSIONINFOW},
Threading::{GetCurrentThreadStackLimits, SetThreadStackGuarantee},
},
w,
};

/// _MAX_ENV from Windows CRT stdlib.h - maximum environment variable size
Expand Down Expand Up @@ -154,8 +157,8 @@ pub struct WindowsVersionInfo {

fn get_kernel32_version() -> io::Result<(u32, u32, u32)> {
unsafe {
let module_name: Vec<u16> = OsStr::new("kernel32.dll").to_wide_with_nul();
let h_kernel32 = GetModuleHandleW(module_name.as_ptr()).check_nonnull()?;
let module_name = w!("kernel32.dll");
let h_kernel32 = GetModuleHandleW(module_name).check_nonnull()?;

let mut kernel32_path = [0u16; MAX_PATH as usize];
let len = GetModuleFileNameW(
Expand All @@ -181,13 +184,13 @@ fn get_kernel32_version() -> io::Result<(u32, u32, u32)> {
)
.check_win32_bool()?;

let sub_block: Vec<u16> = OsStr::new("").to_wide_with_nul();
let sub_block = w!("");

let mut ffi_ptr: *mut VS_FIXEDFILEINFO = core::ptr::null_mut();
let mut ffi_len: u32 = 0;
VerQueryValueW(
ver_block.as_ptr() as *const _,
sub_block.as_ptr(),
sub_block,
&mut ffi_ptr as *mut *mut VS_FIXEDFILEINFO as *mut *mut _,
&mut ffi_len as *mut u32,
)
Expand Down
24 changes: 12 additions & 12 deletions crates/host_env/src/wmi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@

use core::ffi::c_void;
use core::ptr::{NonNull, null, null_mut};
use widestring::WideCString;
use windows_sys::Win32::Foundation::{
CloseHandle, ERROR_BROKEN_PIPE, ERROR_MORE_DATA, ERROR_NOT_ENOUGH_MEMORY, GetLastError, HANDLE,
WAIT_OBJECT_0, WAIT_TIMEOUT,
CloseHandle, ERROR_BROKEN_PIPE, ERROR_INVALID_NAME, ERROR_MORE_DATA, ERROR_NOT_ENOUGH_MEMORY,
GetLastError, HANDLE, WAIT_OBJECT_0, WAIT_TIMEOUT,
};
use windows_sys::Win32::Storage::FileSystem::{ReadFile, WriteFile};
use windows_sys::Win32::System::Pipes::CreatePipe;
use windows_sys::Win32::System::Threading::{
CreateEventW, CreateThread, GetExitCodeThread, SetEvent, WaitForSingleObject,
};
use windows_sys::w;

use crate::ctypes::wcslen;

Expand Down Expand Up @@ -256,10 +258,6 @@ const fn failed(hr: HRESULT) -> bool {
hr < 0
}

fn wide_str(s: &str) -> Vec<u16> {
s.encode_utf16().chain(core::iter::once(0)).collect()
}

unsafe fn wait_event(event: HANDLE, timeout: u32) -> u32 {
match unsafe { WaitForSingleObject(event, timeout) } {
WAIT_OBJECT_0 => 0,
Expand Down Expand Up @@ -346,8 +344,8 @@ unsafe fn query_thread_impl(param: *mut c_void) -> u32 {
}

if succeeded(hr) {
let root_cimv2 = wide_str("ROOT\\CIMV2");
let bstr_root = unsafe { SysAllocString(root_cimv2.as_ptr()) };
let root_cimv2 = w!("ROOT\\CIMV2");
let bstr_root = unsafe { SysAllocString(root_cimv2) };
hr = unsafe {
locator_connect_server(
locator,
Expand Down Expand Up @@ -384,8 +382,8 @@ unsafe fn query_thread_impl(param: *mut c_void) -> u32 {
};
}
if succeeded(hr) {
let wql = wide_str("WQL");
let bstr_wql = unsafe { SysAllocString(wql.as_ptr()) };
let wql = w!("WQL");
let bstr_wql = unsafe { SysAllocString(wql) };
hr = unsafe {
services_exec_query(
services,
Expand Down Expand Up @@ -557,7 +555,9 @@ unsafe fn query_thread_impl(param: *mut c_void) -> u32 {
}

pub fn exec_query(query_str: &str) -> Result<String, ExecQueryError> {
let query_wide = wide_str(query_str);
let query = WideCString::from_str(query_str)
.map_err(|_| ExecQueryError::Code(ERROR_INVALID_NAME))?
.into();
Comment on lines +558 to +560

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

cargo tree -i widestring --edges normal
rg -n 'WideCString::from_str|into_vec(_with_nul)?|SysAllocString|struct QueryThreadData' \
  crates/host_env/src/wmi.rs Cargo.toml Cargo.lock

Repository: RustPython/RustPython

Length of output: 1110


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

sed -n '240,310p' crates/host_env/src/wmi.rs
printf '\n--- 540-590 ---\n'
sed -n '540,590p' crates/host_env/src/wmi.rs

printf '\n--- Widestring references in Cargo.lock ---\n'
rg -n 'name = "widestring"|version = "1\.' Cargo.lock || true

printf '\n--- Source docs from local wide string crate if present ---\n'
fd -a 'ucstring.rs|widestring' Cargo.lock .cargo registry 2>/dev/null | head -20

Repository: RustPython/RustPython

Length of output: 6019


🌐 Web query:

widestring 1.2.1 U16CString into_vec into_vec_with_nul documentation

💡 Result:

In the widestring crate, U16CString is an owned, mutable, nul-terminated 16-bit wide string designed for FFI [1][2][3]. The methods into_vec and into_vec_with_nul are used to consume the U16CString and convert it into a standard Rust Vec [1][4]. into_vec Converts the U16CString into a Vec without a nul terminator [1][4]. The resulting vector will contain no nul values [1]. into_vec_with_nul Converts the U16CString into a Vec including the terminating nul character [1][4]. The resulting vector will contain a nul-terminator at the end and no interior nul values [1][4]. Example usage: use widestring::U16CString; let wcstr = U16CString::from_str("example").unwrap; // Convert to Vec without nul terminator let v = wcstr.into_vec; assert_eq!(v, vec!); // Convert to Vec with nul terminator let wcvec = wcstr.into_vec_with_nul; assert_eq!(wcvec[wcvec.len-1], 0);

Citations:


Retain the WMI query NUL terminator before calling SysAllocString.

QueryThreadData.query: Vec<u16> is passed to SysAllocString(data.query.as_ptr()), so query_vec must include the terminating u16. WideCString::into() drops it via U16CString::<u16>::into_vec(); use into_vec_with_nul() when converting the WQL query string.

Also applies to the WQL Bstr construction at line 386.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/host_env/src/wmi.rs` around lines 558 - 560, Update the WQL query
conversions in the affected query path and the WQL BSTR construction to call
WideCString::into_vec_with_nul() rather than into_vec(), preserving the
terminating u16 required by SysAllocString through QueryThreadData.query.


let mut h_thread: HANDLE = null_mut();
let mut err: u32 = 0;
Expand All @@ -579,7 +579,7 @@ pub fn exec_query(query_str: &str) -> Result<String, ExecQueryError> {
err = GetLastError();
} else {
let thread_data = Box::new(QueryThreadData {
query: query_wide,
query,
write_pipe,
init_event,
connect_event,
Expand Down
Loading