Skip to content

Commit e785741

Browse files
committed
fix(crashtracking): repair macOS sidecar connector
1 parent 0aa19a2 commit e785741

1 file changed

Lines changed: 98 additions & 2 deletions

File tree

components-rs/lib.rs

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ fn reuse_sidecar_fd_connector(_unix_socket_path: &str) -> std::os::fd::RawFd {
324324
}
325325

326326
// Best-effort, signal context: read the transport pointer and get its current fd via
327-
// SidecarTransport::signal_fd (which uses get_mut, never locking). Going through the raw
327+
// SidecarTransport::as_raw_fd (which uses get_mut, never locking). Going through the raw
328328
// pointer knowingly bypasses aliasing checks — the crashing thread is the only realistic
329329
// accessor.
330330
let transport = unsafe { datadog_sidecar_for_signal }
@@ -333,8 +333,104 @@ fn reuse_sidecar_fd_connector(_unix_socket_path: &str) -> std::os::fd::RawFd {
333333
return -1;
334334
}
335335
let fd = unsafe { (*transport).as_raw_fd() };
336+
prepare_crashtracker_sidecar_fd(fd)
337+
}
338+
339+
#[cfg(target_os = "macos")]
340+
fn prepare_crashtracker_sidecar_fd(fd: std::os::fd::RawFd) -> std::os::fd::RawFd {
341+
// Crashtracker takes ownership of and closes the connector fd. Duplicate the sidecar
342+
// transport fd so reporting an exception cannot leave the transport holding a closed fd.
343+
let crashtracker_fd = unsafe { libc::dup(fd) };
344+
if crashtracker_fd < 0 {
345+
return -1;
346+
}
347+
336348
let bytes = crashtracker_receiver_request_bytes();
337-
let sent = unsafe { libc::send(dup, bytes.as_ptr() as *const libc::c_void, bytes.len(), 0) };
349+
let sent = unsafe {
350+
libc::send(
351+
crashtracker_fd,
352+
bytes.as_ptr().cast::<libc::c_void>(),
353+
bytes.len(),
354+
0,
355+
)
356+
};
357+
if sent != bytes.len() as isize {
358+
// Preserve the send error for Receiver::from_connector's last_os_error().
359+
let errno = if sent < 0 {
360+
unsafe { *libc::__error() }
361+
} else {
362+
libc::EIO
363+
};
364+
unsafe {
365+
libc::close(crashtracker_fd);
366+
*libc::__error() = errno;
367+
}
368+
return -1;
369+
}
370+
371+
crashtracker_fd
372+
}
373+
374+
#[cfg(all(test, target_os = "macos"))]
375+
mod crashtracker_connector_tests {
376+
use super::*;
377+
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
378+
379+
fn dgram_pair() -> (OwnedFd, OwnedFd) {
380+
let mut fds = [-1; 2];
381+
let result =
382+
unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_DGRAM, 0, fds.as_mut_ptr()) };
383+
assert_eq!(result, 0, "socketpair: {}", std::io::Error::last_os_error());
384+
unsafe {
385+
(
386+
OwnedFd::from_raw_fd(fds[0]),
387+
OwnedFd::from_raw_fd(fds[1]),
388+
)
389+
}
390+
}
391+
392+
fn recv(fd: &OwnedFd, buffer: &mut [u8]) -> usize {
393+
let received = unsafe {
394+
libc::recv(
395+
fd.as_raw_fd(),
396+
buffer.as_mut_ptr().cast::<libc::c_void>(),
397+
buffer.len(),
398+
0,
399+
)
400+
};
401+
assert!(received >= 0, "recv: {}", std::io::Error::last_os_error());
402+
received as usize
403+
}
404+
405+
#[test]
406+
fn connector_sends_upgrade_request_without_consuming_transport_fd() {
407+
let (transport, peer) = dgram_pair();
408+
409+
let crashtracker_fd = prepare_crashtracker_sidecar_fd(transport.as_raw_fd());
410+
assert!(crashtracker_fd >= 0);
411+
let crashtracker_fd = unsafe { OwnedFd::from_raw_fd(crashtracker_fd) };
412+
413+
let expected = crashtracker_receiver_request_bytes();
414+
let mut received = vec![0; expected.len()];
415+
let len = recv(&peer, &mut received);
416+
assert_eq!(&received[..len], expected);
417+
418+
drop(crashtracker_fd);
419+
let message = b"transport-still-open";
420+
let sent = unsafe {
421+
libc::send(
422+
transport.as_raw_fd(),
423+
message.as_ptr().cast::<libc::c_void>(),
424+
message.len(),
425+
0,
426+
)
427+
};
428+
assert_eq!(sent, message.len() as isize);
429+
430+
let mut received = [0; 32];
431+
let len = recv(&peer, &mut received);
432+
assert_eq!(&received[..len], message);
433+
}
338434
}
339435

340436
// Hack: Without this, the PECL build of the tracer does not contain the ddog_library_* functions

0 commit comments

Comments
 (0)