Skip to content

Commit 76d607d

Browse files
committed
Fix misaligned pointer dereference when storing UserData
closes EmbarkStudios#210
1 parent 60827dd commit 76d607d

File tree

2 files changed

+58
-6
lines changed

2 files changed

+58
-6
lines changed

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 as pointer
112+
do_test([100usize; 4]); // larger than pointer
113+
}
114+
}

0 commit comments

Comments
 (0)