Skip to content

Commit 73137e7

Browse files
authored
Fixing property parsing issue on Rust 1.78+ (n4r1b#129)
* adding safety checks to support calls to from_raw_parts() * adding temp debug prints * more triaging * temporarily removing alignment check for strings * trying to use Vec<u16> to fix pointer alignment weirdness * cleanup
1 parent 8602d9c commit 73137e7

File tree

1 file changed

+34
-6
lines changed

1 file changed

+34
-6
lines changed

src/parser.rs

+34-6
Original file line numberDiff line numberDiff line change
@@ -371,17 +371,38 @@ macro_rules! impl_try_parse_primitive_array {
371371
match prop_slice.property.info {
372372
PropertyInfo::Array { .. } => {
373373
// TODO: Check In and Out type and do a better type checking
374+
375+
// This property type has not been tested yet as I don't have a
376+
// provider that uses it. It's possible that the buffer is not
377+
// aligned correctly, which would cause this to fail.
374378
let size = std::mem::size_of::<$T>();
379+
let align = std::mem::align_of::<$T>();
380+
375381
if prop_slice.buffer.len() % size != 0 {
376382
return Err(ParserError::LengthMismatch);
377383
}
384+
378385
let count = prop_slice.buffer.len() / size;
386+
387+
if prop_slice.buffer.as_ptr() as usize % align != 0 {
388+
return Err(ParserError::PropertyError(
389+
"buffer alignment mismatch".into()
390+
));
391+
}
392+
393+
if size.checked_mul(count).is_none() || (size * count) > isize::MAX as usize {
394+
return Err(ParserError::PropertyError(
395+
"size overflow".into()
396+
));
397+
}
398+
379399
let slice = unsafe {
380400
std::slice::from_raw_parts(
381401
prop_slice.buffer.as_ptr() as *const $T,
382402
count,
383403
)
384404
};
405+
385406
Ok(slice)
386407
}
387408
_ => Err(ParserError::InvalidType),
@@ -447,19 +468,26 @@ impl private::TryParse<String> for Parser<'_, '_> {
447468
));
448469
}
449470

450-
let mut wide = unsafe {
451-
std::slice::from_raw_parts(
452-
prop_slice.buffer.as_ptr() as *const u16,
453-
prop_slice.buffer.len() / 2,
454-
)
455-
};
471+
// std::slice::from_raw_parts requires a pointer to be aligned, but we can't
472+
// guarantee that the buffer is aligned. In testing, I found that the buffer
473+
// is in fact never aligned appropriately, so a cheap workaround is to copy
474+
// the buffer into a new Vec<u16> and use that as the source for the slice
475+
// until we can find a better solution.
476+
let mut aligned_buffer = Vec::with_capacity(prop_slice.buffer.len() / 2);
477+
for chunk in prop_slice.buffer.chunks_exact(2) {
478+
let part = u16::from_ne_bytes([chunk[0], chunk[1]]);
479+
aligned_buffer.push(part);
480+
}
481+
482+
let mut wide = aligned_buffer.as_slice();
456483

457484
match wide.last() {
458485
// remove the null terminator from the slice
459486
Some(c) if c == &0 => wide = &wide[..wide.len() - 1],
460487
_ => (),
461488
}
462489

490+
// Decode UTF-16 to String
463491
Ok(widestring::decode_utf16_lossy(wide.iter().copied()).collect::<String>())
464492
}
465493
TdhInType::InTypeAnsiString => {

0 commit comments

Comments
 (0)