Skip to content

Commit b514ca2

Browse files
authored
Merge branch 'main' into anais/update-test-agent
2 parents d528fe3 + dd71a87 commit b514ca2

13 files changed

Lines changed: 151 additions & 43 deletions

File tree

.github/workflows/release-proposal-dispatch.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ jobs:
116116
contents: write
117117
needs: check-membership
118118
runs-on: ubuntu-latest
119+
env:
120+
RUSTUP_TOOLCHAIN: 1.92.0
119121
steps:
120122
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
121123
with:
@@ -135,7 +137,7 @@ jobs:
135137
run: ln -sf ~/.rustup/toolchains/${{ steps.nightly-version.outputs.version }}-x86_64-unknown-linux-gnu ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu
136138
- uses: dtolnay/rust-toolchain@stable
137139
with:
138-
toolchain: 1.92.0
140+
toolchain: ${{ env.RUSTUP_TOOLCHAIN }}
139141
- uses: taiki-e/cache-cargo-install-action@7447f04c51f2ba27ca35e7f1e28fab848c5b3ba7 # 2.3.1
140142
with:
141143
tool: cargo-public-api@0.50.2

bin_tests/tests/crashtracker_bin_test.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ use bin_tests::{
2121
ArtifactsBuild, BuildProfile,
2222
};
2323
use libdd_crashtracker::{
24-
default_max_threads, CrashtrackerConfiguration, Metadata, SiCodes, SigInfo, SignalNames,
25-
StacktraceCollection,
24+
CrashtrackerConfiguration, Metadata, SiCodes, SigInfo, SignalNames, StacktraceCollection,
2625
};
2726
use serde_json::Value;
2827

@@ -313,7 +312,7 @@ fn test_crash_tracking_multi_thread_collection() {
313312
#[cfg(target_os = "linux")]
314313
#[cfg_attr(miri, ignore)]
315314
fn test_crash_tracking_thread_limit() {
316-
const THREAD_COUNT: usize = default_max_threads();
315+
const THREAD_COUNT: usize = libdd_crashtracker::default_max_threads();
317316

318317
let config = CrashTestConfig::new(
319318
BuildProfile::Release,

libdd-common/src/entity_id/unix/container_id.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ use std::sync::LazyLock;
1111

1212
const UUID_SOURCE: &str =
1313
r"[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}";
14+
/// PCF / Garden container UUID source: 8-4-4-4-4 hex (28 chars).
15+
/// Distinct from `UUID_SOURCE` (8-4-4-4-12) because the last group is 4 hex.
16+
const PCF_UUID_SOURCE: &str = r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}";
1417
const CONTAINER_SOURCE: &str = r"[0-9a-f]{64}";
1518
const TASK_SOURCE: &str = r"[0-9a-f]{32}-\d+";
1619

@@ -22,7 +25,7 @@ pub(crate) static LINE_REGEX: LazyLock<Regex> = LazyLock::new(|| {
2225
pub(crate) static CONTAINER_REGEX: LazyLock<Regex> = LazyLock::new(|| {
2326
#[allow(clippy::unwrap_used)]
2427
Regex::new(&format!(
25-
r"({UUID_SOURCE}|{CONTAINER_SOURCE}|{TASK_SOURCE})(?:\.scope(?:/[^/ \t]+)?)? *$"
28+
r"({UUID_SOURCE}|{PCF_UUID_SOURCE}|{CONTAINER_SOURCE}|{TASK_SOURCE})(?:\.scope(?:/[^/ \t]+)?)? *$"
2629
))
2730
.unwrap()
2831
});
@@ -92,6 +95,17 @@ mod tests {
9295
// invalid hex
9396
"13:name=systemd:/docker/3726184226f5d3147g25fdeab5b60097e378e8a720503a5e19ecfdf29f869860"
9497
=> None,
98+
// PCF Garden 8-4-4-4-4 UUID
99+
"1:name=systemd:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1"
100+
=> Some("6f265890-5165-7fab-6b52-18d1"),
101+
"10:freezer:/garden/6f265890-5165-7fab-6b52-18d1"
102+
=> Some("6f265890-5165-7fab-6b52-18d1"),
103+
// Regression guard: 8-4-4-4-12 standard UUID must NOT be truncated to 28 chars
104+
"1:name=systemd:/uuid/5a081c13-b8cf-4801-b427-f4601742204d"
105+
=> Some("5a081c13-b8cf-4801-b427-f4601742204d"),
106+
// First group only 7 chars -> no match
107+
"1:name=systemd:/garden/6f26589-5165-7fab-6b52-18d1"
108+
=> None,
95109
};
96110
for (line, &expected_result) in test_lines.iter() {
97111
assert_eq!(
@@ -118,6 +132,7 @@ mod tests {
118132
"cgroup.fargate" => Some("432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da"),
119133
// parse a Fargate 1.4+ container ID
120134
"cgroup.fargate.1.4" => Some("8cd79a803caf4d2aa945152e934a5c00-1053176469"),
135+
"cgroup.pcf" => Some("6f265890-5165-7fab-6b52-18d1"),
121136

122137
// Whitespace around the matching ID is permitted so long as it is matched within a valid cgroup line.
123138
// parse a container ID with leading and trailing whitespace

libdd-common/src/lib.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,40 @@ impl<T> RwLockExt<T> for RwLock<T> {
135135
}
136136
}
137137

138+
/// Extension trait that extracts the value from a `Result` whose error type is uninhabited.
139+
///
140+
/// The signature constrains callers at compile time: the method is only available when the
141+
/// error type is [`core::convert::Infallible`]. No panics — the compiler proves the `Err`
142+
/// arm unreachable from the type.
143+
///
144+
/// # Examples
145+
///
146+
/// ```
147+
/// use libdd_common::ResultInfallibleExt;
148+
/// use std::convert::Infallible;
149+
///
150+
/// let result: Result<i32, Infallible> = Ok(42);
151+
/// assert_eq!(result.unwrap_infallible(), 42);
152+
/// ```
153+
pub trait ResultInfallibleExt<T>: sealed::Sealed {
154+
fn unwrap_infallible(self) -> T;
155+
}
156+
157+
impl<T> ResultInfallibleExt<T> for Result<T, core::convert::Infallible> {
158+
#[inline(always)]
159+
fn unwrap_infallible(self) -> T {
160+
match self {
161+
Ok(value) => value,
162+
Err(never) => match never {},
163+
}
164+
}
165+
}
166+
167+
mod sealed {
168+
pub trait Sealed {}
169+
impl<T> Sealed for Result<T, core::convert::Infallible> {}
170+
}
171+
138172
pub mod header {
139173
#![allow(clippy::declare_interior_mutable_const)]
140174
use http::{header::HeaderName, HeaderValue};

libdd-common/tests/cgroup.pcf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
12:rdma:/
2+
11:net_cls,net_prio:/garden/6f265890-5165-7fab-6b52-18d1
3+
10:freezer:/garden/6f265890-5165-7fab-6b52-18d1
4+
9:devices:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1
5+
8:blkio:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1
6+
7:pids:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1
7+
6:memory:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1
8+
5:cpuset:/garden/6f265890-5165-7fab-6b52-18d1
9+
4:cpu,cpuacct:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1
10+
3:perf_event:/garden/6f265890-5165-7fab-6b52-18d1
11+
2:hugetlb:/garden/6f265890-5165-7fab-6b52-18d1
12+
1:name=systemd:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1

libdd-crashtracker/src/receiver/receive_report.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use crate::{
55
crash_info::{
66
CrashInfo, CrashInfoBuilder, ErrorKind, SigInfo, Span, StackFrame, TelemetryCrashUploader,
7-
Threads, Ucontext,
7+
Ucontext,
88
},
99
runtime_callback::RuntimeStack,
1010
shared::constants::*,
@@ -560,7 +560,7 @@ fn collect_and_add_thread_contexts(
560560
crashing_tid: Option<u32>,
561561
budget: Duration,
562562
) -> anyhow::Result<()> {
563-
use crate::crash_info::ThreadData;
563+
use crate::crash_info::{ThreadData, Threads};
564564
use crate::receiver::ptrace_collector::stream_thread_contexts;
565565

566566
let crashing_tid = crashing_tid.unwrap_or(0) as i32;

libdd-data-pipeline/src/trace_exporter/trace_serializer.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use libdd_trace_utils::msgpack_encoder;
1717
use libdd_trace_utils::span::{v04::Span, TraceData};
1818
use libdd_trace_utils::trace_utils::{self, TracerHeaderTags};
1919
use libdd_trace_utils::tracer_metadata::TracerMetadata;
20-
use libdd_trace_utils::tracer_payload;
20+
use libdd_trace_utils::tracer_payload::{self, TraceEncoding};
2121

2222
/// Minimal capacity of fresh buffers allocated to encode traces, in bytes.
2323
const MIN_BUFFER_CAPACITY: usize = 1024;
@@ -76,9 +76,13 @@ impl TraceSerializer {
7676
) -> Result<tracer_payload::TraceChunks<T>, TraceExporterError> {
7777
match self.output_format {
7878
TraceExporterOutputFormat::V1 => Ok(tracer_payload::TraceChunks::V1(traces)),
79-
format => {
80-
let use_v05_format = matches!(format, TraceExporterOutputFormat::V05);
81-
trace_utils::collect_trace_chunks(traces, use_v05_format).map_err(|e| {
79+
TraceExporterOutputFormat::V04 => {
80+
trace_utils::collect_trace_chunks(traces, TraceEncoding::V04).map_err(|e| {
81+
TraceExporterError::Deserialization(DecodeError::InvalidFormat(e.to_string()))
82+
})
83+
}
84+
TraceExporterOutputFormat::V05 => {
85+
trace_utils::collect_trace_chunks(traces, TraceEncoding::V05).map_err(|e| {
8286
TraceExporterError::Deserialization(DecodeError::InvalidFormat(e.to_string()))
8387
})
8488
}

libdd-trace-utils/src/msgpack_encoder/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@
44
pub mod v04;
55
pub mod v1;
66

7+
use rmp::encode::ValueWriteError;
8+
use std::convert::Infallible;
9+
10+
/// Flatten `ValueWriteError<Infallible>` (uninhabited because both variants wrap
11+
/// `Infallible`) into the bare `Infallible` so callers can use
12+
/// [`libdd_common::ResultInfallibleExt`].
13+
#[inline(always)]
14+
pub(crate) fn flatten_value_write_infallible(err: ValueWriteError<Infallible>) -> Infallible {
15+
match err {
16+
ValueWriteError::InvalidMarkerWrite(never) | ValueWriteError::InvalidDataWrite(never) => {
17+
never
18+
}
19+
}
20+
}
21+
722
/// A writer that counts bytes without storing them, used to compute encoded payload size.
823
pub(crate) struct CountLength(u32);
924

libdd-trace-utils/src/msgpack_encoder/v04/mod.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use crate::span::v04::Span;
55
use crate::span::TraceData;
6+
use libdd_common::ResultInfallibleExt;
67
use rmp::encode::{write_array_len, ByteBuf, RmpWrite, ValueWriteError};
78

89
mod span;
@@ -123,8 +124,9 @@ pub fn to_vec_with_capacity<T: TraceData, S: AsRef<[Span<T>]>>(
123124
capacity: u32,
124125
) -> Vec<u8> {
125126
let mut buf = ByteBuf::with_capacity(capacity as usize);
126-
#[allow(clippy::expect_used)]
127-
to_writer(&mut buf, traces).expect("infallible: the error is std::convert::Infallible");
127+
to_writer(&mut buf, traces)
128+
.map_err(super::flatten_value_write_infallible)
129+
.unwrap_infallible();
128130
buf.into_vec()
129131
}
130132

@@ -158,7 +160,11 @@ pub fn to_vec_with_capacity<T: TraceData, S: AsRef<[Span<T>]>>(
158160
/// ```
159161
pub fn to_encoded_byte_len<T: TraceData, S: AsRef<[Span<T>]>>(traces: &[S]) -> u32 {
160162
let mut counter = super::CountLength(0);
161-
#[allow(clippy::expect_used)]
162-
to_writer(&mut counter, traces).expect("infallible: CountLength never fails");
163+
// `CountLength` impls `std::io::Write` (whose error type is `std::io::Error`, not
164+
// `Infallible`), so we can't statically prove infallibility via `unwrap_infallible`
165+
// the way we do for `ByteBuf`. In practice `CountLength::write*` only ever return
166+
// `Ok`, so the error path here is unreachable today; should `CountLength` ever grow
167+
// a fallible code path, fuzz tests on the msgpack encoded length would catch it.
168+
let _ = to_writer(&mut counter, traces);
163169
counter.0
164170
}

libdd-trace-utils/src/msgpack_encoder/v1/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod span_v04;
66
use crate::span::v04::Span;
77
use crate::span::TraceData;
88
use crate::tracer_metadata::TracerMetadata;
9+
use libdd_common::ResultInfallibleExt;
910
use rmp::encode::{
1011
write_array_len, write_bin, write_map_len, write_sint, write_str, write_uint, write_uint8,
1112
ByteBuf, RmpWrite, ValueWriteError,
@@ -399,7 +400,9 @@ pub fn to_vec_with_capacity<T: TraceData, S: AsRef<[Span<T>]>>(
399400
metadata: &TracerMetadata,
400401
) -> Vec<u8> {
401402
let mut buf = ByteBuf::with_capacity(capacity as usize);
402-
let _ = encode_payload(&mut buf, traces, metadata); // infallible: ByteBuf write never fails
403+
encode_payload(&mut buf, traces, metadata)
404+
.map_err(super::flatten_value_write_infallible)
405+
.unwrap_infallible();
403406
buf.into_vec()
404407
}
405408

@@ -409,7 +412,12 @@ pub fn to_encoded_byte_len<T: TraceData, S: AsRef<[Span<T>]>>(
409412
metadata: &TracerMetadata,
410413
) -> u32 {
411414
let mut counter = super::CountLength(0);
412-
let _ = encode_payload(&mut counter, traces, metadata); // infallible: CountLength write never fails
415+
// `CountLength` impls `std::io::Write` (whose error type is `std::io::Error`, not
416+
// `Infallible`), so we can't statically prove infallibility via `unwrap_infallible`
417+
// the way we do for `ByteBuf`. In practice `CountLength::write*` only ever return
418+
// `Ok`, so the error path here is unreachable today; should `CountLength` ever grow
419+
// a fallible code path, fuzz tests on the msgpack encoded length would catch it.
420+
let _ = encode_payload(&mut counter, traces, metadata);
413421
counter.0
414422
}
415423

0 commit comments

Comments
 (0)