Skip to content

Commit 6830707

Browse files
committed
First pass
1 parent c55d7fd commit 6830707

File tree

20 files changed

+2181
-4
lines changed

20 files changed

+2181
-4
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

LICENSE-3rdparty.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
root_name: builder, build_common, tools, datadog-alloc, datadog-crashtracker, ddcommon, ddtelemetry, datadog-ddsketch, datadog-crashtracker-ffi, ddcommon-ffi, datadog-ffe, datadog-ipc, datadog-ipc-macros, tarpc, tarpc-plugins, tinybytes, spawn_worker, datadog-library-config, datadog-library-config-ffi, datadog-live-debugger, datadog-live-debugger-ffi, datadog-profiling, datadog-profiling-protobuf, datadog-profiling-ffi, data-pipeline-ffi, data-pipeline, datadog-trace-protobuf, datadog-trace-stats, datadog-trace-utils, datadog-trace-normalization, dogstatsd-client, datadog-log, datadog-log-ffi, ddsketch-ffi, ddtelemetry-ffi, symbolizer-ffi, datadog-profiling-replayer, datadog-remote-config, datadog-sidecar, datadog-sidecar-macros, datadog-sidecar-ffi, datadog-trace-obfuscation, datadog-tracer-flare, sidecar_mockgen, test_spawn_from_lib
1+
root_name: builder, build_common, tools, datadog-alloc, datadog-crashtracker, ddcommon, ddcommon-ffi, ddtelemetry, datadog-ddsketch, datadog-crashtracker-ffi, datadog-ffe, datadog-ipc, datadog-ipc-macros, tarpc, tarpc-plugins, tinybytes, spawn_worker, datadog-library-config, datadog-library-config-ffi, datadog-live-debugger, datadog-live-debugger-ffi, datadog-profiling, datadog-profiling-protobuf, datadog-profiling-ffi, data-pipeline-ffi, data-pipeline, datadog-trace-protobuf, datadog-trace-stats, datadog-trace-utils, datadog-trace-normalization, dogstatsd-client, datadog-log, datadog-log-ffi, ddsketch-ffi, ddtelemetry-ffi, symbolizer-ffi, datadog-profiling-replayer, datadog-remote-config, datadog-sidecar, datadog-sidecar-macros, datadog-sidecar-ffi, datadog-trace-obfuscation, datadog-tracer-flare, sidecar_mockgen, test_spawn_from_lib
22
third_party_libraries:
33
- package_name: addr2line
44
package_version: 0.24.2

bin_tests/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ current_platform = "0.2.0"
1515
datadog-profiling = { path = "../datadog-profiling" }
1616
datadog-crashtracker = { path = "../datadog-crashtracker" }
1717
ddcommon = { path = "../ddcommon" }
18+
ddcommon-ffi = { path = "../ddcommon-ffi" }
1819
tempfile = "3.3"
1920
serde_json = { version = "1.0" }
2021
strum = { version = "0.26.2", features = ["derive"] }

bin_tests/src/modes/behavior.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ pub fn get_behavior(mode_str: &str) -> Box<dyn Behavior> {
129129
"chained" => Box::new(test_007_chaining::Test),
130130
"fork" => Box::new(test_008_fork::Test),
131131
"prechain_abort" => Box::new(test_009_prechain_with_abort::Test),
132+
"runtime_callback_frame" => Box::new(test_010_runtime_callback_frame::Test),
133+
"runtime_callback_string" => Box::new(test_011_runtime_callback_string::Test),
132134
_ => panic!("Unknown mode: {mode_str}"),
133135
}
134136
}

bin_tests/src/modes/unix/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ pub mod test_006_sigchld_sigstack;
1010
pub mod test_007_chaining;
1111
pub mod test_008_fork;
1212
pub mod test_009_prechain_with_abort;
13+
pub mod test_010_runtime_callback_frame;
14+
pub mod test_011_runtime_callback_string;
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
// This test validates the runtime stack collection callback mechanism using frame-by-frame mode.
5+
// It registers a test callback that provides mock runtime stack frames,
6+
// then crashes and verifies that the runtime frames appear in the crash report.
7+
//
8+
// This test uses frame-by-frame callback to emit structured runtime stack data.
9+
10+
use crate::modes::behavior::Behavior;
11+
use datadog_crashtracker::{
12+
clear_runtime_callback, register_runtime_frame_callback, CrashtrackerConfiguration,
13+
RuntimeStackFrame,
14+
};
15+
use ddcommon_ffi::CharSlice;
16+
use std::path::Path;
17+
18+
pub struct Test;
19+
20+
impl Behavior for Test {
21+
fn setup(
22+
&self,
23+
_output_dir: &Path,
24+
_config: &mut CrashtrackerConfiguration,
25+
) -> anyhow::Result<()> {
26+
Ok(())
27+
}
28+
29+
fn pre(&self, _output_dir: &Path) -> anyhow::Result<()> {
30+
// Ensure clean state
31+
unsafe {
32+
clear_runtime_callback();
33+
}
34+
register_runtime_frame_callback(test_runtime_callback_frame)
35+
.map_err(|e| anyhow::anyhow!("Failed to register runtime callback: {:?}", e))?;
36+
Ok(())
37+
}
38+
39+
fn post(&self, _output_dir: &Path) -> anyhow::Result<()> {
40+
Ok(())
41+
}
42+
}
43+
44+
// Signal-safe test callback that emits mock runtime stack frames
45+
unsafe extern "C" fn test_runtime_callback_frame(
46+
emit_frame: unsafe extern "C" fn(*const RuntimeStackFrame),
47+
) {
48+
static FUNCTION_NAME_1: &str = "test_module.TestClass.runtime_function_1";
49+
static FUNCTION_NAME_2: &str = "my_package.submodule.MyModule.runtime_function_2";
50+
static FUNCTION_NAME_3: &str = "__main__.runtime_main";
51+
static FILE_NAME_1: &str = "script.py";
52+
static FILE_NAME_2: &str = "module.py";
53+
static FILE_NAME_3: &str = "main.py";
54+
55+
let frame1 = RuntimeStackFrame {
56+
function_name: CharSlice::from(FUNCTION_NAME_1),
57+
file_name: CharSlice::from(FILE_NAME_1),
58+
line_number: 42,
59+
column_number: 15,
60+
};
61+
emit_frame(&frame1);
62+
63+
let frame2 = RuntimeStackFrame {
64+
function_name: CharSlice::from(FUNCTION_NAME_2),
65+
file_name: CharSlice::from(FILE_NAME_2),
66+
line_number: 100,
67+
column_number: 8,
68+
};
69+
emit_frame(&frame2);
70+
71+
let frame3 = RuntimeStackFrame {
72+
function_name: CharSlice::from(FUNCTION_NAME_3),
73+
file_name: CharSlice::from(FILE_NAME_3),
74+
line_number: 10,
75+
column_number: 1,
76+
};
77+
emit_frame(&frame3);
78+
}
79+
80+
#[cfg(test)]
81+
mod tests {
82+
use super::*;
83+
use datadog_crashtracker::{clear_runtime_callback, is_runtime_callback_registered};
84+
85+
#[test]
86+
fn test_runtime_callback_frame_registration() {
87+
// Ensure clean state
88+
unsafe {
89+
clear_runtime_callback();
90+
}
91+
92+
assert!(!is_runtime_callback_registered());
93+
94+
let result = register_runtime_frame_callback(test_runtime_callback_frame);
95+
assert!(result.is_ok(), "Frame callback registration should succeed");
96+
assert!(
97+
is_runtime_callback_registered(),
98+
"Callback should be registered"
99+
);
100+
101+
unsafe {
102+
clear_runtime_callback();
103+
}
104+
assert!(
105+
!is_runtime_callback_registered(),
106+
"Callback should be cleared"
107+
);
108+
}
109+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
// This test validates the runtime stack collection callback mechanism using string mode.
5+
// It registers a test callback that provides mock runtime stacktrace string,
6+
// then crashes and verifies that the runtime stacktrace string appear in the crash report.
7+
//
8+
// This test uses stacktrace string callback to emit structured runtime stack data.
9+
10+
use crate::modes::behavior::Behavior;
11+
use datadog_crashtracker::{
12+
clear_runtime_callback, register_runtime_stacktrace_string_callback, CrashtrackerConfiguration,
13+
};
14+
use std::ffi::c_char;
15+
use std::path::Path;
16+
17+
pub struct Test;
18+
19+
impl Behavior for Test {
20+
fn setup(
21+
&self,
22+
_output_dir: &Path,
23+
_config: &mut CrashtrackerConfiguration,
24+
) -> anyhow::Result<()> {
25+
Ok(())
26+
}
27+
28+
fn pre(&self, _output_dir: &Path) -> anyhow::Result<()> {
29+
// Ensure clean state
30+
unsafe {
31+
clear_runtime_callback();
32+
}
33+
register_runtime_stacktrace_string_callback(test_runtime_callback_string)
34+
.map_err(|e| anyhow::anyhow!("Failed to register runtime callback: {:?}", e))?;
35+
Ok(())
36+
}
37+
38+
fn post(&self, _output_dir: &Path) -> anyhow::Result<()> {
39+
Ok(())
40+
}
41+
}
42+
43+
// Signal-safe test callback that emits mock runtime stacktrace string
44+
unsafe extern "C" fn test_runtime_callback_string(
45+
emit_stacktrace_string: unsafe extern "C" fn(*const c_char),
46+
) {
47+
static STACKTRACE_STRING: &[u8] = b"test_stacktrace_string\0";
48+
emit_stacktrace_string(STACKTRACE_STRING.as_ptr() as *const c_char);
49+
}
50+
51+
#[cfg(test)]
52+
mod tests {
53+
use super::*;
54+
use datadog_crashtracker::{clear_runtime_callback, is_runtime_callback_registered};
55+
56+
#[test]
57+
fn test_runtime_callback_string_registration() {
58+
unsafe {
59+
clear_runtime_callback();
60+
}
61+
62+
assert!(!is_runtime_callback_registered());
63+
64+
let result = register_runtime_stacktrace_string_callback(test_runtime_callback_string);
65+
assert!(
66+
result.is_ok(),
67+
"String callback registration should succeed"
68+
);
69+
assert!(
70+
is_runtime_callback_registered(),
71+
"Callback should be registered"
72+
);
73+
74+
unsafe {
75+
clear_runtime_callback();
76+
}
77+
assert!(
78+
!is_runtime_callback_registered(),
79+
"Callback should be cleared"
80+
);
81+
}
82+
}

0 commit comments

Comments
 (0)