Skip to content

Commit 4cdce24

Browse files
authored
Merge branch 'main' into ganeshnj/feat/linux-osx-nuget
2 parents 691d93f + adc183e commit 4cdce24

File tree

7 files changed

+393
-219
lines changed

7 files changed

+393
-219
lines changed

LICENSE-3rdparty.yml

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24363,7 +24363,37 @@ third_party_libraries:
2436324363
limitations under the License.
2436424364

2436524365
- license: BSD-3-Clause
24366-
text: NOT FOUND
24366+
text: |+
24367+
BSD 3-Clause License
24368+
24369+
Copyright (c) 2019, Standard Cognition
24370+
All rights reserved.
24371+
24372+
Redistribution and use in source and binary forms, with or without
24373+
modification, are permitted provided that the following conditions are met:
24374+
24375+
1. Redistributions of source code must retain the above copyright notice, this
24376+
list of conditions and the following disclaimer.
24377+
24378+
2. Redistributions in binary form must reproduce the above copyright notice,
24379+
this list of conditions and the following disclaimer in the documentation
24380+
and/or other materials provided with the distribution.
24381+
24382+
3. Neither the name of the copyright holder nor the names of its
24383+
contributors may be used to endorse or promote products derived from
24384+
this software without specific prior written permission.
24385+
24386+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24387+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24388+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24389+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24390+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24391+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24392+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24393+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24394+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24395+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24396+
2436724397
- package_name: serde
2436824398
package_version: 1.0.214
2436924399
repository: https://github.com/serde-rs/serde
@@ -42298,7 +42328,31 @@ third_party_libraries:
4229842328
license: BSD-2-Clause OR Apache-2.0 OR MIT
4229942329
licenses:
4230042330
- license: BSD-2-Clause
42301-
text: NOT FOUND
42331+
text: |
42332+
Copyright 2019 The Fuchsia Authors.
42333+
42334+
Redistribution and use in source and binary forms, with or without
42335+
modification, are permitted provided that the following conditions are
42336+
met:
42337+
42338+
* Redistributions of source code must retain the above copyright
42339+
notice, this list of conditions and the following disclaimer.
42340+
* Redistributions in binary form must reproduce the above
42341+
copyright notice, this list of conditions and the following disclaimer
42342+
in the documentation and/or other materials provided with the
42343+
distribution.
42344+
42345+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
42346+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42347+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
42348+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
42349+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42350+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42351+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42352+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
42353+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42354+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
42355+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4230242356
- license: Apache-2.0
4230342357
text: |2+
4230442358
Apache License
@@ -42537,7 +42591,31 @@ third_party_libraries:
4253742591
license: BSD-2-Clause OR Apache-2.0 OR MIT
4253842592
licenses:
4253942593
- license: BSD-2-Clause
42540-
text: NOT FOUND
42594+
text: |
42595+
Copyright 2019 The Fuchsia Authors.
42596+
42597+
Redistribution and use in source and binary forms, with or without
42598+
modification, are permitted provided that the following conditions are
42599+
met:
42600+
42601+
* Redistributions of source code must retain the above copyright
42602+
notice, this list of conditions and the following disclaimer.
42603+
* Redistributions in binary form must reproduce the above
42604+
copyright notice, this list of conditions and the following disclaimer
42605+
in the documentation and/or other materials provided with the
42606+
distribution.
42607+
42608+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
42609+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42610+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
42611+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
42612+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42613+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42614+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42615+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
42616+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42617+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
42618+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4254142619
- license: Apache-2.0
4254242620
text: |2+
4254342621
Apache License
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use super::receive_report::{receive_report_from_stream, CrashReportStatus};
5+
use crate::{CrashInfo, CrashtrackerConfiguration, StacktraceCollection};
6+
use anyhow::Context;
7+
use std::time::Duration;
8+
use tokio::{
9+
io::{AsyncBufReadExt, BufReader},
10+
net::UnixListener,
11+
};
12+
13+
/*-----------------------------------------
14+
| Public API |
15+
------------------------------------------*/
16+
17+
pub fn receiver_entry_point_stdin() -> anyhow::Result<()> {
18+
let stream = BufReader::new(tokio::io::stdin());
19+
let rt = tokio::runtime::Builder::new_current_thread()
20+
.enable_all()
21+
.build()?;
22+
rt.block_on(receiver_entry_point(receiver_timeout(), stream))?;
23+
Ok(())
24+
}
25+
26+
pub async fn async_receiver_entry_point_unix_socket(
27+
socket_path: impl AsRef<str>,
28+
one_shot: bool,
29+
) -> anyhow::Result<()> {
30+
let listener = get_unix_socket(socket_path)?;
31+
loop {
32+
let (unix_stream, _) = listener.accept().await?;
33+
let stream = BufReader::new(unix_stream);
34+
let res = receiver_entry_point(receiver_timeout(), stream).await;
35+
36+
if one_shot {
37+
return res;
38+
}
39+
}
40+
}
41+
42+
pub fn receiver_entry_point_unix_socket(socket_path: impl AsRef<str>) -> anyhow::Result<()> {
43+
let rt = tokio::runtime::Builder::new_current_thread()
44+
.enable_all()
45+
.build()?;
46+
rt.block_on(async_receiver_entry_point_unix_socket(socket_path, true))?;
47+
Ok(())
48+
// Dropping the stream closes it, allowing the collector to exit if it was waiting.
49+
}
50+
51+
/*-----------------------------------------
52+
| Helper Functions |
53+
------------------------------------------*/
54+
55+
fn get_unix_socket(socket_path: impl AsRef<str>) -> anyhow::Result<UnixListener> {
56+
fn path_bind(socket_path: impl AsRef<str>) -> anyhow::Result<UnixListener> {
57+
let socket_path = socket_path.as_ref();
58+
if std::fs::metadata(socket_path).is_ok() {
59+
std::fs::remove_file(socket_path).with_context(|| {
60+
format!("could not delete previous socket at {:?}", socket_path)
61+
})?;
62+
}
63+
Ok(UnixListener::bind(socket_path)?)
64+
}
65+
66+
#[cfg(target_os = "linux")]
67+
let unix_listener = if socket_path.as_ref().starts_with(['.', '/']) {
68+
path_bind(socket_path)
69+
} else {
70+
use std::os::linux::net::SocketAddrExt;
71+
std::os::unix::net::SocketAddr::from_abstract_name(socket_path.as_ref())
72+
.and_then(|addr| {
73+
std::os::unix::net::UnixListener::bind_addr(&addr)
74+
.and_then(|listener| {
75+
listener.set_nonblocking(true)?;
76+
Ok(listener)
77+
})
78+
.and_then(UnixListener::from_std)
79+
})
80+
.map_err(anyhow::Error::msg)
81+
};
82+
#[cfg(not(target_os = "linux"))]
83+
let unix_listener = path_bind(socket_path);
84+
unix_listener.context("Could not create the unix socket")
85+
}
86+
87+
/// Receives data from a crash collector via a stream, formats it into
88+
/// `CrashInfo` json, and emits it to the endpoint/file defined in `config`.
89+
///
90+
/// At a high-level, this exists because doing anything in a
91+
/// signal handler is dangerous, so we fork a sidecar to do the stuff we aren't
92+
/// allowed to do in the handler.
93+
///
94+
/// See comments in [crashtracker/lib.rs] for a full architecture
95+
/// description.
96+
async fn receiver_entry_point(
97+
timeout: Duration,
98+
stream: impl AsyncBufReadExt + std::marker::Unpin,
99+
) -> anyhow::Result<()> {
100+
match receive_report_from_stream(timeout, stream).await? {
101+
CrashReportStatus::NoCrash => Ok(()),
102+
CrashReportStatus::CrashReport(config, mut crash_info) => {
103+
resolve_frames(&config, &mut crash_info)?;
104+
crash_info.async_upload_to_endpoint(&config.endpoint).await
105+
}
106+
CrashReportStatus::PartialCrashReport(config, mut crash_info, stdin_state) => {
107+
eprintln!("Failed to fully receive crash. Exit state was: {stdin_state:?}");
108+
resolve_frames(&config, &mut crash_info)?;
109+
crash_info.async_upload_to_endpoint(&config.endpoint).await
110+
}
111+
}
112+
}
113+
114+
fn receiver_timeout() -> Duration {
115+
// https://github.com/DataDog/libdatadog/issues/717
116+
if let Ok(s) = std::env::var("DD_CRASHTRACKER_RECEIVER_TIMEOUT_MS") {
117+
if let Ok(v) = s.parse() {
118+
return Duration::from_millis(v);
119+
}
120+
}
121+
// Default value
122+
Duration::from_millis(4000)
123+
}
124+
125+
fn resolve_frames(
126+
config: &CrashtrackerConfiguration,
127+
crash_info: &mut CrashInfo,
128+
) -> anyhow::Result<()> {
129+
if config.resolve_frames == StacktraceCollection::EnabledWithSymbolsInReceiver {
130+
let proc_info = crash_info
131+
.proc_info
132+
.as_ref()
133+
.context("Unable to resolve frames: No PID specified")?;
134+
crash_info.resolve_names_from_process(proc_info.pid)?;
135+
}
136+
Ok(())
137+
}

crashtracker/src/receiver/mod.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/
2+
// SPDX-License-Identifier: Apache-2.0
3+
#![cfg(unix)]
4+
5+
mod entry_points;
6+
pub use entry_points::{
7+
async_receiver_entry_point_unix_socket, receiver_entry_point_stdin,
8+
receiver_entry_point_unix_socket,
9+
};
10+
mod receive_report;
11+
12+
#[cfg(test)]
13+
mod tests {
14+
use super::receive_report::*;
15+
use crate::shared::constants::*;
16+
use crate::{CrashtrackerConfiguration, SigInfo, StacktraceCollection};
17+
use std::time::Duration;
18+
use tokio::io::{AsyncWriteExt, BufReader};
19+
use tokio::net::UnixStream;
20+
21+
async fn to_socket(
22+
target: &mut tokio::net::UnixStream,
23+
msg: impl AsRef<str>,
24+
) -> anyhow::Result<usize> {
25+
let msg = msg.as_ref();
26+
let n = target.write(format!("{msg}\n").as_bytes()).await?;
27+
target.flush().await?;
28+
Ok(n)
29+
}
30+
31+
async fn send_report(delay: Duration, mut stream: UnixStream) -> anyhow::Result<()> {
32+
let sender = &mut stream;
33+
to_socket(sender, DD_CRASHTRACK_BEGIN_SIGINFO).await?;
34+
to_socket(
35+
sender,
36+
serde_json::to_string(&SigInfo {
37+
signame: Some("SIGSEGV".to_string()),
38+
signum: 11,
39+
faulting_address: None,
40+
})?,
41+
)
42+
.await?;
43+
to_socket(sender, DD_CRASHTRACK_END_SIGINFO).await?;
44+
45+
to_socket(sender, DD_CRASHTRACK_BEGIN_CONFIG).await?;
46+
to_socket(
47+
sender,
48+
serde_json::to_string(&CrashtrackerConfiguration::new(
49+
vec![],
50+
false,
51+
false,
52+
None,
53+
StacktraceCollection::Disabled,
54+
3000,
55+
None,
56+
)?)?,
57+
)
58+
.await?;
59+
to_socket(sender, DD_CRASHTRACK_END_CONFIG).await?;
60+
tokio::time::sleep(delay).await;
61+
to_socket(sender, DD_CRASHTRACK_DONE).await?;
62+
Ok(())
63+
}
64+
65+
#[tokio::test]
66+
#[cfg_attr(miri, ignore)]
67+
async fn test_receive_report_short_timeout() -> anyhow::Result<()> {
68+
let (sender, receiver) = tokio::net::UnixStream::pair()?;
69+
70+
let join_handle1 = tokio::spawn(receive_report_from_stream(
71+
Duration::from_secs(1),
72+
BufReader::new(receiver),
73+
));
74+
let join_handle2 = tokio::spawn(send_report(Duration::from_secs(2), sender));
75+
76+
let crash_report = join_handle1.await??;
77+
assert!(matches!(
78+
crash_report,
79+
CrashReportStatus::PartialCrashReport(_, _, _)
80+
));
81+
let sender_error = join_handle2.await?.unwrap_err().to_string();
82+
assert_eq!(sender_error, "Broken pipe (os error 32)");
83+
Ok(())
84+
}
85+
86+
#[tokio::test]
87+
#[cfg_attr(miri, ignore)]
88+
async fn test_receive_report_long_timeout() -> anyhow::Result<()> {
89+
let (sender, receiver) = tokio::net::UnixStream::pair()?;
90+
91+
let join_handle1 = tokio::spawn(receive_report_from_stream(
92+
Duration::from_secs(2),
93+
BufReader::new(receiver),
94+
));
95+
let join_handle2 = tokio::spawn(send_report(Duration::from_secs(1), sender));
96+
97+
let crash_report = join_handle1.await??;
98+
assert!(matches!(crash_report, CrashReportStatus::CrashReport(_, _)));
99+
join_handle2.await??;
100+
Ok(())
101+
}
102+
}

0 commit comments

Comments
 (0)