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