xref: /openbsd-src/gnu/llvm/compiler-rt/lib/gwp_asan/tests/crash_handler_api.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
11f9cb04fSpatrick //===-- crash_handler_api.cpp -----------------------------------*- C++ -*-===//
21f9cb04fSpatrick //
31f9cb04fSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41f9cb04fSpatrick // See https://llvm.org/LICENSE.txt for license information.
51f9cb04fSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61f9cb04fSpatrick //
71f9cb04fSpatrick //===----------------------------------------------------------------------===//
81f9cb04fSpatrick 
91f9cb04fSpatrick #include "gwp_asan/crash_handler.h"
101f9cb04fSpatrick #include "gwp_asan/guarded_pool_allocator.h"
111f9cb04fSpatrick #include "gwp_asan/stack_trace_compressor.h"
121f9cb04fSpatrick #include "gwp_asan/tests/harness.h"
131f9cb04fSpatrick 
141f9cb04fSpatrick using Error = gwp_asan::Error;
151f9cb04fSpatrick using GuardedPoolAllocator = gwp_asan::GuardedPoolAllocator;
161f9cb04fSpatrick using AllocationMetadata = gwp_asan::AllocationMetadata;
171f9cb04fSpatrick using AllocatorState = gwp_asan::AllocatorState;
181f9cb04fSpatrick 
19d89ec533Spatrick class CrashHandlerAPITest : public Test {
201f9cb04fSpatrick public:
SetUp()211f9cb04fSpatrick   void SetUp() override { setupState(); }
221f9cb04fSpatrick 
231f9cb04fSpatrick protected:
metadata(uintptr_t Addr,uintptr_t Size,bool IsDeallocated)241f9cb04fSpatrick   size_t metadata(uintptr_t Addr, uintptr_t Size, bool IsDeallocated) {
251f9cb04fSpatrick     // Should only be allocating the 0x3000, 0x5000, 0x7000, 0x9000 pages.
261f9cb04fSpatrick     EXPECT_GE(Addr, 0x3000u);
271f9cb04fSpatrick     EXPECT_LT(Addr, 0xa000u);
281f9cb04fSpatrick 
291f9cb04fSpatrick     size_t Slot = State.getNearestSlot(Addr);
301f9cb04fSpatrick 
311f9cb04fSpatrick     Metadata[Slot].Addr = Addr;
32d89ec533Spatrick     Metadata[Slot].RequestedSize = Size;
331f9cb04fSpatrick     Metadata[Slot].IsDeallocated = IsDeallocated;
341f9cb04fSpatrick     Metadata[Slot].AllocationTrace.ThreadID = 123;
351f9cb04fSpatrick     Metadata[Slot].DeallocationTrace.ThreadID = 321;
361f9cb04fSpatrick     setupBacktraces(&Metadata[Slot]);
371f9cb04fSpatrick 
381f9cb04fSpatrick     return Slot;
391f9cb04fSpatrick   }
401f9cb04fSpatrick 
setupState()411f9cb04fSpatrick   void setupState() {
421f9cb04fSpatrick     State.GuardedPagePool = 0x2000;
43*810390e3Srobert     State.GuardedPagePoolEnd = 0xc000;
44*810390e3Srobert     InternalFaultAddr = State.GuardedPagePoolEnd - 0x10;
451f9cb04fSpatrick     State.MaxSimultaneousAllocations = 4; // 0x3000, 0x5000, 0x7000, 0x9000.
461f9cb04fSpatrick     State.PageSize = 0x1000;
471f9cb04fSpatrick   }
481f9cb04fSpatrick 
setupBacktraces(AllocationMetadata * Meta)491f9cb04fSpatrick   void setupBacktraces(AllocationMetadata *Meta) {
501f9cb04fSpatrick     Meta->AllocationTrace.TraceSize = gwp_asan::compression::pack(
511f9cb04fSpatrick         BacktraceConstants, kNumBacktraceConstants,
521f9cb04fSpatrick         Meta->AllocationTrace.CompressedTrace,
531f9cb04fSpatrick         AllocationMetadata::kStackFrameStorageBytes);
541f9cb04fSpatrick 
551f9cb04fSpatrick     if (Meta->IsDeallocated)
561f9cb04fSpatrick       Meta->DeallocationTrace.TraceSize = gwp_asan::compression::pack(
571f9cb04fSpatrick           BacktraceConstants, kNumBacktraceConstants,
581f9cb04fSpatrick           Meta->DeallocationTrace.CompressedTrace,
591f9cb04fSpatrick           AllocationMetadata::kStackFrameStorageBytes);
601f9cb04fSpatrick   }
611f9cb04fSpatrick 
checkBacktrace(const AllocationMetadata * Meta,bool IsDeallocated)621f9cb04fSpatrick   void checkBacktrace(const AllocationMetadata *Meta, bool IsDeallocated) {
631f9cb04fSpatrick     uintptr_t Buffer[kNumBacktraceConstants];
641f9cb04fSpatrick     size_t NumBacktraceConstants = kNumBacktraceConstants;
651f9cb04fSpatrick     EXPECT_EQ(NumBacktraceConstants, __gwp_asan_get_allocation_trace(
661f9cb04fSpatrick                                          Meta, Buffer, kNumBacktraceConstants));
671f9cb04fSpatrick     for (size_t i = 0; i < kNumBacktraceConstants; ++i)
681f9cb04fSpatrick       EXPECT_EQ(Buffer[i], BacktraceConstants[i]);
691f9cb04fSpatrick 
701f9cb04fSpatrick     if (IsDeallocated) {
711f9cb04fSpatrick       EXPECT_EQ(NumBacktraceConstants,
721f9cb04fSpatrick                 __gwp_asan_get_deallocation_trace(Meta, Buffer,
731f9cb04fSpatrick                                                   kNumBacktraceConstants));
741f9cb04fSpatrick       for (size_t i = 0; i < kNumBacktraceConstants; ++i)
751f9cb04fSpatrick         EXPECT_EQ(Buffer[i], BacktraceConstants[i]);
761f9cb04fSpatrick     }
771f9cb04fSpatrick   }
781f9cb04fSpatrick 
checkMetadata(size_t Index,uintptr_t ErrorPtr)791f9cb04fSpatrick   void checkMetadata(size_t Index, uintptr_t ErrorPtr) {
801f9cb04fSpatrick     const AllocationMetadata *Meta =
811f9cb04fSpatrick         __gwp_asan_get_metadata(&State, Metadata, ErrorPtr);
821f9cb04fSpatrick     EXPECT_NE(nullptr, Meta);
831f9cb04fSpatrick     EXPECT_EQ(Metadata[Index].Addr, __gwp_asan_get_allocation_address(Meta));
84d89ec533Spatrick     EXPECT_EQ(Metadata[Index].RequestedSize,
85d89ec533Spatrick               __gwp_asan_get_allocation_size(Meta));
861f9cb04fSpatrick     EXPECT_EQ(Metadata[Index].AllocationTrace.ThreadID,
871f9cb04fSpatrick               __gwp_asan_get_allocation_thread_id(Meta));
881f9cb04fSpatrick 
891f9cb04fSpatrick     bool IsDeallocated = __gwp_asan_is_deallocated(Meta);
901f9cb04fSpatrick     EXPECT_EQ(Metadata[Index].IsDeallocated, IsDeallocated);
911f9cb04fSpatrick     checkBacktrace(Meta, IsDeallocated);
921f9cb04fSpatrick 
931f9cb04fSpatrick     if (!IsDeallocated)
941f9cb04fSpatrick       return;
951f9cb04fSpatrick 
961f9cb04fSpatrick     EXPECT_EQ(Metadata[Index].DeallocationTrace.ThreadID,
971f9cb04fSpatrick               __gwp_asan_get_deallocation_thread_id(Meta));
981f9cb04fSpatrick   }
991f9cb04fSpatrick 
1001f9cb04fSpatrick   static constexpr size_t kNumBacktraceConstants = 4;
1011f9cb04fSpatrick   static uintptr_t BacktraceConstants[kNumBacktraceConstants];
1021f9cb04fSpatrick   AllocatorState State = {};
1031f9cb04fSpatrick   AllocationMetadata Metadata[4] = {};
104*810390e3Srobert   uintptr_t InternalFaultAddr;
1051f9cb04fSpatrick };
1061f9cb04fSpatrick 
1071f9cb04fSpatrick uintptr_t CrashHandlerAPITest::BacktraceConstants[kNumBacktraceConstants] = {
1081f9cb04fSpatrick     0xdeadbeef, 0xdeadc0de, 0xbadc0ffe, 0xcafef00d};
1091f9cb04fSpatrick 
TEST_F(CrashHandlerAPITest,PointerNotMine)1101f9cb04fSpatrick TEST_F(CrashHandlerAPITest, PointerNotMine) {
1111f9cb04fSpatrick   uintptr_t UnknownPtr = reinterpret_cast<uintptr_t>(&State);
1121f9cb04fSpatrick 
1131f9cb04fSpatrick   EXPECT_FALSE(__gwp_asan_error_is_mine(&State, 0));
1141f9cb04fSpatrick   EXPECT_FALSE(__gwp_asan_error_is_mine(&State, UnknownPtr));
1151f9cb04fSpatrick 
1161f9cb04fSpatrick   EXPECT_EQ(Error::UNKNOWN, __gwp_asan_diagnose_error(&State, Metadata, 0));
1171f9cb04fSpatrick   EXPECT_EQ(Error::UNKNOWN,
1181f9cb04fSpatrick             __gwp_asan_diagnose_error(&State, Metadata, UnknownPtr));
1191f9cb04fSpatrick 
1201f9cb04fSpatrick   EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, 0));
1211f9cb04fSpatrick   EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, UnknownPtr));
1221f9cb04fSpatrick }
1231f9cb04fSpatrick 
TEST_F(CrashHandlerAPITest,PointerNotAllocated)1241f9cb04fSpatrick TEST_F(CrashHandlerAPITest, PointerNotAllocated) {
1251f9cb04fSpatrick   uintptr_t FailureAddress = 0x9000;
1261f9cb04fSpatrick 
1271f9cb04fSpatrick   EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));
1281f9cb04fSpatrick   EXPECT_EQ(Error::UNKNOWN,
1291f9cb04fSpatrick             __gwp_asan_diagnose_error(&State, Metadata, FailureAddress));
130*810390e3Srobert   EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State, FailureAddress));
1311f9cb04fSpatrick   EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress));
1321f9cb04fSpatrick }
1331f9cb04fSpatrick 
TEST_F(CrashHandlerAPITest,DoubleFree)1341f9cb04fSpatrick TEST_F(CrashHandlerAPITest, DoubleFree) {
1351f9cb04fSpatrick   size_t Index =
1361f9cb04fSpatrick       metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true);
1371f9cb04fSpatrick   uintptr_t FailureAddress = 0x7000;
1381f9cb04fSpatrick 
1391f9cb04fSpatrick   State.FailureType = Error::DOUBLE_FREE;
1401f9cb04fSpatrick   State.FailureAddress = FailureAddress;
1411f9cb04fSpatrick 
1421f9cb04fSpatrick   EXPECT_TRUE(__gwp_asan_error_is_mine(&State));
1431f9cb04fSpatrick   EXPECT_EQ(Error::DOUBLE_FREE,
1441f9cb04fSpatrick             __gwp_asan_diagnose_error(&State, Metadata, 0x0));
145*810390e3Srobert   EXPECT_EQ(FailureAddress,
146*810390e3Srobert             __gwp_asan_get_internal_crash_address(&State, InternalFaultAddr));
1471f9cb04fSpatrick   checkMetadata(Index, FailureAddress);
1481f9cb04fSpatrick }
1491f9cb04fSpatrick 
TEST_F(CrashHandlerAPITest,InvalidFree)1501f9cb04fSpatrick TEST_F(CrashHandlerAPITest, InvalidFree) {
1511f9cb04fSpatrick   size_t Index =
1521f9cb04fSpatrick       metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ false);
1531f9cb04fSpatrick   uintptr_t FailureAddress = 0x7001;
1541f9cb04fSpatrick 
1551f9cb04fSpatrick   State.FailureType = Error::INVALID_FREE;
1561f9cb04fSpatrick   State.FailureAddress = FailureAddress;
1571f9cb04fSpatrick 
1581f9cb04fSpatrick   EXPECT_TRUE(__gwp_asan_error_is_mine(&State));
1591f9cb04fSpatrick   EXPECT_EQ(Error::INVALID_FREE,
1601f9cb04fSpatrick             __gwp_asan_diagnose_error(&State, Metadata, 0x0));
161*810390e3Srobert   EXPECT_EQ(FailureAddress,
162*810390e3Srobert             __gwp_asan_get_internal_crash_address(&State, InternalFaultAddr));
1631f9cb04fSpatrick   checkMetadata(Index, FailureAddress);
1641f9cb04fSpatrick }
1651f9cb04fSpatrick 
TEST_F(CrashHandlerAPITest,InvalidFreeNoMetadata)1661f9cb04fSpatrick TEST_F(CrashHandlerAPITest, InvalidFreeNoMetadata) {
1671f9cb04fSpatrick   uintptr_t FailureAddress = 0x7001;
1681f9cb04fSpatrick 
1691f9cb04fSpatrick   State.FailureType = Error::INVALID_FREE;
1701f9cb04fSpatrick   State.FailureAddress = FailureAddress;
1711f9cb04fSpatrick 
1721f9cb04fSpatrick   EXPECT_TRUE(__gwp_asan_error_is_mine(&State));
1731f9cb04fSpatrick   EXPECT_EQ(Error::INVALID_FREE,
1741f9cb04fSpatrick             __gwp_asan_diagnose_error(&State, Metadata, 0x0));
175*810390e3Srobert   EXPECT_EQ(FailureAddress,
176*810390e3Srobert             __gwp_asan_get_internal_crash_address(&State, InternalFaultAddr));
1771f9cb04fSpatrick   EXPECT_EQ(nullptr, __gwp_asan_get_metadata(&State, Metadata, FailureAddress));
1781f9cb04fSpatrick }
1791f9cb04fSpatrick 
TEST_F(CrashHandlerAPITest,UseAfterFree)1801f9cb04fSpatrick TEST_F(CrashHandlerAPITest, UseAfterFree) {
1811f9cb04fSpatrick   size_t Index =
1821f9cb04fSpatrick       metadata(/* Addr */ 0x7000, /* Size */ 0x20, /* IsDeallocated */ true);
1831f9cb04fSpatrick   uintptr_t FailureAddress = 0x7001;
1841f9cb04fSpatrick 
1851f9cb04fSpatrick   EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));
1861f9cb04fSpatrick   EXPECT_EQ(Error::USE_AFTER_FREE,
1871f9cb04fSpatrick             __gwp_asan_diagnose_error(&State, Metadata, FailureAddress));
188*810390e3Srobert   EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State, FailureAddress));
1891f9cb04fSpatrick   checkMetadata(Index, FailureAddress);
1901f9cb04fSpatrick }
1911f9cb04fSpatrick 
TEST_F(CrashHandlerAPITest,BufferOverflow)1921f9cb04fSpatrick TEST_F(CrashHandlerAPITest, BufferOverflow) {
1931f9cb04fSpatrick   size_t Index =
1941f9cb04fSpatrick       metadata(/* Addr */ 0x5f00, /* Size */ 0x100, /* IsDeallocated */ false);
1951f9cb04fSpatrick   uintptr_t FailureAddress = 0x6000;
1961f9cb04fSpatrick 
1971f9cb04fSpatrick   EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));
1981f9cb04fSpatrick   EXPECT_EQ(Error::BUFFER_OVERFLOW,
1991f9cb04fSpatrick             __gwp_asan_diagnose_error(&State, Metadata, FailureAddress));
200*810390e3Srobert   EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State, FailureAddress));
2011f9cb04fSpatrick   checkMetadata(Index, FailureAddress);
2021f9cb04fSpatrick }
2031f9cb04fSpatrick 
TEST_F(CrashHandlerAPITest,BufferUnderflow)2041f9cb04fSpatrick TEST_F(CrashHandlerAPITest, BufferUnderflow) {
2051f9cb04fSpatrick   size_t Index =
2061f9cb04fSpatrick       metadata(/* Addr */ 0x3000, /* Size */ 0x10, /* IsDeallocated*/ false);
2071f9cb04fSpatrick   uintptr_t FailureAddress = 0x2fff;
2081f9cb04fSpatrick 
2091f9cb04fSpatrick   EXPECT_TRUE(__gwp_asan_error_is_mine(&State, FailureAddress));
2101f9cb04fSpatrick   EXPECT_EQ(Error::BUFFER_UNDERFLOW,
2111f9cb04fSpatrick             __gwp_asan_diagnose_error(&State, Metadata, FailureAddress));
212*810390e3Srobert   EXPECT_EQ(0u, __gwp_asan_get_internal_crash_address(&State, FailureAddress));
2131f9cb04fSpatrick   checkMetadata(Index, FailureAddress);
2141f9cb04fSpatrick }
215