Skip to content

Commit 3b5fba7

Browse files
Merge branch 'main' into vianney/data-pipeline/use-send-with-retry
2 parents e8d1c90 + 7a481f8 commit 3b5fba7

File tree

15 files changed

+573
-199
lines changed

15 files changed

+573
-199
lines changed

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ opt-level = "s" # optimize for size
7373
[profile.release.package.datadog-serverless-trace-mini-agent]
7474
strip = true
7575

76+
[profile.bench]
77+
codegen-units = 1
78+
debug = false
79+
incremental = false
80+
opt-level = 3
81+
7682
# https://camshaft.github.io/bolero/library-installation.html
7783
[profile.fuzz]
7884
inherits = "dev"

bin_tests/src/bin/crashtracker_bin_test.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ fn main() -> anyhow::Result<()> {
1313
mod unix {
1414
use anyhow::Context;
1515
use bin_tests::modes::behavior::get_behavior;
16+
use nix::sys::signal::{raise, Signal};
1617
use std::env;
1718
use std::path::Path;
1819

@@ -24,8 +25,9 @@ mod unix {
2425
const TEST_COLLECTOR_TIMEOUT_MS: u32 = 10_000;
2526

2627
#[inline(never)]
27-
unsafe fn deref_ptr(p: *mut u8) {
28+
unsafe fn deref_ptr(p: *mut u8) -> u8 {
2829
*std::hint::black_box(p) = std::hint::black_box(1);
30+
*std::hint::black_box(p)
2931
}
3032

3133
pub fn main() -> anyhow::Result<()> {
@@ -34,6 +36,7 @@ mod unix {
3436
let receiver_binary = args.next().context("Unexpected number of arguments")?;
3537
let output_dir = args.next().context("Unexpected number of arguments")?;
3638
let mode_str = args.next().context("Unexpected number of arguments")?;
39+
let crash_typ = args.next().context("Missing crash type")?;
3740
anyhow::ensure!(args.next().is_none(), "unexpected extra arguments");
3841

3942
let stderr_filename = format!("{output_dir}/out.stderr");
@@ -54,6 +57,7 @@ mod unix {
5457
create_alt_stack: true,
5558
use_alt_stack: true,
5659
resolve_frames: crashtracker::StacktraceCollection::WithoutSymbols,
60+
signals: crashtracker::default_signals(),
5761
endpoint,
5862
timeout_ms: TEST_COLLECTOR_TIMEOUT_MS,
5963
unix_socket_path: Some("".to_string()),
@@ -95,11 +99,18 @@ mod unix {
9599
behavior.post(output_dir)?;
96100

97101
crashtracker::begin_op(crashtracker::OpTypes::ProfilerCollectingSample)?;
98-
unsafe {
99-
deref_ptr(std::ptr::null_mut::<u8>());
102+
match crash_typ.as_str() {
103+
"null_deref" => {
104+
let x = unsafe { deref_ptr(std::ptr::null_mut::<u8>()) };
105+
println!("{x}");
106+
}
107+
"sigabrt" => raise(Signal::SIGABRT)?,
108+
"sigill" => raise(Signal::SIGILL)?,
109+
"sigbus" => raise(Signal::SIGBUS)?,
110+
"sigsegv" => raise(Signal::SIGSEGV)?,
111+
_ => anyhow::bail!("Unexpected crash_typ: {crash_typ}"),
100112
}
101113
crashtracker::end_op(crashtracker::OpTypes::ProfilerCollectingSample)?;
102-
103114
Ok(())
104115
}
105116
}

bin_tests/tests/crashtracker_bin_test.rs

Lines changed: 145 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,62 +11,95 @@ use std::{fs, path::PathBuf};
1111

1212
use anyhow::Context;
1313
use bin_tests::{build_artifacts, ArtifactType, ArtifactsBuild, BuildProfile};
14+
use serde_json::Value;
1415

1516
#[test]
1617
#[cfg_attr(miri, ignore)]
1718
fn 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)]
2324
fn 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)]
2930
fn 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)]
3536
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");
3738
}
3839

3940
#[test]
4041
#[cfg_attr(miri, ignore)]
4142
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");
4344
}
4445

4546
#[test]
4647
#[cfg_attr(miri, ignore)]
4748
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");
4950
}
5051

5152
#[test]
5253
#[cfg_attr(miri, ignore)]
5354
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");
5556
}
5657

5758
#[test]
5859
#[cfg_attr(miri, ignore)]
5960
fn 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)]
6566
fn 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

292379
struct TestFixtures<'a> {

0 commit comments

Comments
 (0)