immediate_crash_unittest.cc 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/immediate_crash.h"
  5. #include <stdint.h>
  6. #include "base/base_paths.h"
  7. #include "base/clang_profiling_buildflags.h"
  8. #include "base/containers/span.h"
  9. #include "base/files/file_path.h"
  10. #include "base/path_service.h"
  11. #include "base/ranges/algorithm.h"
  12. #include "base/scoped_native_library.h"
  13. #include "base/strings/string_number_conversions.h"
  14. #include "build/build_config.h"
  15. #include "build/buildflag.h"
  16. #include "testing/gtest/include/gtest/gtest.h"
  17. #include "third_party/abseil-cpp/absl/types/optional.h"
  18. namespace base {
  19. namespace {
  20. // If IMMEDIATE_CRASH() is not treated as noreturn by the compiler, the compiler
  21. // will complain that not all paths through this function return a value.
  22. [[maybe_unused]] int TestImmediateCrashTreatedAsNoReturn() {
  23. IMMEDIATE_CRASH();
  24. }
  25. #if defined(ARCH_CPU_X86_FAMILY)
  26. // This is tricksy and false, since x86 instructions are not all one byte long,
  27. // but there is no better alternative short of implementing an x86 instruction
  28. // decoder.
  29. using Instruction = uint8_t;
  30. // https://software.intel.com/en-us/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4
  31. // Look for RET opcode (0xc3). Note that 0xC3 is a substring of several
  32. // other opcodes (VMRESUME, MOVNTI), and can also be encoded as part of an
  33. // argument to another opcode. None of these other cases are expected to be
  34. // present, so a simple byte scan should be Good Enough™.
  35. constexpr Instruction kRet = 0xc3;
  36. // INT3 ; UD2
  37. constexpr Instruction kRequiredBody[] = {0xcc, 0x0f, 0x0b};
  38. constexpr Instruction kOptionalFooter[] = {};
  39. #elif defined(ARCH_CPU_ARMEL)
  40. using Instruction = uint16_t;
  41. // T32 opcode reference: https://developer.arm.com/docs/ddi0487/latest
  42. // Actually BX LR, canonical encoding:
  43. constexpr Instruction kRet = 0x4770;
  44. // BKPT #0; UDF #0
  45. constexpr Instruction kRequiredBody[] = {0xbe00, 0xde00};
  46. constexpr Instruction kOptionalFooter[] = {};
  47. #elif defined(ARCH_CPU_ARM64)
  48. using Instruction = uint32_t;
  49. // A64 opcode reference: https://developer.arm.com/docs/ddi0487/latest
  50. // Use an enum here rather than separate constexpr vars because otherwise some
  51. // of the vars will end up unused on each platform, upsetting
  52. // -Wunused-const-variable.
  53. enum : Instruction {
  54. // There are multiple valid encodings of return (which is really a special
  55. // form of branch). This is the one clang seems to use:
  56. kRet = 0xd65f03c0,
  57. kBrk0 = 0xd4200000,
  58. kBrk1 = 0xd4200020,
  59. kBrkF000 = 0xd43e0000,
  60. kHlt0 = 0xd4400000,
  61. };
  62. #if BUILDFLAG(IS_WIN)
  63. constexpr Instruction kRequiredBody[] = {kBrkF000, kBrk1};
  64. constexpr Instruction kOptionalFooter[] = {};
  65. #elif BUILDFLAG(IS_MAC)
  66. constexpr Instruction kRequiredBody[] = {kBrk0, kHlt0};
  67. // Some clangs emit a BRK #1 for __builtin_unreachable(), but some do not, so
  68. // it is allowed but not required to occur.
  69. constexpr Instruction kOptionalFooter[] = {kBrk1};
  70. #else
  71. constexpr Instruction kRequiredBody[] = {kBrk0, kHlt0};
  72. constexpr Instruction kOptionalFooter[] = {};
  73. #endif
  74. #endif
  75. // This function loads a shared library that defines two functions,
  76. // TestFunction1 and TestFunction2. It then returns the bytes of the body of
  77. // whichever of those functions happens to come first in the library.
  78. void GetTestFunctionInstructions(std::vector<Instruction>* body) {
  79. FilePath helper_library_path;
  80. #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
  81. // On Android M, DIR_EXE == /system/bin when running base_unittests.
  82. // On Fuchsia, NativeLibrary understands the native convention that libraries
  83. // are not colocated with the binary.
  84. ASSERT_TRUE(PathService::Get(DIR_EXE, &helper_library_path));
  85. #endif
  86. helper_library_path = helper_library_path.AppendASCII(
  87. GetNativeLibraryName("immediate_crash_test_helper"));
  88. #if BUILDFLAG(IS_ANDROID) && defined(COMPONENT_BUILD)
  89. helper_library_path = helper_library_path.ReplaceExtension(".cr.so");
  90. #endif
  91. ScopedNativeLibrary helper_library(helper_library_path);
  92. ASSERT_TRUE(helper_library.is_valid())
  93. << "shared library load failed: "
  94. << helper_library.GetError()->ToString();
  95. void* a = helper_library.GetFunctionPointer("TestFunction1");
  96. ASSERT_TRUE(a);
  97. void* b = helper_library.GetFunctionPointer("TestFunction2");
  98. ASSERT_TRUE(b);
  99. #if defined(ARCH_CPU_ARMEL)
  100. // Routines loaded from a shared library will have the LSB in the pointer set
  101. // if encoded as T32 instructions. The rest of this test assumes T32.
  102. ASSERT_TRUE(reinterpret_cast<uintptr_t>(a) & 0x1)
  103. << "Expected T32 opcodes but found A32 opcodes instead.";
  104. ASSERT_TRUE(reinterpret_cast<uintptr_t>(b) & 0x1)
  105. << "Expected T32 opcodes but found A32 opcodes instead.";
  106. // Mask off the lowest bit.
  107. a = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(a) & ~uintptr_t{0x1});
  108. b = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(b) & ~uintptr_t{0x1});
  109. #endif
  110. // There are two identical test functions starting at a and b, which may
  111. // occur in the library in either order. Grab whichever one comes first,
  112. // and use the address of the other to figure out where it ends.
  113. const Instruction* const start = static_cast<Instruction*>(std::min(a, b));
  114. const Instruction* const end = static_cast<Instruction*>(std::max(a, b));
  115. for (const Instruction& instruction : make_span(start, end))
  116. body->push_back(instruction);
  117. }
  118. absl::optional<std::vector<Instruction>> ExpectImmediateCrashInvocation(
  119. std::vector<Instruction> instructions) {
  120. auto iter = instructions.begin();
  121. for (const auto inst : kRequiredBody) {
  122. if (iter == instructions.end())
  123. return absl::nullopt;
  124. EXPECT_EQ(inst, *iter);
  125. iter++;
  126. }
  127. return absl::make_optional(
  128. std::vector<Instruction>(iter, instructions.end()));
  129. }
  130. std::vector<Instruction> MaybeSkipOptionalFooter(
  131. std::vector<Instruction> instructions) {
  132. auto iter = instructions.begin();
  133. for (const auto inst : kOptionalFooter) {
  134. if (iter == instructions.end() || *iter != inst)
  135. break;
  136. iter++;
  137. }
  138. return std::vector<Instruction>(iter, instructions.end());
  139. }
  140. #if BUILDFLAG(USE_CLANG_COVERAGE) || BUILDFLAG(CLANG_PROFILING)
  141. bool MatchPrefix(const std::vector<Instruction>& haystack,
  142. const base::span<const Instruction>& needle) {
  143. for (size_t i = 0; i < needle.size(); i++) {
  144. if (i >= haystack.size() || needle[i] != haystack[i])
  145. return false;
  146. }
  147. return true;
  148. }
  149. std::vector<Instruction> DropUntilMatch(
  150. std::vector<Instruction> haystack,
  151. const base::span<const Instruction>& needle) {
  152. while (!haystack.empty() && !MatchPrefix(haystack, needle))
  153. haystack.erase(haystack.begin());
  154. return haystack;
  155. }
  156. #endif // USE_CLANG_COVERAGE || BUILDFLAG(CLANG_PROFILING)
  157. std::vector<Instruction> MaybeSkipCoverageHook(
  158. std::vector<Instruction> instructions) {
  159. #if BUILDFLAG(USE_CLANG_COVERAGE) || BUILDFLAG(CLANG_PROFILING)
  160. // Warning: it is not illegal for the entirety of the expected crash sequence
  161. // to appear as a subsequence of the coverage hook code. If that happens, this
  162. // code will falsely exit early, having not found the real expected crash
  163. // sequence, so this may not adequately ensure that the immediate crash
  164. // sequence is present. We do check when not under coverage, at least.
  165. return DropUntilMatch(instructions, base::make_span(kRequiredBody));
  166. #else
  167. return instructions;
  168. #endif // USE_CLANG_COVERAGE || BUILDFLAG(CLANG_PROFILING)
  169. }
  170. } // namespace
  171. // Attempts to verify the actual instructions emitted by IMMEDIATE_CRASH().
  172. // While the test results are highly implementation-specific, this allows macro
  173. // changes (e.g. CLs like https://crrev.com/671123) to be verified using the
  174. // trybots/waterfall, without having to build and disassemble Chrome on
  175. // multiple platforms. This makes it easier to evaluate changes to
  176. // IMMEDIATE_CRASH() against its requirements (e.g. size of emitted sequence,
  177. // whether or not multiple IMMEDIATE_CRASH sequences can be folded together, et
  178. // cetera). Please see immediate_crash.h for more details about the
  179. // requirements.
  180. //
  181. // Note that C++ provides no way to get the size of a function. Instead, the
  182. // test relies on a shared library which defines only two functions and assumes
  183. // the two functions will be laid out contiguously as a heuristic for finding
  184. // the size of the function.
  185. TEST(ImmediateCrashTest, ExpectedOpcodeSequence) {
  186. std::vector<Instruction> body;
  187. ASSERT_NO_FATAL_FAILURE(GetTestFunctionInstructions(&body));
  188. SCOPED_TRACE(HexEncode(body.data(), body.size() * sizeof(Instruction)));
  189. auto it = ranges::find(body, kRet);
  190. ASSERT_NE(body.end(), it) << "Failed to find return opcode";
  191. it++;
  192. body = std::vector<Instruction>(it, body.end());
  193. absl::optional<std::vector<Instruction>> result = MaybeSkipCoverageHook(body);
  194. result = ExpectImmediateCrashInvocation(result.value());
  195. result = MaybeSkipOptionalFooter(result.value());
  196. result = MaybeSkipCoverageHook(result.value());
  197. result = ExpectImmediateCrashInvocation(result.value());
  198. ASSERT_TRUE(result);
  199. }
  200. } // namespace base