Files
uv/crates/uv-trampoline/src/diagnostics.rs
T
samypr100 eee90a340c feat: re-enable std in uv-trampoline (#4722)
## Summary

Partially closes #1917

This PR picks up on some of the great work from #1864 and opted to keep
`panic_immediate_abort` (for size reasons). I split the PR in different
isolated commits in case we want to separate/cherry-pick them out.

1. The first commit ports mostly all std changes from that PR into this
PR. Binary sizes stayed the same ~16kb.
2. The second commit migrates our existing usage of windows-sys to
windows for a safer ffi calls with Results!. It also changes all large
unsafe blocks to be isolated to the actual unsafe calls, and switches
some areas to use std such as getenv port ( which seemed buggy! ) from
launcher.c. In addition, this also adds more error checking in order to
match some missing assertions from distlib's launcher.c. Note, due to
the additional .text data, the binary sizes increased to ~20.5kb, but we
can cut back on some of the added error msgs as needed.
3. The third commit switches to using xwin for building on all 3
supported trampoline targets for sanity, and adds a CI bloat check for
core::fmt and panic as a precaution. Sadly, this will invalidate the
xwin cache on the first run.

## Test Plan

Most changes were tested on a couple of local GUI apps and console apps,
also tested some of the error states manually by using SetLastError at
different points in the code and/or passing in invalid handles.

I'm not sure how far we can get with migrating some of the other calls
without increasing binary size substantially. An initial attempt at
using std::path didn't seem so bad size wise when I tried it (~1k). On
other cases, such as std::process::exit added ~10k to the total binary
size.

---------

Co-authored-by: konstin <konstin@mailbox.org>
2024-07-06 20:38:45 +00:00

63 lines
1.8 KiB
Rust

use std::convert::Infallible;
use std::ffi::CString;
use std::string::String;
use ufmt_write::uWrite;
use windows::core::PCSTR;
use windows::Win32::{
Foundation::INVALID_HANDLE_VALUE,
Storage::FileSystem::WriteFile,
System::Console::{GetStdHandle, STD_ERROR_HANDLE},
UI::WindowsAndMessaging::{MessageBoxA, MESSAGEBOX_STYLE},
};
#[macro_export]
macro_rules! eprintln {
($($tt:tt)*) => {{
$crate::diagnostics::write_diagnostic(&$crate::format!($($tt)*));
}}
}
#[macro_export]
macro_rules! format {
($($tt:tt)*) => {{
let mut buffer = $crate::diagnostics::StringBuffer::default();
_ = ufmt::uwriteln!(&mut buffer, $($tt)*);
buffer.0
}}
}
#[derive(Default)]
pub(crate) struct StringBuffer(pub(crate) String);
impl uWrite for StringBuffer {
type Error = Infallible;
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
self.0.push_str(s);
Ok(())
}
}
#[cold]
pub(crate) fn write_diagnostic(message: &str) {
let handle = unsafe { GetStdHandle(STD_ERROR_HANDLE) }.unwrap_or(INVALID_HANDLE_VALUE);
let mut written: u32 = 0;
let mut remaining = message;
while !remaining.is_empty() {
// If we get an error, it means we tried to write to an invalid handle (GUI Application)
// and we should try to write to a window instead
if unsafe { WriteFile(handle, Some(remaining.as_bytes()), Some(&mut written), None) }
.is_err()
{
let nul_terminated = unsafe { CString::new(message.as_bytes()).unwrap_unchecked() };
let pcstr_message = PCSTR::from_raw(nul_terminated.as_ptr() as *const _);
unsafe { MessageBoxA(None, pcstr_message, None, MESSAGEBOX_STYLE(0)) };
return;
}
if let Some(out) = remaining.get(written as usize..) {
remaining = out
}
}
}