@@ -11,62 +11,95 @@ use std::{fs, path::PathBuf};
11
11
12
12
use anyhow:: Context ;
13
13
use bin_tests:: { build_artifacts, ArtifactType , ArtifactsBuild , BuildProfile } ;
14
+ use serde_json:: Value ;
14
15
15
16
#[ test]
16
17
#[ cfg_attr( miri, ignore) ]
17
18
fn test_crash_tracking_bin_debug ( ) {
18
- test_crash_tracking_bin ( BuildProfile :: Debug , "donothing" ) ;
19
+ test_crash_tracking_bin ( BuildProfile :: Debug , "donothing" , "null_deref" ) ;
19
20
}
20
21
21
22
#[ test]
22
23
#[ cfg_attr( miri, ignore) ]
23
24
fn test_crash_tracking_bin_sigpipe ( ) {
24
- test_crash_tracking_bin ( BuildProfile :: Debug , "sigpipe" ) ;
25
+ test_crash_tracking_bin ( BuildProfile :: Debug , "sigpipe" , "null_deref" ) ;
25
26
}
26
27
27
28
#[ test]
28
29
#[ cfg_attr( miri, ignore) ]
29
30
fn test_crash_tracking_bin_sigchld ( ) {
30
- test_crash_tracking_bin ( BuildProfile :: Debug , "sigchld" ) ;
31
+ test_crash_tracking_bin ( BuildProfile :: Debug , "sigchld" , "null_deref" ) ;
31
32
}
32
33
33
34
#[ test]
34
35
#[ cfg_attr( miri, ignore) ]
35
36
fn 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" ) ;
37
38
}
38
39
39
40
#[ test]
40
41
#[ cfg_attr( miri, ignore) ]
41
42
fn 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" ) ;
43
44
}
44
45
45
46
#[ test]
46
47
#[ cfg_attr( miri, ignore) ]
47
48
fn 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" ) ;
49
50
}
50
51
51
52
#[ test]
52
53
#[ cfg_attr( miri, ignore) ]
53
54
fn 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" ) ;
55
56
}
56
57
57
58
#[ test]
58
59
#[ cfg_attr( miri, ignore) ]
59
60
fn test_crash_tracking_bin_chained ( ) {
60
- test_crash_tracking_bin ( BuildProfile :: Release , "chained" ) ;
61
+ test_crash_tracking_bin ( BuildProfile :: Release , "chained" , "null_deref" ) ;
61
62
}
62
63
63
64
#[ test]
64
65
#[ cfg_attr( miri, ignore) ]
65
66
fn test_crash_tracking_bin_fork ( ) {
66
- test_crash_tracking_bin ( BuildProfile :: Release , "fork" ) ;
67
+ test_crash_tracking_bin ( BuildProfile :: Release , "fork" , "null_deref" ) ;
67
68
}
68
69
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
+ ) {
70
103
let ( crashtracker_bin, crashtracker_receiver) =
71
104
setup_crashtracking_crates ( crash_tracking_receiver_profile) ;
72
105
let fixtures = setup_test_fixtures ( & [ & crashtracker_receiver, & crashtracker_bin] ) ;
@@ -76,13 +109,23 @@ fn test_crash_tracking_bin(crash_tracking_receiver_profile: BuildProfile, mode:
76
109
. arg ( fixtures. artifacts [ & crashtracker_receiver] . as_os_str ( ) )
77
110
. arg ( & fixtures. output_dir )
78
111
. arg ( mode)
112
+ . arg ( crash_typ)
79
113
. spawn ( )
80
114
. unwrap ( ) ;
81
115
let exit_status = bin_tests:: timeit!( "exit after signal" , {
82
116
eprintln!( "Waiting for exit" ) ;
83
117
p. wait( ) . unwrap( )
84
118
} ) ;
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
+ }
86
129
87
130
let stderr_path = format ! ( "{0}/out.stderr" , fixtures. output_dir. display( ) ) ;
88
131
let stderr = fs:: read ( stderr_path)
@@ -120,32 +163,12 @@ fn test_crash_tracking_bin(crash_tracking_receiver_profile: BuildProfile, mode:
120
163
crash_payload[ "counters" ] ,
121
164
) ;
122
165
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) ;
144
167
145
168
let crash_telemetry = fs:: read ( fixtures. crash_telemetry_path )
146
169
. context ( "reading crashtracker telemetry payload" )
147
170
. unwrap ( ) ;
148
- assert_telemetry_message ( & crash_telemetry) ;
171
+ assert_telemetry_message ( & crash_telemetry, crash_typ ) ;
149
172
150
173
// Crashtracking signal handler chaining tests, as well as other tests, might only be able to
151
174
// 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:
161
184
}
162
185
}
163
186
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 ) {
165
227
let telemetry_payload: serde_json:: Value =
166
228
serde_json:: from_slice :: < serde_json:: Value > ( crash_telemetry)
167
229
. context ( "deserializing crashtracker telemetry payload to json" )
@@ -185,8 +247,8 @@ fn assert_telemetry_message(crash_telemetry: &[u8]) {
185
247
. split ( ',' )
186
248
. filter ( |t| !t. starts_with ( "uuid:" ) )
187
249
. 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 > =
190
252
std:: collections:: HashSet :: from_iter ( [
191
253
"data_schema_version:1.2" ,
192
254
"incomplete:false" ,
@@ -195,27 +257,51 @@ fn assert_telemetry_message(crash_telemetry: &[u8]) {
195
257
"profiler_inactive:0" ,
196
258
"profiler_serializing:0" ,
197
259
"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
+
219
305
assert_eq ! ( telemetry_payload[ "payload" ] [ 0 ] [ "is_sensitive" ] , true ) ;
220
306
}
221
307
@@ -238,6 +324,7 @@ fn crash_tracking_empty_endpoint() {
238
324
. arg ( fixtures. artifacts [ & crashtracker_receiver] . as_os_str ( ) )
239
325
. arg ( & fixtures. output_dir )
240
326
. arg ( "donothing" )
327
+ . arg ( "null_deref" )
241
328
. env (
242
329
"DD_TRACE_AGENT_URL" ,
243
330
format ! ( "unix://{}" , socket_path. display( ) ) ,
@@ -286,7 +373,7 @@ fn crash_tracking_empty_endpoint() {
286
373
let resp = String :: from_utf8_lossy ( & out[ ..total_read] ) ;
287
374
let pos = resp. find ( "\r \n \r \n " ) . unwrap ( ) ;
288
375
let body = & resp[ pos + 4 ..] ;
289
- assert_telemetry_message ( body. as_bytes ( ) ) ;
376
+ assert_telemetry_message ( body. as_bytes ( ) , "null_deref" ) ;
290
377
}
291
378
292
379
struct TestFixtures < ' a > {
0 commit comments