我有一个Rust程序,它的行为取决于应用的优化级别。这是一个简单的程序,显示Win32 MessageBoxW
。
以下是opt-level = 0
的输出:
下面是opt-level = 1
的输出:
下面是opt-level = 2
的输出:
下面是程序的一个最小可重复的例子。它不太一样,因为我的二进制是no_std
(因此我使用alloc
crate),但是每个优化级别的行为都是相似的。
extern crate alloc;
use std::{
ffi::{c_char, c_int, c_uint},
ptr::null_mut,
};
pub enum HWND__ {}
pub type HWND = *mut HWND__;
pub type DWORD = u32;
pub type LPCCH = *const c_char;
pub type LPCWSTR = *const u16;
pub type LPWSTR = *mut u16;
pub type UINT = c_uint;
pub const CP_UTF8: DWORD = 65001;
pub const MB_ERR_INVALID_CHARS: DWORD = 0x08;
pub const MB_OK: UINT = 0x00000000;
macro_rules! wide_str {
($($arg:tt)*) => {{
let utf8 = alloc::fmt::format(format_args!($($arg)*));
const BUFFER_LEN: usize = 256;
let utf16: &[u16; BUFFER_LEN] = {
let mut utf16 = [0; BUFFER_LEN];
let result = MultiByteToWideChar(
CP_UTF8,
MB_ERR_INVALID_CHARS,
utf8.as_ptr() as LPCCH,
utf8.len() as core::ffi::c_int,
utf16.as_mut_ptr() as LPWSTR,
utf16.len() as core::ffi::c_int,
);
assert!(result != 0, "error converting utf8 to utf16");
&{ utf16 }
};
utf16.as_ptr()
}};
}
#[link(name = "kernel32")]
extern "system" {
pub fn MultiByteToWideChar(
CodePage: UINT,
dwFlags: DWORD,
lpMultiByteStr: LPCCH,
cbMultiByte: c_int,
lpWideCharStr: LPWSTR,
cchWideChar: c_int,
) -> c_int;
}
#[link(name = "user32")]
extern "system" {
pub fn MessageBoxW(hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT) -> c_int;
}
fn main() {
unsafe {
MessageBoxW(
null_mut(),
wide_str!("Message!"),
wide_str!("Caption!"),
MB_OK,
);
}
}
为什么会出现这种产量差异,如何解决?
1条答案
按热度按时间okxuctiv1#
由
wide_str!
创建的指针是悬空的,因为utf16
(具有相同名称的内部和外部变量)在MessageBoxW
被调用之前就被破坏了。它可能会中断并导致像这样的不一致,甚至更糟的是,它可能看起来有效,但后来或以更微妙的方式被中断。为了避免将来的误用,我建议从你的宏中返回一个拥有数据的值,你可以手动调用
.as_ptr()
。类似这样:这并没有表现出你所看到的行为。