@@ -11,62 +11,95 @@ use std::{fs, path::PathBuf};
1111
1212use  anyhow:: Context ; 
1313use  bin_tests:: { build_artifacts,  ArtifactType ,  ArtifactsBuild ,  BuildProfile } ; 
14+ use  serde_json:: Value ; 
1415
1516#[ test]  
1617#[ cfg_attr( miri,  ignore) ]  
1718fn  test_crash_tracking_bin_debug ( )  { 
18-     test_crash_tracking_bin ( BuildProfile :: Debug ,  "donothing" ) ; 
19+     test_crash_tracking_bin ( BuildProfile :: Debug ,  "donothing" ,   "null_deref" ) ; 
1920} 
2021
2122#[ test]  
2223#[ cfg_attr( miri,  ignore) ]  
2324fn  test_crash_tracking_bin_sigpipe ( )  { 
24-     test_crash_tracking_bin ( BuildProfile :: Debug ,  "sigpipe" ) ; 
25+     test_crash_tracking_bin ( BuildProfile :: Debug ,  "sigpipe" ,   "null_deref" ) ; 
2526} 
2627
2728#[ test]  
2829#[ cfg_attr( miri,  ignore) ]  
2930fn  test_crash_tracking_bin_sigchld ( )  { 
30-     test_crash_tracking_bin ( BuildProfile :: Debug ,  "sigchld" ) ; 
31+     test_crash_tracking_bin ( BuildProfile :: Debug ,  "sigchld" ,   "null_deref" ) ; 
3132} 
3233
3334#[ test]  
3435#[ cfg_attr( miri,  ignore) ]  
3536fn  test_crash_tracking_bin_sigchld_exec ( )  { 
36-     test_crash_tracking_bin ( BuildProfile :: Debug ,  "sigchld_exec" ) ; 
37+     test_crash_tracking_bin ( BuildProfile :: Debug ,  "sigchld_exec" ,   "null_deref" ) ; 
3738} 
3839
3940#[ test]  
4041#[ cfg_attr( miri,  ignore) ]  
4142fn  test_crash_tracking_bin_sigstack ( )  { 
42-     test_crash_tracking_bin ( BuildProfile :: Release ,  "donothing_sigstack" ) ; 
43+     test_crash_tracking_bin ( BuildProfile :: Release ,  "donothing_sigstack" ,   "null_deref" ) ; 
4344} 
4445
4546#[ test]  
4647#[ cfg_attr( miri,  ignore) ]  
4748fn  test_crash_tracking_bin_sigpipe_sigstack ( )  { 
48-     test_crash_tracking_bin ( BuildProfile :: Release ,  "sigpipe_sigstack" ) ; 
49+     test_crash_tracking_bin ( BuildProfile :: Release ,  "sigpipe_sigstack" ,   "null_deref" ) ; 
4950} 
5051
5152#[ test]  
5253#[ cfg_attr( miri,  ignore) ]  
5354fn  test_crash_tracking_bin_sigchld_sigstack ( )  { 
54-     test_crash_tracking_bin ( BuildProfile :: Release ,  "sigchld_sigstack" ) ; 
55+     test_crash_tracking_bin ( BuildProfile :: Release ,  "sigchld_sigstack" ,   "null_deref" ) ; 
5556} 
5657
5758#[ test]  
5859#[ cfg_attr( miri,  ignore) ]  
5960fn  test_crash_tracking_bin_chained ( )  { 
60-     test_crash_tracking_bin ( BuildProfile :: Release ,  "chained" ) ; 
61+     test_crash_tracking_bin ( BuildProfile :: Release ,  "chained" ,   "null_deref" ) ; 
6162} 
6263
6364#[ test]  
6465#[ cfg_attr( miri,  ignore) ]  
6566fn  test_crash_tracking_bin_fork ( )  { 
66-     test_crash_tracking_bin ( BuildProfile :: Release ,  "fork" ) ; 
67+     test_crash_tracking_bin ( BuildProfile :: Release ,  "fork" ,   "null_deref" ) ; 
6768} 
6869
69- fn  test_crash_tracking_bin ( crash_tracking_receiver_profile :  BuildProfile ,  mode :  & str )  { 
70+ #[ test]  
71+ #[ cfg_attr( miri,  ignore) ]  
72+ fn  test_crash_tracking_bin_abort ( )  { 
73+     // For now, do the base test (donothing).  For future we should probably also test chaining. 
74+     test_crash_tracking_bin ( BuildProfile :: Release ,  "donothing" ,  "sigabrt" ) ; 
75+ } 
76+ 
77+ #[ test]  
78+ #[ cfg_attr( miri,  ignore) ]  
79+ fn  test_crash_tracking_bin_sigill ( )  { 
80+     // For now, do the base test (donothing).  For future we should probably also test chaining. 
81+     test_crash_tracking_bin ( BuildProfile :: Release ,  "donothing" ,  "sigill" ) ; 
82+ } 
83+ 
84+ #[ test]  
85+ #[ cfg_attr( miri,  ignore) ]  
86+ fn  test_crash_tracking_bin_sigbus ( )  { 
87+     // For now, do the base test (donothing).  For future we should probably also test chaining. 
88+     test_crash_tracking_bin ( BuildProfile :: Release ,  "donothing" ,  "sigbus" ) ; 
89+ } 
90+ 
91+ #[ test]  
92+ #[ cfg_attr( miri,  ignore) ]  
93+ fn  test_crash_tracking_bin_sigsegv ( )  { 
94+     // For now, do the base test (donothing).  For future we should probably also test chaining. 
95+     test_crash_tracking_bin ( BuildProfile :: Release ,  "donothing" ,  "sigsegv" ) ; 
96+ } 
97+ 
98+ fn  test_crash_tracking_bin ( 
99+     crash_tracking_receiver_profile :  BuildProfile , 
100+     mode :  & str , 
101+     crash_typ :  & str , 
102+ )  { 
70103    let  ( crashtracker_bin,  crashtracker_receiver)  =
71104        setup_crashtracking_crates ( crash_tracking_receiver_profile) ; 
72105    let  fixtures = setup_test_fixtures ( & [ & crashtracker_receiver,  & crashtracker_bin] ) ; 
@@ -76,13 +109,23 @@ fn test_crash_tracking_bin(crash_tracking_receiver_profile: BuildProfile, mode:
76109        . arg ( fixtures. artifacts [ & crashtracker_receiver] . as_os_str ( ) ) 
77110        . arg ( & fixtures. output_dir ) 
78111        . arg ( mode) 
112+         . arg ( crash_typ) 
79113        . spawn ( ) 
80114        . unwrap ( ) ; 
81115    let  exit_status = bin_tests:: timeit!( "exit after signal" ,  { 
82116        eprintln!( "Waiting for exit" ) ; 
83117        p. wait( ) . unwrap( ) 
84118    } ) ; 
85-     assert ! ( !exit_status. success( ) ) ; 
119+ 
120+     // When we raise SIGSEGV/SIGBUS, the chained handler doesn't kill the program 
121+     // Presumably because continuing after raise is allowed. 
122+     // Not sure why sigill behaves differently?? 
123+     // TODO: figure that out. 
124+     match  crash_typ { 
125+         "null_deref"  | "sigabrt"  | "sigill"  => assert ! ( !exit_status. success( ) ) , 
126+         "sigbus"  | "sigsegv"  => ( ) , 
127+         _ => unreachable ! ( "{crash_typ} shouldn't happen" ) , 
128+     } 
86129
87130    let  stderr_path = format ! ( "{0}/out.stderr" ,  fixtures. output_dir. display( ) ) ; 
88131    let  stderr = fs:: read ( stderr_path) 
@@ -120,32 +163,12 @@ fn test_crash_tracking_bin(crash_tracking_receiver_profile: BuildProfile, mode:
120163        crash_payload[ "counters" ] , 
121164    ) ; 
122165    let  sig_info = & crash_payload[ "sig_info" ] ; 
123-     // On every platform other than OSX ARM, the si_code is 1: SEGV_MAPERR 
124-     // On OSX ARM, its 2: SEGV_ACCERR 
125-     assert ! ( 
126-         * sig_info
127-             == serde_json:: json!( { 
128-                 "si_addr" :  "0x0000000000000000" , 
129-                 "si_code" :  1 , 
130-                 "si_code_human_readable" :  "UNKNOWN" , 
131-                 "si_signo" :  11 , 
132-                 "si_signo_human_readable" :  "SIGSEGV" , 
133-             } ) 
134-             || * sig_info
135-                 == serde_json:: json!( { 
136-                     "si_addr" :  "0x0000000000000000" , 
137-                     "si_code" :  2 , 
138-                     "si_code_human_readable" :  "UNKNOWN" , 
139-                     "si_signo" :  11 , 
140-                     "si_signo_human_readable" :  "SIGSEGV" , 
141-                 } ) , 
142-         "Unexpected sig_info: {sig_info}" 
143-     ) ; 
166+     assert_siginfo_message ( sig_info,  crash_typ) ; 
144167
145168    let  crash_telemetry = fs:: read ( fixtures. crash_telemetry_path ) 
146169        . context ( "reading crashtracker telemetry payload" ) 
147170        . unwrap ( ) ; 
148-     assert_telemetry_message ( & crash_telemetry) ; 
171+     assert_telemetry_message ( & crash_telemetry,  crash_typ ) ; 
149172
150173    // Crashtracking signal handler chaining tests, as well as other tests, might only be able to 
151174    // influence system state after the main application has crashed, and has therefore lost the 
@@ -161,7 +184,46 @@ fn test_crash_tracking_bin(crash_tracking_receiver_profile: BuildProfile, mode:
161184    } 
162185} 
163186
164- fn  assert_telemetry_message ( crash_telemetry :  & [ u8 ] )  { 
187+ fn  assert_siginfo_message ( sig_info :  & Value ,  crash_typ :  & str )  { 
188+     match  crash_typ { 
189+         "sigabrt"  => { 
190+             assert_eq ! ( sig_info[ "si_code_human_readable" ] ,  "UNKNOWN" ) ; 
191+             assert_eq ! ( sig_info[ "si_signo" ] ,  libc:: SIGABRT ) ; 
192+             assert_eq ! ( sig_info[ "si_signo_human_readable" ] ,  "SIGABRT" ) ; 
193+         } 
194+         "sigsegv"  => { 
195+             assert_eq ! ( sig_info[ "si_code_human_readable" ] ,  "UNKNOWN" ) ; 
196+             assert_eq ! ( sig_info[ "si_signo" ] ,  libc:: SIGSEGV ) ; 
197+             assert_eq ! ( sig_info[ "si_signo_human_readable" ] ,  "SIGSEGV" ) ; 
198+         } 
199+         "sigbus"  => { 
200+             assert_eq ! ( sig_info[ "si_code_human_readable" ] ,  "UNKNOWN" ) ; 
201+             assert_eq ! ( sig_info[ "si_signo" ] ,  libc:: SIGBUS ) ; 
202+             assert_eq ! ( sig_info[ "si_signo_human_readable" ] ,  "SIGBUS" ) ; 
203+         } 
204+         "sigill"  => { 
205+             assert_eq ! ( sig_info[ "si_code_human_readable" ] ,  "UNKNOWN" ) ; 
206+             assert_eq ! ( sig_info[ "si_signo" ] ,  libc:: SIGILL ) ; 
207+             assert_eq ! ( sig_info[ "si_signo_human_readable" ] ,  "SIGILL" ) ; 
208+         } 
209+         "null_deref"  =>
210+         // On every platform other than OSX ARM, the si_code is 1: SEGV_MAPERR 
211+         // On OSX ARM, its 2: SEGV_ACCERR 
212+         { 
213+             assert_eq ! ( sig_info[ "si_addr" ] ,  "0x0000000000000000" ) ; 
214+             assert ! ( 
215+                 sig_info[ "si_code" ]  == 2  || sig_info[ "si_code" ]  == 1 , 
216+                 "{sig_info:?}" 
217+             ) ; 
218+             assert_eq ! ( sig_info[ "si_code_human_readable" ] ,  "UNKNOWN" ) ; 
219+             assert_eq ! ( sig_info[ "si_signo" ] ,  libc:: SIGSEGV ) ; 
220+             assert_eq ! ( sig_info[ "si_signo_human_readable" ] ,  "SIGSEGV" ) ; 
221+         } 
222+         _ => panic ! ( "unexpected crash_typ {crash_typ}" ) , 
223+     } 
224+ } 
225+ 
226+ fn  assert_telemetry_message ( crash_telemetry :  & [ u8 ] ,  crash_typ :  & str )  { 
165227    let  telemetry_payload:  serde_json:: Value  =
166228        serde_json:: from_slice :: < serde_json:: Value > ( crash_telemetry) 
167229            . context ( "deserializing crashtracker telemetry payload to json" ) 
@@ -185,8 +247,8 @@ fn assert_telemetry_message(crash_telemetry: &[u8]) {
185247        . split ( ',' ) 
186248        . filter ( |t| !t. starts_with ( "uuid:" ) ) 
187249        . collect :: < std:: collections:: HashSet < _ > > ( ) ; 
188-      // As above, ARM OSX can have a si_code of 2. 
189-     assert ! ( 
250+ 
251+     let  base_expected_tags :  std :: collections :: HashSet < & str >  = 
190252        std:: collections:: HashSet :: from_iter ( [ 
191253            "data_schema_version:1.2" , 
192254            "incomplete:false" , 
@@ -195,27 +257,51 @@ fn assert_telemetry_message(crash_telemetry: &[u8]) {
195257            "profiler_inactive:0" , 
196258            "profiler_serializing:0" , 
197259            "profiler_unwinding:0" , 
198-             "si_addr:0x0000000000000000" , 
199-             "si_code_human_readable:UNKNOWN" , 
200-             "si_code:1" , 
201-             "si_signo_human_readable:SIGSEGV" , 
202-             "si_signo:11" , 
203-         ] )  == tags
204-             || std:: collections:: HashSet :: from_iter( [ 
205-                 "data_schema_version:1.2" , 
206-                 "incomplete:false" , 
207-                 "is_crash:true" , 
208-                 "profiler_collecting_sample:1" , 
209-                 "profiler_inactive:0" , 
210-                 "profiler_serializing:0" , 
211-                 "profiler_unwinding:0" , 
212-                 "si_addr:0x0000000000000000" , 
213-                 "si_code_human_readable:UNKNOWN" , 
214-                 "si_code:2" , 
215-                 "si_signo_human_readable:SIGSEGV" , 
216-                 "si_signo:11" , 
217-             ] )  == tags
218-     ) ; 
260+         ] ) ; 
261+ 
262+     match  crash_typ { 
263+         "sigabrt"  => { 
264+             assert ! ( base_expected_tags. is_subset( & tags) ,  "{tags:?}" ) ; 
265+             assert ! ( tags. contains( "si_code_human_readable:UNKNOWN" ) ,  "{tags:?}" ) ; 
266+             assert ! ( tags. contains( "si_signo_human_readable:SIGABRT" ) ,  "{tags:?}" ) ; 
267+             assert ! ( tags. contains( "si_signo:6" ) ,  "{tags:?}" ) ; 
268+         } 
269+         "sigbus"  => { 
270+             assert ! ( base_expected_tags. is_subset( & tags) ,  "{tags:?}" ) ; 
271+             assert ! ( tags. contains( "si_code_human_readable:UNKNOWN" ) ,  "{tags:?}" ) ; 
272+             assert ! ( tags. contains( "si_signo_human_readable:SIGBUS" ) ,  "{tags:?}" ) ; 
273+             // SIGBUS can be 7 or 10, depending on the os. 
274+             assert ! ( 
275+                 tags. contains( format!( "si_signo:{}" ,  libc:: SIGBUS ) . as_str( ) ) , 
276+                 "{tags:?}" 
277+             ) ; 
278+         } 
279+         "sigill"  => { 
280+             assert ! ( base_expected_tags. is_subset( & tags) ,  "{tags:?}" ) ; 
281+             assert ! ( tags. contains( "si_code_human_readable:UNKNOWN" ) ,  "{tags:?}" ) ; 
282+             assert ! ( tags. contains( "si_signo_human_readable:SIGILL" ) ,  "{tags:?}" ) ; 
283+             assert ! ( tags. contains( "si_signo:4" ) ,  "{tags:?}" ) ; 
284+         } 
285+         "sigsegv"  => { 
286+             assert ! ( base_expected_tags. is_subset( & tags) ,  "{tags:?}" ) ; 
287+             assert ! ( tags. contains( "si_code_human_readable:UNKNOWN" ) ,  "{tags:?}" ) ; 
288+             assert ! ( tags. contains( "si_signo_human_readable:SIGSEGV" ) ,  "{tags:?}" ) ; 
289+             assert ! ( tags. contains( "si_signo:11" ) ,  "{tags:?}" ) ; 
290+         } 
291+         "null_deref"  => { 
292+             assert ! ( base_expected_tags. is_subset( & tags) ,  "{tags:?}" ) ; 
293+             assert ! ( tags. contains( "si_addr:0x0000000000000000" ) ,  "{tags:?}" ) ; 
294+             assert ! ( tags. contains( "si_code_human_readable:UNKNOWN" ) ,  "{tags:?}" ) ; 
295+             assert ! ( tags. contains( "si_signo_human_readable:SIGSEGV" ) ,  "{tags:?}" ) ; 
296+             assert ! ( tags. contains( "si_signo:11" ) ,  "{tags:?}" ) ; 
297+             assert ! ( 
298+                 tags. contains( "si_code:1" )  || tags. contains( "si_code:2" ) , 
299+                 "{tags:?}" 
300+             ) ; 
301+         } 
302+         _ => panic ! ( "{crash_typ}" ) , 
303+     } 
304+ 
219305    assert_eq ! ( telemetry_payload[ "payload" ] [ 0 ] [ "is_sensitive" ] ,  true ) ; 
220306} 
221307
@@ -238,6 +324,7 @@ fn crash_tracking_empty_endpoint() {
238324        . arg ( fixtures. artifacts [ & crashtracker_receiver] . as_os_str ( ) ) 
239325        . arg ( & fixtures. output_dir ) 
240326        . arg ( "donothing" ) 
327+         . arg ( "null_deref" ) 
241328        . env ( 
242329            "DD_TRACE_AGENT_URL" , 
243330            format ! ( "unix://{}" ,  socket_path. display( ) ) , 
@@ -286,7 +373,7 @@ fn crash_tracking_empty_endpoint() {
286373    let  resp = String :: from_utf8_lossy ( & out[ ..total_read] ) ; 
287374    let  pos = resp. find ( "\r \n \r \n " ) . unwrap ( ) ; 
288375    let  body = & resp[ pos + 4 ..] ; 
289-     assert_telemetry_message ( body. as_bytes ( ) ) ; 
376+     assert_telemetry_message ( body. as_bytes ( ) ,   "null_deref" ) ; 
290377} 
291378
292379struct  TestFixtures < ' a >  { 
0 commit comments