Skip to content

Commit b386595

Browse files
committed
Fix macOS debug build crashes due to unaligned reads.
This is a port of servo/ipc-channel#314 , originally written by Mukilan Thiyagarajan <[email protected]> .
1 parent 4c8d5eb commit b386595

File tree

8 files changed

+82519
-23851
lines changed

8 files changed

+82519
-23851
lines changed
Binary file not shown.
Binary file not shown.
Binary file not shown.

samply-mac-preload/src/mach_ipc.rs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ const KERN_NO_SPACE: kern_return_t = 3;
3939
const MACH_MSGH_BITS_COMPLEX: u32 = 0x80000000;
4040
const MACH_MSG_IPC_KERNEL: kern_return_t = 0x00000800;
4141
const MACH_MSG_IPC_SPACE: kern_return_t = 0x00002000;
42-
const MACH_MSG_PORT_DESCRIPTOR: u8 = 0;
42+
const MACH_MSG_PORT_DESCRIPTOR: u32 = 0;
4343
const MACH_MSG_SUCCESS: kern_return_t = 0;
4444
const MACH_MSG_TIMEOUT_NONE: mach_msg_timeout_t = 0;
45-
const MACH_MSG_TYPE_COPY_SEND: u8 = 19;
46-
const MACH_MSG_TYPE_MAKE_SEND: u8 = 20;
47-
const MACH_MSG_TYPE_MAKE_SEND_ONCE: u8 = 21;
48-
const MACH_MSG_TYPE_MOVE_SEND: u8 = 17;
49-
const MACH_MSG_TYPE_PORT_SEND: u8 = MACH_MSG_TYPE_MOVE_SEND;
45+
const MACH_MSG_TYPE_COPY_SEND: u32 = 19;
46+
const MACH_MSG_TYPE_MAKE_SEND: u32 = 20;
47+
const MACH_MSG_TYPE_MAKE_SEND_ONCE: u32 = 21;
48+
const MACH_MSG_TYPE_MOVE_SEND: u32 = 17;
49+
const MACH_MSG_TYPE_PORT_SEND: u32 = MACH_MSG_TYPE_MOVE_SEND;
5050
const MACH_MSG_VM_KERNEL: kern_return_t = 0x00000400;
5151
const MACH_MSG_VM_SPACE: kern_return_t = 0x00001000;
5252
const MACH_NOTIFY_FIRST: i32 = 64;
@@ -174,7 +174,7 @@ impl OsIpcReceiver {
174174
mach_task_self(),
175175
port,
176176
MACH_PORT_LIMITS_INFO,
177-
&limits as *const mach_sys::Struct_mach_port_limits as *mut i32,
177+
&limits as *const mach_sys::mach_port_limits as *mut i32,
178178
1,
179179
)
180180
};
@@ -194,9 +194,8 @@ impl OsIpcReceiver {
194194
fn sender(&self) -> Result<OsIpcSender, MachError> {
195195
let port = self.port.get();
196196
debug_assert!(port != MACH_PORT_NULL);
197-
let (right, acquired_right) =
198-
mach_port_extract_right(port, MACH_MSG_TYPE_MAKE_SEND as u32)?;
199-
debug_assert!(acquired_right == MACH_MSG_TYPE_PORT_SEND as u32);
197+
let (right, acquired_right) = mach_port_extract_right(port, MACH_MSG_TYPE_MAKE_SEND)?;
198+
debug_assert!(acquired_right == MACH_MSG_TYPE_PORT_SEND);
200199
Ok(OsIpcSender::from_name(right))
201200
}
202201

@@ -249,7 +248,7 @@ impl OsIpcReceiver {
249248
let mut port_descriptor = message.offset(1) as *mut mach_msg_port_descriptor_t;
250249
let mut descriptors_remaining = (*message).body.msgh_descriptor_count;
251250
while descriptors_remaining > 0 {
252-
if (*port_descriptor).type_ != MACH_MSG_PORT_DESCRIPTOR {
251+
if (*port_descriptor).type_() != MACH_MSG_PORT_DESCRIPTOR {
253252
break;
254253
}
255254
let _ = (*port_descriptor).name;
@@ -265,7 +264,9 @@ impl OsIpcReceiver {
265264
let has_inline_data_ptr = shared_memory_descriptor as *mut bool;
266265
let has_inline_data = *has_inline_data_ptr;
267266
let payload = if has_inline_data {
268-
let payload_size_ptr = has_inline_data_ptr.offset(1) as *mut usize;
267+
let padding_start = has_inline_data_ptr.offset(1) as *mut u8;
268+
let padding_count = Message::payload_padding(padding_start as usize);
269+
let payload_size_ptr = padding_start.add(padding_count) as *mut usize;
269270
let payload_size = *payload_size_ptr;
270271
let max_payload_size = message as usize + ((*message).header.msgh_size as usize)
271272
- (shared_memory_descriptor as usize);
@@ -362,11 +363,10 @@ impl OsIpcSender {
362363
unsafe {
363364
let size = Message::size_of(data, ports.len(), 0);
364365
let message = libc::malloc(size as size_t) as *mut Message;
365-
(*message).header.msgh_bits = (MACH_MSG_TYPE_COPY_SEND as u32) | MACH_MSGH_BITS_COMPLEX;
366+
(*message).header.msgh_bits = (MACH_MSG_TYPE_COPY_SEND) | MACH_MSGH_BITS_COMPLEX;
366367
(*message).header.msgh_size = size as u32;
367368
(*message).header.msgh_local_port = MACH_PORT_NULL;
368369
(*message).header.msgh_remote_port = self.port;
369-
(*message).header.msgh_reserved = 0;
370370
(*message).header.msgh_id = 0;
371371
(*message).body.msgh_descriptor_count = ports.len() as u32;
372372

@@ -375,12 +375,13 @@ impl OsIpcSender {
375375
(*port_descriptor_dest).name = outgoing_port.port();
376376
(*port_descriptor_dest).pad1 = 0;
377377

378-
(*port_descriptor_dest).disposition = match *outgoing_port {
378+
let disposition = match *outgoing_port {
379379
OsIpcChannel::Sender(_) => MACH_MSG_TYPE_MOVE_SEND,
380380
OsIpcChannel::RawPort(_) => MACH_MSG_TYPE_COPY_SEND,
381381
};
382+
(*port_descriptor_dest).set_disposition(disposition);
382383

383-
(*port_descriptor_dest).type_ = MACH_MSG_PORT_DESCRIPTOR;
384+
(*port_descriptor_dest).set_type(MACH_MSG_PORT_DESCRIPTOR);
384385
port_descriptor_dest = port_descriptor_dest.offset(1);
385386
}
386387

@@ -394,7 +395,11 @@ impl OsIpcSender {
394395
*((message as *mut u8).offset(size as isize - 4) as *mut u32) = 0;
395396

396397
let data_size = data.len();
397-
let data_size_dest = is_inline_dest.offset(1) as *mut usize;
398+
let padding_start = is_inline_dest.offset(1) as *mut u8;
399+
let padding_count = Message::payload_padding(padding_start as usize);
400+
// Zero out padding
401+
padding_start.write_bytes(0, padding_count);
402+
let data_size_dest = padding_start.add(padding_count) as *mut usize;
398403
*data_size_dest = data_size;
399404

400405
let data_dest = data_size_dest.offset(1) as *mut u8;
@@ -465,12 +470,19 @@ struct Message {
465470
}
466471

467472
impl Message {
473+
fn payload_padding(unaligned: usize) -> usize {
474+
((unaligned + 7) & !7) - unaligned // 8 byte alignment
475+
}
476+
468477
fn size_of(data: &[u8], port_length: usize, shared_memory_length: usize) -> usize {
469478
let mut size = mem::size_of::<Message>()
470479
+ mem::size_of::<mach_msg_port_descriptor_t>() * port_length
471480
+ mem::size_of::<mach_msg_ool_descriptor_t>() * shared_memory_length
472481
+ mem::size_of::<bool>();
473482

483+
// rustc panics in debug mode for unaligned accesses.
484+
// so include padding to start payload at 8-byte aligned address
485+
size += Self::payload_padding(size);
474486
size += mem::size_of::<usize>() + data.len();
475487

476488
// Round up to the next 4 bytes; mach_msg_send returns an error for unaligned sizes.

0 commit comments

Comments
 (0)