crash_handler.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. //===-- crash_handler.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-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "gwp_asan/common.h"
  9. #include "gwp_asan/stack_trace_compressor.h"
  10. #include <assert.h>
  11. #include <stdint.h>
  12. #include <string.h>
  13. using AllocationMetadata = gwp_asan::AllocationMetadata;
  14. using Error = gwp_asan::Error;
  15. #ifdef __cplusplus
  16. extern "C" {
  17. #endif
  18. bool __gwp_asan_error_is_mine(const gwp_asan::AllocatorState *State,
  19. uintptr_t ErrorPtr) {
  20. assert(State && "State should not be nullptr.");
  21. if (State->FailureType != Error::UNKNOWN && State->FailureAddress != 0)
  22. return true;
  23. return ErrorPtr < State->GuardedPagePoolEnd &&
  24. State->GuardedPagePool <= ErrorPtr;
  25. }
  26. uintptr_t
  27. __gwp_asan_get_internal_crash_address(const gwp_asan::AllocatorState *State) {
  28. return State->FailureAddress;
  29. }
  30. static const AllocationMetadata *
  31. addrToMetadata(const gwp_asan::AllocatorState *State,
  32. const AllocationMetadata *Metadata, uintptr_t Ptr) {
  33. // Note - Similar implementation in guarded_pool_allocator.cpp.
  34. return &Metadata[State->getNearestSlot(Ptr)];
  35. }
  36. gwp_asan::Error
  37. __gwp_asan_diagnose_error(const gwp_asan::AllocatorState *State,
  38. const gwp_asan::AllocationMetadata *Metadata,
  39. uintptr_t ErrorPtr) {
  40. if (!__gwp_asan_error_is_mine(State, ErrorPtr))
  41. return Error::UNKNOWN;
  42. if (State->FailureType != Error::UNKNOWN)
  43. return State->FailureType;
  44. // Let's try and figure out what the source of this error is.
  45. if (State->isGuardPage(ErrorPtr)) {
  46. size_t Slot = State->getNearestSlot(ErrorPtr);
  47. const AllocationMetadata *SlotMeta =
  48. addrToMetadata(State, Metadata, State->slotToAddr(Slot));
  49. // Ensure that this slot was allocated once upon a time.
  50. if (!SlotMeta->Addr)
  51. return Error::UNKNOWN;
  52. if (SlotMeta->Addr < ErrorPtr)
  53. return Error::BUFFER_OVERFLOW;
  54. return Error::BUFFER_UNDERFLOW;
  55. }
  56. // Access wasn't a guard page, check for use-after-free.
  57. const AllocationMetadata *SlotMeta =
  58. addrToMetadata(State, Metadata, ErrorPtr);
  59. if (SlotMeta->IsDeallocated) {
  60. return Error::USE_AFTER_FREE;
  61. }
  62. // If we have reached here, the error is still unknown.
  63. return Error::UNKNOWN;
  64. }
  65. const gwp_asan::AllocationMetadata *
  66. __gwp_asan_get_metadata(const gwp_asan::AllocatorState *State,
  67. const gwp_asan::AllocationMetadata *Metadata,
  68. uintptr_t ErrorPtr) {
  69. if (!__gwp_asan_error_is_mine(State, ErrorPtr))
  70. return nullptr;
  71. if (ErrorPtr >= State->GuardedPagePoolEnd ||
  72. State->GuardedPagePool > ErrorPtr)
  73. return nullptr;
  74. const AllocationMetadata *Meta = addrToMetadata(State, Metadata, ErrorPtr);
  75. if (Meta->Addr == 0)
  76. return nullptr;
  77. return Meta;
  78. }
  79. uintptr_t __gwp_asan_get_allocation_address(
  80. const gwp_asan::AllocationMetadata *AllocationMeta) {
  81. return AllocationMeta->Addr;
  82. }
  83. size_t __gwp_asan_get_allocation_size(
  84. const gwp_asan::AllocationMetadata *AllocationMeta) {
  85. return AllocationMeta->RequestedSize;
  86. }
  87. uint64_t __gwp_asan_get_allocation_thread_id(
  88. const gwp_asan::AllocationMetadata *AllocationMeta) {
  89. return AllocationMeta->AllocationTrace.ThreadID;
  90. }
  91. size_t __gwp_asan_get_allocation_trace(
  92. const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,
  93. size_t BufferLen) {
  94. uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];
  95. size_t UnpackedLength = gwp_asan::compression::unpack(
  96. AllocationMeta->AllocationTrace.CompressedTrace,
  97. AllocationMeta->AllocationTrace.TraceSize, UncompressedBuffer,
  98. AllocationMetadata::kMaxTraceLengthToCollect);
  99. if (UnpackedLength < BufferLen)
  100. BufferLen = UnpackedLength;
  101. memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));
  102. return UnpackedLength;
  103. }
  104. bool __gwp_asan_is_deallocated(
  105. const gwp_asan::AllocationMetadata *AllocationMeta) {
  106. return AllocationMeta->IsDeallocated;
  107. }
  108. uint64_t __gwp_asan_get_deallocation_thread_id(
  109. const gwp_asan::AllocationMetadata *AllocationMeta) {
  110. return AllocationMeta->DeallocationTrace.ThreadID;
  111. }
  112. size_t __gwp_asan_get_deallocation_trace(
  113. const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,
  114. size_t BufferLen) {
  115. uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];
  116. size_t UnpackedLength = gwp_asan::compression::unpack(
  117. AllocationMeta->DeallocationTrace.CompressedTrace,
  118. AllocationMeta->DeallocationTrace.TraceSize, UncompressedBuffer,
  119. AllocationMetadata::kMaxTraceLengthToCollect);
  120. if (UnpackedLength < BufferLen)
  121. BufferLen = UnpackedLength;
  122. memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));
  123. return UnpackedLength;
  124. }
  125. #ifdef __cplusplus
  126. } // extern "C"
  127. #endif