Skip to content

Commit 4cbf2c2

Browse files
authored
Fix misaligned pointer dereference when storing UserData (#211)
* Fix misaligned pointer dereference when storing UserData closes #210 * chore: run cargo fmt in physx-sys/pxbind
1 parent 60827dd commit 4cbf2c2

File tree

5 files changed

+73
-11
lines changed

5 files changed

+73
-11
lines changed

physx-sys/pxbind/src/consumer.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,9 @@ impl<'ast> AstConsumer<'ast> {
299299
// If a record decl doesn't have any inner nodes, it's just
300300
// a foreward declaration and we can skip it
301301
if inn.inner.is_empty() || rec.definition_data.is_none() {
302-
let Some(name) = rec.name.as_deref() else { continue; };
302+
let Some(name) = rec.name.as_deref() else {
303+
continue;
304+
};
303305

304306
if !self.classes.contains_key(name) {
305307
self.recs

physx-sys/pxbind/src/consumer/enums.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,9 @@ impl<'ast> super::AstConsumer<'ast> {
182182
// PhysX uses a PxFlags<> template typedef to create a bitfield type for
183183
// a specific enum, we use this typedef to also generate an appropriate
184184
// bitflags that can be transparently passed between the FFI boundary
185-
let Some(flags) = super::no_physx(&td.kind.qual_type).strip_prefix("PxFlags<") else { return Ok(()) };
185+
let Some(flags) = super::no_physx(&td.kind.qual_type).strip_prefix("PxFlags<") else {
186+
return Ok(());
187+
};
186188
// Get rid of `>`
187189
let flags = &flags[..flags.len() - 1];
188190

physx-sys/pxbind/src/consumer/record.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ impl Constructor {
5858
}
5959
});
6060

61-
let Some(first) = iter.next() else { return false };
61+
let Some(first) = iter.next() else {
62+
return false;
63+
};
6264

6365
if first.ends_with(" &&") {
6466
return true;
@@ -443,7 +445,9 @@ impl<'ast> super::AstConsumer<'ast> {
443445
return Ok(());
444446
}
445447

446-
let Some(rname) = rec.name.as_deref() else { return Ok(()) };
448+
let Some(rname) = rec.name.as_deref() else {
449+
return Ok(());
450+
};
447451

448452
anyhow::ensure!(
449453
rec.definition_data.is_some(),
@@ -674,7 +678,9 @@ impl<'ast> super::AstConsumer<'ast> {
674678
template_types: &[(&str, &super::TemplateArg<'ast>)],
675679
fields: &mut Vec<FieldBinding<'ast>>,
676680
) -> anyhow::Result<()> {
677-
let Some(rname) = rec.name.as_deref() else { return Ok(()) };
681+
let Some(rname) = rec.name.as_deref() else {
682+
return Ok(());
683+
};
678684
let mut is_public = !matches!(rec.tag_used, Some(Tag::Class));
679685

680686
for inn in &node.inner {

physx/CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ into mutable and immutable variants.
1212
- `ActorMap::as_rigid_static` -> `ActorMap::as_rigid_static_mut`
1313
- `ActorMap::as_articulation_link` -> `ActorMap::as_articulation_link_mut`
1414

15+
### Fixed
16+
- [PR#211](https://github.com/EmbarkStudios/physx-rs/pull/211) fixed misaligned pointer dereference when using `UserData` with small-size values.
17+
1518
## [0.18.0] - 2023-03-03
1619
### Changed
1720
- [PR#191](https://github.com/EmbarkStudios/physx-rs/pull/191) replaced `PxCooking` with regular functions as `PxCooking` is deprecated in the C++ code.

physx/src/traits/user_data.rs

+55-6
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,11 @@ pub unsafe trait UserData: Sized {
2121
unsafe fn init_user_data(&mut self, user_data: Self::UserData) -> &mut Self {
2222
if size_of::<Self::UserData>() > size_of::<*mut c_void>() {
2323
// Too big to pack into a *mut c_void, kick it to the heap.
24-
let data = Box::new(user_data);
25-
*self.user_data_ptr_mut() = Box::into_raw(data) as *mut c_void;
24+
let data = Box::into_raw(Box::new(user_data));
25+
*(self.user_data_ptr_mut() as *mut *mut c_void as *mut *mut Self::UserData) = data;
2626
} else {
2727
// DATA_SIZE <= VOID_SIZE
28-
unsafe {
29-
*self.user_data_ptr_mut() =
30-
*(&user_data as *const Self::UserData as *const *mut c_void)
31-
}
28+
*(self.user_data_ptr_mut() as *mut *mut c_void as *mut Self::UserData) = user_data;
3229
}
3330
self
3431
}
@@ -49,6 +46,7 @@ pub unsafe trait UserData: Sized {
4946
}
5047

5148
/// # Safety
49+
///
5250
/// The user data field must have previously been initialized via `init_user_data`.
5351
unsafe fn get_user_data_mut(this: &mut Self) -> &mut Self::UserData {
5452
unsafe {
@@ -63,3 +61,54 @@ pub unsafe trait UserData: Sized {
6361
}
6462
}
6563
}
64+
65+
#[cfg(test)]
66+
mod tests {
67+
use std::{ffi::c_void, fmt::Debug, marker::PhantomData, ptr::null_mut};
68+
69+
use super::UserData;
70+
71+
struct TestUserData<U> {
72+
user_data: *mut c_void,
73+
phantom: PhantomData<U>,
74+
}
75+
76+
impl<U> Default for TestUserData<U> {
77+
fn default() -> Self {
78+
Self {
79+
user_data: null_mut(),
80+
phantom: PhantomData,
81+
}
82+
}
83+
}
84+
85+
unsafe impl<U> UserData for TestUserData<U> {
86+
type UserData = U;
87+
88+
fn user_data_ptr(&self) -> &*mut c_void {
89+
&self.user_data
90+
}
91+
92+
fn user_data_ptr_mut(&mut self) -> &mut *mut c_void {
93+
&mut self.user_data
94+
}
95+
}
96+
97+
fn do_test<U: PartialEq + Clone + Debug>(user_data: U) {
98+
unsafe {
99+
let mut object: TestUserData<U> = TestUserData::default();
100+
object.init_user_data(user_data.clone());
101+
102+
assert_eq!(UserData::get_user_data(&object), &user_data);
103+
assert_eq!(UserData::get_user_data_mut(&mut object), &user_data);
104+
}
105+
}
106+
107+
#[test]
108+
fn test_user_data() {
109+
do_test(()); // unit type
110+
do_test(100u8); // smaller than pointer
111+
do_test(100usize); // same size as pointer
112+
do_test([100usize; 4]); // larger than pointer
113+
}
114+
}

0 commit comments

Comments
 (0)