#include "gwp_asan/stack_trace_compressor.h"
#include <assert.h>
+#include <string.h>
using AllocationMetadata = gwp_asan::AllocationMetadata;
using Error = gwp_asan::Error;
size_t __gwp_asan_get_allocation_trace(
const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,
size_t BufferLen) {
- return gwp_asan::compression::unpack(
+ uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];
+ size_t UnpackedLength = gwp_asan::compression::unpack(
AllocationMeta->AllocationTrace.CompressedTrace,
- AllocationMeta->AllocationTrace.TraceSize, Buffer, BufferLen);
+ AllocationMeta->AllocationTrace.TraceSize, UncompressedBuffer,
+ AllocationMetadata::kMaxTraceLengthToCollect);
+ if (UnpackedLength < BufferLen)
+ BufferLen = UnpackedLength;
+ memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));
+ return UnpackedLength;
}
bool __gwp_asan_is_deallocated(
size_t __gwp_asan_get_deallocation_trace(
const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,
size_t BufferLen) {
- return gwp_asan::compression::unpack(
+ uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];
+ size_t UnpackedLength = gwp_asan::compression::unpack(
AllocationMeta->DeallocationTrace.CompressedTrace,
- AllocationMeta->DeallocationTrace.TraceSize, Buffer, BufferLen);
+ AllocationMeta->DeallocationTrace.TraceSize, UncompressedBuffer,
+ AllocationMetadata::kMaxTraceLengthToCollect);
+ if (UnpackedLength < BufferLen)
+ BufferLen = UnpackedLength;
+ memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));
+ return UnpackedLength;
}
#ifdef __cplusplus
#include <string>
+#include "gwp_asan/common.h"
#include "gwp_asan/crash_handler.h"
#include "gwp_asan/tests/harness.h"
TEST(Backtrace, ExceedsStorableLength) {
gwp_asan::AllocationMetadata Meta;
Meta.AllocationTrace.RecordBacktrace(
- [](uintptr_t * /* TraceBuffer */, size_t /* Size */) -> size_t {
- return SIZE_MAX; // Wow, that's big!
+ [](uintptr_t *TraceBuffer, size_t Size) -> size_t {
+ // Need to inintialise the elements that will be packed.
+ memset(TraceBuffer, 0u, Size * sizeof(*TraceBuffer));
+
+ // Indicate that there were more frames, and we just didn't have enough
+ // room to store them.
+ return Size * 2;
+ });
+ // Retrieve a frame from the collected backtrace, make sure it works E2E.
+ uintptr_t TraceOutput;
+ EXPECT_EQ(gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect,
+ __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));
+}
+
+TEST(Backtrace, ExceedsRetrievableAllocLength) {
+ gwp_asan::AllocationMetadata Meta;
+ constexpr size_t kNumFramesToStore = 3u;
+ Meta.AllocationTrace.RecordBacktrace(
+ [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
+ memset(TraceBuffer, kNumFramesToStore,
+ kNumFramesToStore * sizeof(*TraceBuffer));
+ return kNumFramesToStore;
+ });
+ uintptr_t TraceOutput;
+ // Ask for one element, get told that there's `kNumFramesToStore` available.
+ EXPECT_EQ(kNumFramesToStore,
+ __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));
+}
+
+TEST(Backtrace, ExceedsRetrievableDeallocLength) {
+ gwp_asan::AllocationMetadata Meta;
+ constexpr size_t kNumFramesToStore = 3u;
+ Meta.DeallocationTrace.RecordBacktrace(
+ [](uintptr_t *TraceBuffer, size_t /* Size */) -> size_t {
+ memset(TraceBuffer, kNumFramesToStore,
+ kNumFramesToStore * sizeof(*TraceBuffer));
+ return kNumFramesToStore;
});
uintptr_t TraceOutput;
- EXPECT_EQ(1u, __gwp_asan_get_allocation_trace(&Meta, &TraceOutput, 1));
+ // Ask for one element, get told that there's `kNumFramesToStore` available.
+ EXPECT_EQ(kNumFramesToStore,
+ __gwp_asan_get_deallocation_trace(&Meta, &TraceOutput, 1));
}