diff --git a/ddprof-lib/src/main/cpp/stackWalker.cpp b/ddprof-lib/src/main/cpp/stackWalker.cpp index 5d293f7ca..f009a0bfd 100644 --- a/ddprof-lib/src/main/cpp/stackWalker.cpp +++ b/ddprof-lib/src/main/cpp/stackWalker.cpp @@ -655,6 +655,10 @@ __attribute__((no_sanitize("address"))) int StackWalker::walkVM(void* ucontext, if (vm_thread != NULL) vm_thread->exception() = saved_exception; + // Drop unknown leaf frame - it provides no useful information and breaks + // aggregation by lumping unrelated samples under a single "unknown" entry + depth = StackWalkValidation::dropUnknownLeaf(frames, depth); + if (truncated) { if (depth > max_depth) { *truncated = true; diff --git a/ddprof-lib/src/main/cpp/stackWalker.h b/ddprof-lib/src/main/cpp/stackWalker.h index f0f1d855e..c365b8c8c 100644 --- a/ddprof-lib/src/main/cpp/stackWalker.h +++ b/ddprof-lib/src/main/cpp/stackWalker.h @@ -8,6 +8,7 @@ #define _STACKWALKER_H #include +#include #include "arguments.h" #include "event.h" #include "vmEntry.h" @@ -49,6 +50,18 @@ namespace StackWalkValidation { static inline bool sameStack(void* hi, void* lo) { return (uintptr_t)hi - (uintptr_t)lo < SAME_STACK_DISTANCE; } + + // Drop unknown leaf frame (method_id == NULL at index 0). + // Returns the new depth after removal. + static inline int dropUnknownLeaf(ASGCT_CallFrame* frames, int depth) { + if (depth > 0 && frames[0].method_id == NULL) { + depth--; + if (depth > 0) { + memmove(frames, frames + 1, depth * sizeof(frames[0])); + } + } + return depth; + } } class StackWalker { diff --git a/ddprof-lib/src/test/cpp/stackWalker_ut.cpp b/ddprof-lib/src/test/cpp/stackWalker_ut.cpp new file mode 100644 index 000000000..7017c8092 --- /dev/null +++ b/ddprof-lib/src/test/cpp/stackWalker_ut.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2026, Datadog, Inc + */ + +#include +#include "../../main/cpp/stackWalker.h" +#include "../../main/cpp/gtest_crash_handler.h" + +static constexpr char STACKWALKER_TEST_NAME[] = "StackWalkerTest"; + +class StackWalkerTest : public ::testing::Test { +protected: + void SetUp() override { + installGtestCrashHandler(); + } + + void TearDown() override { + restoreDefaultSignalHandlers(); + } + + // Helper to create a frame with a non-NULL method_id + static ASGCT_CallFrame knownFrame(int id) { + ASGCT_CallFrame f = {}; + f.bci = 0; + f.method_id = (jmethodID)(uintptr_t)(id + 1); // non-NULL + return f; + } + + // Helper to create a frame with NULL method_id (unknown) + static ASGCT_CallFrame unknownFrame() { + ASGCT_CallFrame f = {}; + f.bci = 0; + f.method_id = NULL; + return f; + } +}; + +TEST_F(StackWalkerTest, dropUnknownLeaf_empty_trace) { + ASGCT_CallFrame frames[1]; + int depth = StackWalkValidation::dropUnknownLeaf(frames, 0); + EXPECT_EQ(0, depth); +} + +TEST_F(StackWalkerTest, dropUnknownLeaf_single_unknown_frame) { + ASGCT_CallFrame frames[1] = { unknownFrame() }; + int depth = StackWalkValidation::dropUnknownLeaf(frames, 1); + EXPECT_EQ(0, depth); +} + +TEST_F(StackWalkerTest, dropUnknownLeaf_single_known_frame) { + ASGCT_CallFrame frames[1] = { knownFrame(1) }; + int depth = StackWalkValidation::dropUnknownLeaf(frames, 1); + EXPECT_EQ(1, depth); + EXPECT_NE(nullptr, frames[0].method_id); +} + +TEST_F(StackWalkerTest, dropUnknownLeaf_unknown_leaf_with_known_callers) { + // frames[0] is the leaf (top of stack), frames[1..2] are callers + ASGCT_CallFrame frames[3] = { unknownFrame(), knownFrame(1), knownFrame(2) }; + int depth = StackWalkValidation::dropUnknownLeaf(frames, 3); + EXPECT_EQ(2, depth); + // The former frames[1] and frames[2] should now be at [0] and [1] + EXPECT_EQ((jmethodID)(uintptr_t)2, frames[0].method_id); + EXPECT_EQ((jmethodID)(uintptr_t)3, frames[1].method_id); +} + +TEST_F(StackWalkerTest, dropUnknownLeaf_known_leaf_not_dropped) { + ASGCT_CallFrame frames[3] = { knownFrame(1), knownFrame(2), knownFrame(3) }; + int depth = StackWalkValidation::dropUnknownLeaf(frames, 3); + EXPECT_EQ(3, depth); + EXPECT_EQ((jmethodID)(uintptr_t)2, frames[0].method_id); + EXPECT_EQ((jmethodID)(uintptr_t)3, frames[1].method_id); + EXPECT_EQ((jmethodID)(uintptr_t)4, frames[2].method_id); +} + +TEST_F(StackWalkerTest, dropUnknownLeaf_unknown_non_leaf_not_dropped) { + // Only the leaf (index 0) should be checked — unknown at other positions stays + ASGCT_CallFrame frames[3] = { knownFrame(1), unknownFrame(), knownFrame(2) }; + int depth = StackWalkValidation::dropUnknownLeaf(frames, 3); + EXPECT_EQ(3, depth); + EXPECT_NE(nullptr, frames[0].method_id); + EXPECT_EQ(nullptr, frames[1].method_id); + EXPECT_NE(nullptr, frames[2].method_id); +}