Skip to content

Commit 5a69542

Browse files
committed
fix interior null checking on windows
whelp!
1 parent 6f25c6f commit 5a69542

File tree

2 files changed

+43
-12
lines changed

2 files changed

+43
-12
lines changed

src/as_filename.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub trait AsFilename {
1616
sealed: SealedFilename,
1717
function: impl FnOnce(*const u16) -> Result<R, crate::Error>,
1818
) -> Result<R, crate::Error>;
19+
1920
#[cfg(unix)]
2021
#[doc(hidden)]
2122
fn posix_filename<R>(
@@ -32,7 +33,11 @@ impl AsFilename for &str {
3233
_seal: SealedFilename,
3334
function: impl FnOnce(*const u16) -> Result<R, Error>,
3435
) -> Result<R, Error> {
35-
let utf16: alloc::vec::Vec<u16> = self.encode_utf16().chain(Some(0)).collect();
36+
let utf16: alloc::vec::Vec<u16> = if crate::util::check_null_bytes(self.as_bytes())? {
37+
self.encode_utf16().collect()
38+
} else {
39+
self.encode_utf16().chain(Some(0)).collect()
40+
};
3641
function(utf16.as_ptr())
3742
}
3843

@@ -110,10 +115,14 @@ mod std {
110115
_seal: SealedFilename,
111116
function: impl FnOnce(*const u16) -> Result<R, Error>,
112117
) -> Result<R, Error> {
113-
let wide: alloc::vec::Vec<u16> = std::os::windows::ffi::OsStrExt::encode_wide(self)
114-
.chain(Some(0))
115-
.collect();
116-
function(wide.as_ptr())
118+
use std::os::windows::ffi::OsStrExt;
119+
let bytes = self.as_encoded_bytes();
120+
let utf16: alloc::vec::Vec<u16> = if crate::util::check_null_bytes(bytes)? {
121+
self.encode_wide().collect()
122+
} else {
123+
self.encode_wide().chain(Some(0)).collect()
124+
};
125+
function(utf16.as_ptr())
117126
}
118127

119128
#[cfg(unix)]

tests/functions.rs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,33 +72,34 @@ fn test_id_u32() {
7272
#[cfg(feature = "std")]
7373
#[test]
7474
fn test_as_filename_osstring() {
75-
as_filename_test::<std::ffi::OsString>(lib_path().into_os_string());
75+
as_filename_test::<std::ffi::OsString>(lib_path().into_os_string(), "potato\0beetroot".into());
7676
}
7777

7878
#[cfg(feature = "std")]
7979
#[test]
8080
fn test_as_filename_osstr() {
81-
as_filename_test::<&std::ffi::OsStr>(lib_path().as_os_str());
81+
let with_nulls = std::ffi::OsStr::new("hazelnut\0peanut");
82+
as_filename_test::<&std::ffi::OsStr>(lib_path().as_os_str(), with_nulls);
8283
}
8384

8485
#[cfg(feature = "std")]
8586
#[test]
8687
fn test_as_filename_pathbuf() {
87-
as_filename_test::<std::path::PathBuf>(lib_path());
88+
as_filename_test::<std::path::PathBuf>(lib_path(), "orange\0grape".into());
8889
}
8990

9091
#[cfg(feature = "std")]
9192
#[test]
9293
fn test_as_filename_path() {
93-
as_filename_test::<&std::path::Path>(&*lib_path());
94+
as_filename_test::<&std::path::Path>(&*lib_path(), std::path::Path::new("peach\0mango"));
9495
}
9596

9697
#[cfg(feature = "std")]
9798
#[test]
9899
fn test_as_filename_str() {
99100
let path = lib_path();
100101
if let Some(p) = path.to_str() {
101-
as_filename_test::<&str>(p);
102+
as_filename_test::<&str>(p, "kiwi\0peach\0");
102103
}
103104
}
104105

@@ -107,14 +108,18 @@ fn test_as_filename_str() {
107108
fn test_as_filename_string() {
108109
let path = lib_path();
109110
if let Some(p) = path.to_str() {
110-
as_filename_test::<String>(p.to_string());
111+
as_filename_test::<String>(p.to_string(), "apple\0banana".to_string());
111112
}
112113
}
113114

114115
#[cfg(feature = "std")]
115-
fn as_filename_test<T: libloading::AsFilename>(path: T) {
116+
fn as_filename_test<T: libloading::AsFilename>(path: T, with_interior_nulls: T) {
116117
make_helpers();
117118
unsafe {
119+
assert!(matches!(
120+
Library::new(with_interior_nulls).unwrap_err(),
121+
libloading::Error::InteriorZeroElements,
122+
));
118123
let lib = Library::new(path).unwrap();
119124
let f: Symbol<unsafe extern "C" fn(u32) -> u32> = lib.get(b"test_identity_u32\0").unwrap();
120125
assert_eq!(42, f(42));
@@ -126,13 +131,15 @@ fn as_filename_test<T: libloading::AsFilename>(path: T) {
126131
fn test_as_symbol_name_string() {
127132
as_symbol_name_test::<String>("test_identity_u32".to_string());
128133
as_symbol_name_test::<String>("test_identity_u32\0".to_string());
134+
as_symbol_name_test_interior_nulls::<String>("test_iden\0tity_u32".to_string());
129135
}
130136

131137
#[cfg(feature = "std")]
132138
#[test]
133139
fn test_as_symbol_name_str() {
134140
as_symbol_name_test::<&str>("test_identity_u32");
135141
as_symbol_name_test::<&str>("test_identity_u32\0");
142+
as_symbol_name_test_interior_nulls::<&str>("test_iden\0tity_u32\0");
136143
}
137144

138145
#[cfg(feature = "std")]
@@ -153,6 +160,9 @@ fn test_as_symbol_name_bytes() {
153160
as_symbol_name_test::<&[u8]>(b"test_identity_u32");
154161
as_symbol_name_test::<&[u8]>(b"test_identity_u32\0");
155162
as_symbol_name_test::<&[u8; 18]>(b"test_identity_u32\0");
163+
as_symbol_name_test_interior_nulls::<&[u8]>(b"test_identity\0_u32");
164+
as_symbol_name_test_interior_nulls::<&[u8]>(b"test\0_identity_u32");
165+
as_symbol_name_test_interior_nulls::<&[u8; 19]>(b"test_iden\0tity_u32\0");
156166
}
157167

158168
#[cfg(feature = "std")]
@@ -165,6 +175,18 @@ fn as_symbol_name_test<T: libloading::AsSymbolName>(symbol: T) {
165175
}
166176
}
167177

178+
#[cfg(feature = "std")]
179+
fn as_symbol_name_test_interior_nulls<T: libloading::AsSymbolName>(symbol: T) {
180+
make_helpers();
181+
unsafe {
182+
let lib = Library::new(lib_path()).unwrap();
183+
assert!(matches!(
184+
lib.get::<unsafe extern "C" fn(u32) -> u32>(symbol),
185+
Err(libloading::Error::InteriorZeroElements),
186+
));
187+
}
188+
}
189+
168190
#[test]
169191
#[cfg(feature = "std")]
170192
fn test_try_into_ptr() {

0 commit comments

Comments
 (0)