@@ -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