215 lines · cpp
1//===-- crash_handler_api.cpp -----------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "gwp_asan/crash_handler.h"10#include "gwp_asan/guarded_pool_allocator.h"11#include "gwp_asan/stack_trace_compressor.h"12#include "gwp_asan/tests/harness.h"13 14using Error = gwp_asan::Error;15using GuardedPoolAllocator = gwp_asan::GuardedPoolAllocator;16using AllocationMetadata = gwp_asan::AllocationMetadata;17using AllocatorState = gwp_asan::AllocatorState;18 19class CrashHandlerAPITest : public ::testing::Test {20public:21 void SetUp() override { setupState(); }22 23protected:24 size_t metadata(uintptr_t Addr, uintptr_t Size, bool IsDeallocated) {25 // Should only be allocating the 0x3000, 0x5000, 0x7000, 0x9000 pages.26 EXPECT_GE(Addr, 0x3000u);27 EXPECT_LT(Addr, 0xa000u);28 29 size_t Slot = State.getNearestSlot(Addr);30 31 Metadata[Slot].Addr = Addr;32 Metadata[Slot].RequestedSize = Size;33 Metadata[Slot].IsDeallocated = IsDeallocated;34 Metadata[Slot].AllocationTrace.ThreadID = 123;35 Metadata[Slot].DeallocationTrace.ThreadID = 321;36 setupBacktraces(&Metadata[Slot]);37 38 return Slot;39 }40 41 void setupState() {42 State.GuardedPagePool = 0x2000;43 State.GuardedPagePoolEnd = 0xc000;44 InternalFaultAddr = State.GuardedPagePoolEnd - 0x10;45 State.MaxSimultaneousAllocations = 4; // 0x3000, 0x5000, 0x7000, 0x9000.46 State.PageSize = 0x1000;47 }48 49 void setupBacktraces(AllocationMetadata *Meta) {50 Meta->AllocationTrace.TraceSize = gwp_asan::compression::pack(51 BacktraceConstants, kNumBacktraceConstants,52 Meta->AllocationTrace.CompressedTrace,53 AllocationMetadata::kStackFrameStorageBytes);54 55 if (Meta->IsDeallocated)56 Meta->DeallocationTrace.TraceSize = gwp_asan::compression::pack(57 BacktraceConstants, kNumBacktraceConstants,58 Meta->DeallocationTrace.CompressedTrace,59 AllocationMetadata::kStackFrameStorageBytes);60 }61 62 void checkBacktrace(const AllocationMetadata *Meta, bool IsDeallocated) {63 uintptr_t Buffer[kNumBacktraceConstants];64 size_t NumBacktraceConstants = kNumBacktraceConstants;65 EXPECT_EQ(NumBacktraceConstants, __gwp_asan_get_allocation_trace(66 Meta, Buffer, kNumBacktraceConstants));67 for (size_t i = 0; i < kNumBacktraceConstants; ++i)68 EXPECT_EQ(Buffer[i], BacktraceConstants[i]);69 70 if (IsDeallocated) {71 EXPECT_EQ(NumBacktraceConstants,72 __gwp_asan_get_deallocation_trace(Meta, Buffer,73 kNumBacktraceConstants));74 for (size_t i = 0; i < kNumBacktraceConstants; ++i)75 EXPECT_EQ(Buffer[i], BacktraceConstants[i]);76 }77 }78 79 void checkMetadata(size_t Index, uintptr_t ErrorPtr) {80 const AllocationMetadata *Meta =81 __gwp_asan_get_metadata(&State, Metadata, ErrorPtr);82 EXPECT_NE(nullptr, Meta);83 EXPECT_EQ(Metadata[Index].Addr, __gwp_asan_get_allocation_address(Meta));84 EXPECT_EQ(Metadata[Index].RequestedSize,85 __gwp_asan_get_allocation_size(Meta));86 EXPECT_EQ(Metadata[Index].AllocationTrace.ThreadID,87 __gwp_asan_get_allocation_thread_id(Meta));88 89 bool IsDeallocated = __gwp_asan_is_deallocated(Meta);90 EXPECT_EQ(Metadata[Index].IsDeallocated, IsDeallocated);91 checkBacktrace(Meta, IsDeallocated);92 93 if (!IsDeallocated)94 return;95 96 EXPECT_EQ(Metadata[Index].DeallocationTrace.ThreadID,97 __gwp_asan_get_deallocation_thread_id(Meta));98 }99 100 static constexpr size_t kNumBacktraceConstants = 4;101 static uintptr_t BacktraceConstants[kNumBacktraceConstants];102 AllocatorState State = {};103 AllocationMetadata Metadata[4] = {};104 uintptr_t InternalFaultAddr;105};106 107uintptr_t CrashHandlerAPITest::BacktraceConstants[kNumBacktraceConstants] = {108 0xdeadbeef, 0xdeadc0de, 0xbadc0ffe, 0xcafef00d};109 110TEST_F(CrashHandlerAPITest, PointerNotMine) {111 uintptr_t UnknownPtr = reinterpret_cast<uintptr_t>(&State);112 113 EXPECT_FALSE(__gwp_asan_error_is_mine(&State, 0));114 EXPECT_FALSE(__gwp_asan_error_is_mine(&State, UnknownPtr));115 116 EXPECT_EQ(Error::UNKNOWN, __gwp_asan_diagnose_error(&State, Metadata, 0));117 EXPECT_EQ(Error::UNKNOWN,118 __gwp_asan_diagnose_error(&State, Metadata, UnknownPtr));119 120 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, 0));121 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, UnknownPtr));122}123 124TEST_F(CrashHandlerAPITest, PointerNotAllocated) {125 uintptr_t FailureAddress = 0x9000;126 127 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));128 EXPECT_EQ(Error::UNKNOWN,129 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress));130 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State, FailureAddress));131 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress));132}133 134TEST_F(CrashHandlerAPITest, DoubleFree) {135 size_t Index =136 metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true);137 uintptr_t FailureAddress = 0x7000;138 139 State.FailureType = Error::DOUBLE_FREE;140 State.FailureAddress = FailureAddress;141 142 EXPECT_TRUE(__gwp_asan_error_is_mine(&State));143 EXPECT_EQ(Error::DOUBLE_FREE,144 __gwp_asan_diagnose_error(&State, Metadata, 0x0));145 EXPECT_EQ(FailureAddress,146 __gwp_asan_get_internal_crash_address(&State, InternalFaultAddr));147 checkMetadata(Index, FailureAddress);148}149 150TEST_F(CrashHandlerAPITest, InvalidFree) {151 size_t Index =152 metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ false);153 uintptr_t FailureAddress = 0x7001;154 155 State.FailureType = Error::INVALID_FREE;156 State.FailureAddress = FailureAddress;157 158 EXPECT_TRUE(__gwp_asan_error_is_mine(&State));159 EXPECT_EQ(Error::INVALID_FREE,160 __gwp_asan_diagnose_error(&State, Metadata, 0x0));161 EXPECT_EQ(FailureAddress,162 __gwp_asan_get_internal_crash_address(&State, InternalFaultAddr));163 checkMetadata(Index, FailureAddress);164}165 166TEST_F(CrashHandlerAPITest, InvalidFreeNoMetadata) {167 uintptr_t FailureAddress = 0x7001;168 169 State.FailureType = Error::INVALID_FREE;170 State.FailureAddress = FailureAddress;171 172 EXPECT_TRUE(__gwp_asan_error_is_mine(&State));173 EXPECT_EQ(Error::INVALID_FREE,174 __gwp_asan_diagnose_error(&State, Metadata, 0x0));175 EXPECT_EQ(FailureAddress,176 __gwp_asan_get_internal_crash_address(&State, InternalFaultAddr));177 EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress));178}179 180TEST_F(CrashHandlerAPITest, UseAfterFree) {181 size_t Index =182 metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true);183 uintptr_t FailureAddress = 0x7001;184 185 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));186 EXPECT_EQ(Error::USE_AFTER_FREE,187 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress));188 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State, FailureAddress));189 checkMetadata(Index, FailureAddress);190}191 192TEST_F(CrashHandlerAPITest, BufferOverflow) {193 size_t Index =194 metadata(/* Addr */ 0x5f00, /* Size */ 0x100, /* IsDeallocated */ false);195 uintptr_t FailureAddress = 0x6000;196 197 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));198 EXPECT_EQ(Error::BUFFER_OVERFLOW,199 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress));200 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State, FailureAddress));201 checkMetadata(Index, FailureAddress);202}203 204TEST_F(CrashHandlerAPITest, BufferUnderflow) {205 size_t Index =206 metadata(/* Addr */ 0x3000, /* Size */ 0x10, /* IsDeallocated*/ false);207 uintptr_t FailureAddress = 0x2fff;208 209 EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));210 EXPECT_EQ(Error::BUFFER_UNDERFLOW,211 __gwp_asan_diagnose_error(&State, Metadata, FailureAddress));212 EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State, FailureAddress));213 checkMetadata(Index, FailureAddress);214}215