Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion ddprof-lib/src/main/cpp/stackWalker.inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,14 @@ inline void fillFrame(ASGCT_CallFrame& frame, FrameTypeId type, int bci, jmethod
// zero-size-symbol cases, not zero-gap adjacency (see
// BinarySearchPicksNextSymbolAtZeroGapBoundary), which is why the adjustment
// is needed.
//
// The adjustment is done on uintptr_t rather than on a char pointer: pc can be
// garbage read from a return-address slot during an optimistic unwind (UBSan
// has caught both nullptr and 0x1 here), and offsetting a pointer to or from
// null is undefined behavior, while unsigned integer wrap-around is not. Such
// an address still matches no library and no FDE either way.
inline const void* attributionPC(const void* pc, bool pc_is_return_address) {
return pc_is_return_address ? (const void*)((const char*)pc - 1) : pc;
return pc_is_return_address ? (const void*)((uintptr_t)pc - 1) : pc;
}

// The walking pc and "was it loaded from a return-address slot?" are one
Expand Down
18 changes: 18 additions & 0 deletions ddprof-lib/src/test/cpp/returnAddressAttribution_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,24 @@ TEST(ReturnAddressAttributionCharacterizationTest, AttributionPcArithmetic) {
EXPECT_EQ((const void*)((const char*)p - 1), attributionPC(p, true));
}

// An optimistic unwind can read garbage such as 0 or 1 from a return-address
// slot and hand it to attributionPC(). Offsetting a pointer to or from null is
// undefined behavior, which the asan config's -fsanitize=pointer-overflow with
// -fno-sanitize-recover=all turns into an abort; outside sanitizer builds this
// pins the wrapped values. The inputs go through volatile so the arithmetic
// runs at run time where UBSan instruments it.
TEST(ReturnAddressAttributionCharacterizationTest, AttributionPcOfGarbageNearNullIsDefined) {
volatile uintptr_t zero = 0;
volatile uintptr_t one = 1;
const void* null_pc = (const void*)zero;
const void* one_pc = (const void*)one;

EXPECT_EQ(null_pc, attributionPC(null_pc, false));
EXPECT_EQ(one_pc, attributionPC(one_pc, false));
EXPECT_EQ((const void*)UINTPTR_MAX, attributionPC(null_pc, true));
EXPECT_EQ(nullptr, attributionPC(one_pc, true));
}

// Supporting characterization (not gating): pins findFrameDesc's and
// binarySearch's row-selection semantics directly, independent of the live
// walker. These do NOT change with the fix -- they document why Test 3's
Expand Down
Loading