From 5fffec17eb37b7e9f03a1e548c9d1738b381fddc Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Tue, 17 Jun 2025 11:30:06 -0400 Subject: [PATCH 1/2] [profiling] Experiment using antithesis assertions --- Cargo.lock | 58 +++++++++++++++++++ datadog-crashtracker-ffi/Cargo.toml | 1 + datadog-profiling-ffi/Cargo.toml | 1 + datadog-profiling-ffi/src/exporter.rs | 14 +++-- .../src/profiles/datatypes.rs | 55 ++++++++++++++---- datadog-profiling-ffi/src/string_storage.rs | 19 ++++++ ddcommon-ffi/Cargo.toml | 1 + ddcommon-ffi/src/utils.rs | 9 +++ 8 files changed, 143 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 31428f6527..d3f3c955d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,6 +114,22 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "antithesis_sdk" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201eba73b76341631014baf9c0018e703af204a1e0f15d7664d8a0947f6be74d" +dependencies = [ + "libc", + "libloading", + "linkme", + "once_cell", + "rand 0.8.5", + "rustc_version_runtime", + "serde", + "serde_json", +] + [[package]] name = "anyhow" version = "1.0.93" @@ -1429,6 +1445,7 @@ dependencies = [ name = "datadog-crashtracker-ffi" version = "19.0.0" dependencies = [ + "antithesis_sdk", "anyhow", "build_common", "datadog-crashtracker", @@ -1613,6 +1630,7 @@ dependencies = [ name = "datadog-profiling-ffi" version = "19.0.0" dependencies = [ + "antithesis_sdk", "anyhow", "build_common", "data-pipeline-ffi", @@ -1892,6 +1910,7 @@ dependencies = [ name = "ddcommon-ffi" version = "19.0.0" dependencies = [ + "antithesis_sdk", "anyhow", "bolero", "build_common", @@ -3314,6 +3333,26 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linkme" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b1703c00b2a6a70738920544aa51652532cacddfec2e162d2e29eae01e665c" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d55ca5d5a14363da83bf3c33874b8feaa34653e760d5216d7ef9829c88001a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -4540,6 +4579,25 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustc_version_runtime" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd18cd2bae1820af0b6ad5e54f4a51d0f3fcc53b05f845675074efcc7af071d" +dependencies = [ + "rustc_version", + "semver", +] + [[package]] name = "rustix" version = "0.38.39" diff --git a/datadog-crashtracker-ffi/Cargo.toml b/datadog-crashtracker-ffi/Cargo.toml index 96a4e3caf2..70911a427f 100644 --- a/datadog-crashtracker-ffi/Cargo.toml +++ b/datadog-crashtracker-ffi/Cargo.toml @@ -45,6 +45,7 @@ function_name = "0.3.0" libc = "0.2.167" serde_json = "1.0.132" serde = { version = "1.0.214", features = ["derive"] } +antithesis_sdk = "0.2.5" [target.'cfg(windows)'.dependencies] windows = { version = "0.59.0", features = ["Win32_System_Diagnostics_Debug", "Win32_System_ErrorReporting"] } diff --git a/datadog-profiling-ffi/Cargo.toml b/datadog-profiling-ffi/Cargo.toml index 275959d42c..a615ce2bb5 100644 --- a/datadog-profiling-ffi/Cargo.toml +++ b/datadog-profiling-ffi/Cargo.toml @@ -51,3 +51,4 @@ libc = "0.2" serde_json = { version = "1.0" } symbolizer-ffi = { path = "../symbolizer-ffi", optional = true, default-features = false } tokio-util = "0.7.1" +antithesis_sdk = "0.2.5" diff --git a/datadog-profiling-ffi/src/exporter.rs b/datadog-profiling-ffi/src/exporter.rs index f1ff7ce464..cc81dcf31c 100644 --- a/datadog-profiling-ffi/src/exporter.rs +++ b/datadog-profiling-ffi/src/exporter.rs @@ -4,6 +4,7 @@ #![allow(renamed_and_removed_lints)] #![allow(clippy::box_vec)] +use antithesis_sdk::assert_always; use datadog_profiling::exporter; use datadog_profiling::exporter::{ProfileExporter, Request}; use datadog_profiling::internal::EncodedProfile; @@ -176,8 +177,9 @@ pub unsafe extern "C" fn ddog_prof_Exporter_set_timeout( #[no_mangle] pub unsafe extern "C" fn ddog_prof_Exporter_drop(mut exporter: *mut Handle) { // Technically, this function has been designed so if it's double-dropped - // then it's okay, but it's not something that should be relied on. - drop(exporter.take()) + let taken = exporter.take(); + assert_always!(taken.is_ok(), "exporter take() failed"); + drop(taken) } unsafe fn into_vec_files<'a>(slice: Slice<'a, File>) -> Vec> { @@ -272,7 +274,9 @@ unsafe fn parse_json( pub unsafe extern "C" fn ddog_prof_Exporter_Request_drop(mut request: *mut Handle) { // Technically, this function has been designed so if it's double-dropped // then it's okay, but it's not something that should be relied on. - drop(request.take()) + let taken = request.take(); + assert_always!(taken.is_ok(), "request take() failed"); + drop(taken) } /// Sends the request, returning the HttpStatus. @@ -372,7 +376,9 @@ pub unsafe extern "C" fn ddog_CancellationToken_cancel( pub unsafe extern "C" fn ddog_CancellationToken_drop( mut token: *mut Handle, ) { - drop(token.take()) + let taken = token.take(); + assert_always!(taken.is_ok(), "exporter take() failed"); + drop(taken) } #[cfg(test)] diff --git a/datadog-profiling-ffi/src/profiles/datatypes.rs b/datadog-profiling-ffi/src/profiles/datatypes.rs index 4956f1a34c..b2f5c84d62 100644 --- a/datadog-profiling-ffi/src/profiles/datatypes.rs +++ b/datadog-profiling-ffi/src/profiles/datatypes.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::string_storage::{get_inner_string_storage, ManagedStringStorage}; +use antithesis_sdk::prelude::*; use anyhow::Context; use datadog_profiling::api; use datadog_profiling::api::ManagedStringId; @@ -65,7 +66,10 @@ impl From> for ProfileResult { fn from(value: anyhow::Result<()>) -> Self { match value { Ok(_) => Self::Ok(true), - Err(err) => Self::Err(err.into()), + Err(err) => { + assert_unreachable!("ProfileResult error"); + Self::Err(err.into()) + } } } } @@ -90,7 +94,10 @@ impl From> for SerializeResult { fn from(value: anyhow::Result) -> Self { match value { Ok(e) => Self::Ok(e.into()), - Err(err) => Self::Err(err.into()), + Err(err) => { + assert_unreachable!("SerializeResult error"); + Self::Err(err.into()) + } } } } @@ -426,7 +433,10 @@ unsafe fn profile_new( Some(s) => { let string_storage = match get_inner_string_storage(s, true) { Ok(string_storage) => string_storage, - Err(err) => return ProfileNewResult::Err(err.into()), + Err(err) => { + assert_unreachable!("Failed to get inner string storage"); + return ProfileNewResult::Err(err.into()); + } }; internal::Profile::with_string_storage(&types, period, string_storage) } @@ -440,6 +450,7 @@ unsafe fn profile_new( /// made by this module, which has not previously been dropped. #[no_mangle] pub unsafe extern "C" fn ddog_prof_Profile_drop(profile: *mut Profile) { + assert_always!(!profile.is_null(), "profile pointer was null"); // Technically, this function has been designed so if it's double-dropped // then it's okay, but it's not something that should be relied on. if !profile.is_null() { @@ -499,6 +510,9 @@ pub unsafe extern "C" fn ddog_prof_Profile_add( profile.add_sample(sample.try_into()?, timestamp) } })() + .inspect_err(|_| { + assert_unreachable!("ddog_prof_Profile_add failed"); + }) .context("ddog_prof_Profile_add failed") .into() } @@ -507,10 +521,16 @@ pub(crate) unsafe fn profile_ptr_to_inner<'a>( profile_ptr: *mut Profile, ) -> anyhow::Result<&'a mut internal::Profile> { match profile_ptr.as_mut() { - None => anyhow::bail!("profile pointer was null"), + None => { + assert_unreachable!("profile pointer was null"); + anyhow::bail!("profile pointer was null") + } Some(inner_ptr) => match inner_ptr.inner.as_mut() { Some(profile) => Ok(profile), - None => anyhow::bail!("profile's inner pointer was null (indicates use-after-free)"), + None => { + assert_unreachable!("profile's inner pointer was null"); + anyhow::bail!("profile's inner pointer was null (indicates use-after-free)") + } }, } } @@ -543,6 +563,9 @@ pub unsafe extern "C" fn ddog_prof_Profile_set_endpoint( let endpoint = endpoint.to_utf8_lossy(); profile.add_endpoint(local_root_span_id, endpoint) })() + .inspect_err(|_| { + assert_unreachable!("ddog_prof_Profile_set_endpoint failed"); + }) .context("ddog_prof_Profile_set_endpoint failed") .into() } @@ -569,6 +592,9 @@ pub unsafe extern "C" fn ddog_prof_Profile_add_endpoint_count( let endpoint = endpoint.to_utf8_lossy(); profile.add_endpoint_count(endpoint, value) })() + .inspect_err(|_| { + assert_unreachable!("ddog_prof_Profile_add_endpoint_count failed"); + }) .context("ddog_prof_Profile_set_endpoint failed") .into() } @@ -620,6 +646,9 @@ pub unsafe extern "C" fn ddog_prof_Profile_add_upscaling_rule_poisson( upscaling_info, ) })() + .inspect_err(|_| { + assert_unreachable!("ddog_prof_Profile_add_endpoint_count failed"); + }) .context("ddog_prof_Profile_add_upscaling_rule_proportional failed") .into() } @@ -680,12 +709,16 @@ unsafe fn add_upscaling_rule( ) -> anyhow::Result<()> { let label_name_n = label_name.to_utf8_lossy(); let label_value_n = label_value.to_utf8_lossy(); - profile.add_upscaling_rule( - offset_values.as_slice(), - label_name_n.as_ref(), - label_value_n.as_ref(), - upscaling_info, - ) + profile + .add_upscaling_rule( + offset_values.as_slice(), + label_name_n.as_ref(), + label_value_n.as_ref(), + upscaling_info, + ) + .inspect_err(|_| { + assert_unreachable!("Failed to add upscaling rule"); + }) } /// # Safety diff --git a/datadog-profiling-ffi/src/string_storage.rs b/datadog-profiling-ffi/src/string_storage.rs index b57ea4ef25..8bd561cfac 100644 --- a/datadog-profiling-ffi/src/string_storage.rs +++ b/datadog-profiling-ffi/src/string_storage.rs @@ -1,6 +1,7 @@ // Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ // SPDX-License-Identifier: Apache-2.0 +use antithesis_sdk::assert_unreachable; use anyhow::Context; use datadog_profiling::api::ManagedStringId; use datadog_profiling::collections::string_storage::ManagedStringStorage as InternalManagedStringStorage; @@ -82,6 +83,9 @@ pub unsafe extern "C" fn ddog_prof_ManagedStringStorage_intern( anyhow::Ok(ManagedStringId::new(string_id)) })() + .inspect_err(|_| { + assert_unreachable!("ddog_prof_ManagedStringStorage_intern failed"); + }) .context("ddog_prof_ManagedStringStorage_intern failed") .into() } @@ -130,6 +134,9 @@ pub unsafe extern "C" fn ddog_prof_ManagedStringStorage_intern_all( anyhow::Ok(()) })() + .inspect_err(|_| { + assert_unreachable!("ddog_prof_ManagedStringStorage_intern_all failed"); + }) .context("ddog_prof_ManagedStringStorage_intern failed"); match result { @@ -157,6 +164,9 @@ pub unsafe extern "C" fn ddog_prof_ManagedStringStorage_unintern( write_locked_storage.unintern(non_empty_string_id) })() + .inspect_err(|_| { + assert_unreachable!("ddog_prof_ManagedStringStorage_unintern failed"); + }) .context("ddog_prof_ManagedStringStorage_unintern failed"); match result { @@ -184,6 +194,9 @@ pub unsafe extern "C" fn ddog_prof_ManagedStringStorage_unintern_all( anyhow::Ok(()) })() + .inspect_err(|_| { + assert_unreachable!("ddog_prof_ManagedStringStorage_unintern_all failed"); + }) .context("ddog_prof_ManagedStringStorage_unintern failed"); match result { @@ -215,6 +228,9 @@ pub unsafe extern "C" fn ddog_prof_ManagedStringStorage_get_string( anyhow::Ok(string) })() + .inspect_err(|_| { + assert_unreachable!("ddog_prof_ManagedStringStorage_get_string failed"); + }) .context("ddog_prof_ManagedStringStorage_get_string failed") .into() } @@ -234,6 +250,9 @@ pub unsafe extern "C" fn ddog_prof_ManagedStringStorage_advance_gen( anyhow::Ok(()) })() + .inspect_err(|_| { + assert_unreachable!("ddog_prof_ManagedStringStorage_advance_gen failed"); + }) .context("ddog_prof_ManagedStringStorage_advance_gen failed"); match result { diff --git a/ddcommon-ffi/Cargo.toml b/ddcommon-ffi/Cargo.toml index a6b909af5f..245cae7a4d 100644 --- a/ddcommon-ffi/Cargo.toml +++ b/ddcommon-ffi/Cargo.toml @@ -19,6 +19,7 @@ cbindgen = ["build_common/cbindgen"] build_common = { path = "../build-common" } [dependencies] +antithesis_sdk = "0.2.5" anyhow = "1.0" chrono = { version = "0.4.38", features = ["std"] } crossbeam-queue = "0.3.11" diff --git a/ddcommon-ffi/src/utils.rs b/ddcommon-ffi/src/utils.rs index 584ed34d75..84f0b87c96 100644 --- a/ddcommon-ffi/src/utils.rs +++ b/ddcommon-ffi/src/utils.rs @@ -7,8 +7,12 @@ #[macro_export] macro_rules! wrap_with_ffi_result { ($body:block) => {{ + use antithesis_sdk::prelude::*; use anyhow::Context; (|| $body)() + .inspect_err(|err| { + assert_unreachable!("FFI function failed"); + }) .context(concat!(function_name!(), " failed")) .into() }}; @@ -19,11 +23,16 @@ macro_rules! wrap_with_ffi_result { #[macro_export] macro_rules! wrap_with_void_ffi_result { ($body:block) => {{ + use antithesis_sdk::prelude::*; use anyhow::Context; + (|| { $body; anyhow::Ok(()) })() + .inspect_err(|err| { + assert_unreachable!("FFI function failed"); + }) .context(concat!(function_name!(), " failed")) .into() }}; From 7b76664bd299e721cdca41794050fec758959da7 Mon Sep 17 00:00:00 2001 From: Daniel Schwartz-Narbonne Date: Wed, 18 Jun 2025 15:01:13 -0400 Subject: [PATCH 2/2] Apply Paul's patch --- build-profiling-ffi.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/build-profiling-ffi.sh b/build-profiling-ffi.sh index d9f30f16d5..90528e17b5 100755 --- a/build-profiling-ffi.sh +++ b/build-profiling-ffi.sh @@ -103,7 +103,7 @@ case "$target" in ;; "x86_64-unknown-linux-gnu"|"aarch64-unknown-linux-gnu") - expected_native_static_libs=" -ldl -lrt -lpthread -lgcc_s -lc -lm -lrt -lpthread -lutil -ldl -lutil" + expected_native_static_libs=" -ldl -lrt -lpthread -lgcc_s -lc -lm -lrt -lpthread -lutil -ldl -lutil -lvoidstar" native_static_libs=" -ldl -lrt -lpthread -lc -lm -lrt -lpthread -lutil -ldl -lutil" symbolizer=1 ;; @@ -166,6 +166,16 @@ FEATURES=$(IFS=, ; echo "${FEATURES[*]}") echo "Building for features: $FEATURES" # build inside the crate to use the config.toml file +export PATH_TO_LIBVOIDSTAR=/usr/lib/libvoidstar.so +export LD_LIBRARY_PATH=${PATH_TO_LIBVOIDSTAR} +export RUSTFLAGS=" \ + -Ccodegen-units=1 \ + -Cpasses=sancov-module \ + -Cllvm-args=-sanitizer-coverage-level=3 \ + -Cllvm-args=-sanitizer-coverage-trace-pc-guard \ + -Clink-args=-Wl,--build-id \ + -L${PATH_TO_LIBVOIDSTAR} \ + -lvoidstar" ( cd datadog-profiling-ffi && DESTDIR="$destdir" cargo rustc --features $FEATURES --release --target "${target}" --crate-type cdylib && DESTDIR="$destdir" cargo rustc --features $FEATURES --release --target "${target}" --crate-type staticlib) # Remove _ffi suffix when copying