crash_handler.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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. uintptr_t ErrorPtr) {
  29. // There can be a race between internally- and externally-raised faults. The
  30. // fault address from the signal handler is used to discriminate whether it's
  31. // internally- or externally-raised, and the pool maintains a special page at
  32. // the end of the GuardedPagePool specifically for the internally-raised
  33. // faults.
  34. if (ErrorPtr != State->internallyDetectedErrorFaultAddress())
  35. return 0u;
  36. return State->FailureAddress;
  37. }
  38. static const AllocationMetadata *
  39. addrToMetadata(const gwp_asan::AllocatorState *State,
  40. const AllocationMetadata *Metadata, uintptr_t Ptr) {
  41. // Note - Similar implementation in guarded_pool_allocator.cpp.
  42. return &Metadata[State->getNearestSlot(Ptr)];
  43. }
  44. gwp_asan::Error
  45. __gwp_asan_diagnose_error(const gwp_asan::AllocatorState *State,
  46. const gwp_asan::AllocationMetadata *Metadata,
  47. uintptr_t ErrorPtr) {
  48. if (!__gwp_asan_error_is_mine(State, ErrorPtr))
  49. return Error::UNKNOWN;
  50. if (State->FailureType != Error::UNKNOWN)
  51. return State->FailureType;
  52. // Check for use-after-free.
  53. if (addrToMetadata(State, Metadata, ErrorPtr)->IsDeallocated)
  54. return Error::USE_AFTER_FREE;
  55. // Check for buffer-overflow. Because of allocation alignment or left/right
  56. // page placement, we can have buffer-overflows that don't touch a guarded
  57. // page, but these are not possible to detect unless it's also a
  58. // use-after-free, which is handled above.
  59. if (State->isGuardPage(ErrorPtr)) {
  60. size_t Slot = State->getNearestSlot(ErrorPtr);
  61. const AllocationMetadata *SlotMeta =
  62. addrToMetadata(State, Metadata, State->slotToAddr(Slot));
  63. // Ensure that this slot was allocated once upon a time.
  64. if (!SlotMeta->Addr)
  65. return Error::UNKNOWN;
  66. if (SlotMeta->Addr < ErrorPtr)
  67. return Error::BUFFER_OVERFLOW;
  68. return Error::BUFFER_UNDERFLOW;
  69. }
  70. // If we have reached here, the error is still unknown.
  71. return Error::UNKNOWN;
  72. }
  73. const gwp_asan::AllocationMetadata *
  74. __gwp_asan_get_metadata(const gwp_asan::AllocatorState *State,
  75. const gwp_asan::AllocationMetadata *Metadata,
  76. uintptr_t ErrorPtr) {
  77. if (!__gwp_asan_error_is_mine(State, ErrorPtr))
  78. return nullptr;
  79. if (ErrorPtr >= State->GuardedPagePoolEnd ||
  80. State->GuardedPagePool > ErrorPtr)
  81. return nullptr;
  82. const AllocationMetadata *Meta = addrToMetadata(State, Metadata, ErrorPtr);
  83. if (Meta->Addr == 0)
  84. return nullptr;
  85. return Meta;
  86. }
  87. uintptr_t __gwp_asan_get_allocation_address(
  88. const gwp_asan::AllocationMetadata *AllocationMeta) {
  89. return AllocationMeta->Addr;
  90. }
  91. size_t __gwp_asan_get_allocation_size(
  92. const gwp_asan::AllocationMetadata *AllocationMeta) {
  93. return AllocationMeta->RequestedSize;
  94. }
  95. uint64_t __gwp_asan_get_allocation_thread_id(
  96. const gwp_asan::AllocationMetadata *AllocationMeta) {
  97. return AllocationMeta->AllocationTrace.ThreadID;
  98. }
  99. size_t __gwp_asan_get_allocation_trace(
  100. const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,
  101. size_t BufferLen) {
  102. uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];
  103. size_t UnpackedLength = gwp_asan::compression::unpack(
  104. AllocationMeta->AllocationTrace.CompressedTrace,
  105. AllocationMeta->AllocationTrace.TraceSize, UncompressedBuffer,
  106. AllocationMetadata::kMaxTraceLengthToCollect);
  107. if (UnpackedLength < BufferLen)
  108. BufferLen = UnpackedLength;
  109. memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));
  110. return UnpackedLength;
  111. }
  112. bool __gwp_asan_is_deallocated(
  113. const gwp_asan::AllocationMetadata *AllocationMeta) {
  114. return AllocationMeta->IsDeallocated;
  115. }
  116. uint64_t __gwp_asan_get_deallocation_thread_id(
  117. const gwp_asan::AllocationMetadata *AllocationMeta) {
  118. return AllocationMeta->DeallocationTrace.ThreadID;
  119. }
  120. size_t __gwp_asan_get_deallocation_trace(
  121. const gwp_asan::AllocationMetadata *AllocationMeta, uintptr_t *Buffer,
  122. size_t BufferLen) {
  123. uintptr_t UncompressedBuffer[AllocationMetadata::kMaxTraceLengthToCollect];
  124. size_t UnpackedLength = gwp_asan::compression::unpack(
  125. AllocationMeta->DeallocationTrace.CompressedTrace,
  126. AllocationMeta->DeallocationTrace.TraceSize, UncompressedBuffer,
  127. AllocationMetadata::kMaxTraceLengthToCollect);
  128. if (UnpackedLength < BufferLen)
  129. BufferLen = UnpackedLength;
  130. memcpy(Buffer, UncompressedBuffer, BufferLen * sizeof(*Buffer));
  131. return UnpackedLength;
  132. }
  133. #ifdef __cplusplus
  134. } // extern "C"
  135. #endif