Poison.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* vim: set ts=8 sts=2 et sw=2 tw=80: */
  3. /* This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. /*
  7. * A poison value that can be used to fill a memory space with
  8. * an address that leads to a safe crash when dereferenced.
  9. */
  10. #ifndef mozilla_Poison_h
  11. #define mozilla_Poison_h
  12. #include "mozilla/Assertions.h"
  13. #include "mozilla/Types.h"
  14. #include <stdint.h>
  15. MOZ_BEGIN_EXTERN_C
  16. extern MFBT_DATA uintptr_t gMozillaPoisonValue;
  17. /**
  18. * @return the poison value.
  19. */
  20. inline uintptr_t mozPoisonValue()
  21. {
  22. return gMozillaPoisonValue;
  23. }
  24. /**
  25. * Overwrite the memory block of aSize bytes at aPtr with the poison value.
  26. * aPtr MUST be aligned at a sizeof(uintptr_t) boundary.
  27. * Only an even number of sizeof(uintptr_t) bytes are overwritten, the last
  28. * few bytes (if any) is not overwritten.
  29. */
  30. inline void mozWritePoison(void* aPtr, size_t aSize)
  31. {
  32. const uintptr_t POISON = mozPoisonValue();
  33. char* p = (char*)aPtr;
  34. char* limit = p + aSize;
  35. MOZ_ASSERT((uintptr_t)aPtr % sizeof(uintptr_t) == 0, "bad alignment");
  36. MOZ_ASSERT(aSize >= sizeof(uintptr_t), "poisoning this object has no effect");
  37. for (; p < limit; p += sizeof(uintptr_t)) {
  38. *((uintptr_t*)p) = POISON;
  39. }
  40. }
  41. /**
  42. * Initialize the poison value.
  43. * This should only be called once.
  44. */
  45. extern MFBT_API void mozPoisonValueInit();
  46. /* Values annotated by CrashReporter */
  47. extern MFBT_DATA uintptr_t gMozillaPoisonBase;
  48. extern MFBT_DATA uintptr_t gMozillaPoisonSize;
  49. MOZ_END_EXTERN_C
  50. #if defined(__cplusplus)
  51. namespace mozilla {
  52. /**
  53. * This class is designed to cause crashes when various kinds of memory
  54. * corruption are observed. For instance, let's say we have a class C where we
  55. * suspect out-of-bounds writes to some members. We can insert a member of type
  56. * Poison near the members we suspect are being corrupted by out-of-bounds
  57. * writes. Or perhaps we have a class K we suspect is subject to use-after-free
  58. * violations, in which case it doesn't particularly matter where in the class
  59. * we add the member of type Poison.
  60. *
  61. * In either case, we then insert calls to Check() throughout the code. Doing
  62. * so enables us to narrow down the location where the corruption is occurring.
  63. * A pleasant side-effect of these additional Check() calls is that crash
  64. * signatures may become more regular, as crashes will ideally occur
  65. * consolidated at the point of a Check(), rather than scattered about at
  66. * various uses of the corrupted memory.
  67. */
  68. class CorruptionCanary {
  69. public:
  70. CorruptionCanary() {
  71. mValue = kCanarySet;
  72. }
  73. ~CorruptionCanary() {
  74. Check();
  75. mValue = mozPoisonValue();
  76. }
  77. void Check() const {
  78. if (mValue != kCanarySet) {
  79. MOZ_CRASH("Canary check failed, check lifetime");
  80. }
  81. }
  82. private:
  83. static const uintptr_t kCanarySet = 0x0f0b0f0b;
  84. uintptr_t mValue;
  85. };
  86. } // mozilla
  87. #endif
  88. #endif /* mozilla_Poison_h */