[M85 Dev][EFL] Fix crashes at webview launch
[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 <algorithm>
10
11 #include "base/base_paths.h"
12 #include "base/containers/span.h"
13 #include "base/files/file_path.h"
14 #include "base/native_library.h"
15 #include "base/optional.h"
16 #include "base/path_service.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "build/build_config.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace base {
22
23 // Compile test.
24 int TestImmediateCrashTreatedAsNoReturn() {
25   IMMEDIATE_CRASH();
26 }
27
28 // iOS is excluded, since it doesn't support loading shared libraries.
29 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) ||      \
30     defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS) || \
31     defined(OS_FUCHSIA)
32
33 // Checks that the IMMEDIATE_CRASH() macro produces specific instructions; see
34 // comments in immediate_crash.h for the requirements.
35 TEST(ImmediateCrashTest, ExpectedOpcodeSequence) {
36   // TestFunction1() and TestFunction2() are defined in a shared library in an
37   // attempt to guarantee that they are located next to each other.
38   NativeLibraryLoadError load_error;
39   FilePath helper_library_path;
40 #if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
41   // On Android M, DIR_EXE == /system/bin when running base_unittests.
42   // On Fuchsia, NativeLibrary understands the native convention that libraries
43   // are not colocated with the binary.
44   ASSERT_TRUE(PathService::Get(DIR_EXE, &helper_library_path));
45 #endif
46   helper_library_path = helper_library_path.AppendASCII(
47       GetNativeLibraryName("immediate_crash_test_helper"));
48 #if defined(OS_ANDROID) && defined(COMPONENT_BUILD)
49   helper_library_path = helper_library_path.ReplaceExtension(".cr.so");
50 #endif
51   // TODO(dcheng): Shouldn't GetNativeLibraryName just return a FilePath?
52   NativeLibrary helper_library =
53       LoadNativeLibrary(helper_library_path, &load_error);
54   ASSERT_TRUE(helper_library)
55       << "shared library load failed: " << load_error.ToString();
56
57   // TestFunction1() and TestFunction2() each contain two IMMEDIATE_CRASH()
58   // invocations. IMMEDIATE_CRASH() should be treated as a noreturn sequence and
59   // optimized into the function epilogue. The general strategy is to find the
60   // return opcode, then scan the following bytes for the opcodes for two
61   // consecutive IMMEDIATE_CRASH() sequences.
62   void* a =
63       GetFunctionPointerFromNativeLibrary(helper_library, "TestFunction1");
64   ASSERT_TRUE(a);
65   void* b =
66       GetFunctionPointerFromNativeLibrary(helper_library, "TestFunction2");
67   ASSERT_TRUE(b);
68
69 #if defined(ARCH_CPU_X86_FAMILY)
70
71   // X86 opcode reference:
72   // 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
73   span<const uint8_t> function_body =
74       a < b ? make_span(static_cast<const uint8_t*>(a),
75                         static_cast<const uint8_t*>(b))
76             : make_span(static_cast<const uint8_t*>(b),
77                         static_cast<const uint8_t*>(a));
78   SCOPED_TRACE(HexEncode(function_body.data(), function_body.size_bytes()));
79
80   // Look for RETN opcode (0xC3). Note that 0xC3 is a substring of several
81   // other opcodes (VMRESUME, MOVNTI), and can also be encoded as part of an
82   // argument to another opcode. None of these other cases are expected to be
83   // present, so a simple byte scan should be Good Enoughâ„¢.
84   auto it = std::find(function_body.begin(), function_body.end(), 0xC3);
85   ASSERT_NE(function_body.end(), it) << "Failed to find return! ";
86
87   // Look for two IMMEDIATE_CRASH() opcode sequences.
88   for (int i = 0; i < 2; ++i) {
89     // INT 3
90     EXPECT_EQ(0xCC, *++it);
91     // UD2
92     EXPECT_EQ(0x0F, *++it);
93     EXPECT_EQ(0x0B, *++it);
94   }
95
96 #elif defined(ARCH_CPU_ARMEL)
97
98   // Routines loaded from a shared library will have the LSB in the pointer set
99   // if encoded as T32 instructions. The rest of this test assumes T32.
100   ASSERT_TRUE(reinterpret_cast<uintptr_t>(a) & 0x1)
101       << "Expected T32 opcodes but found A32 opcodes instead.";
102   ASSERT_TRUE(reinterpret_cast<uintptr_t>(b) & 0x1)
103       << "Expected T32 opcodes but found A32 opcodes instead.";
104
105   // Mask off the lowest bit.
106   a = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(a) & ~uintptr_t{0x1});
107   b = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(b) & ~uintptr_t{0x1});
108
109   // T32 opcode reference: https://developer.arm.com/docs/ddi0487/latest
110   span<const uint16_t> function_body =
111       a < b ? make_span(static_cast<const uint16_t*>(a),
112                         static_cast<const uint16_t*>(b))
113             : make_span(static_cast<const uint16_t*>(b),
114                         static_cast<const uint16_t*>(a));
115   SCOPED_TRACE(HexEncode(function_body.data(), function_body.size_bytes()));
116
117   // Look for the standard return opcode sequence (BX LR).
118   auto it = std::find(function_body.begin(), function_body.end(), 0x4770);
119   ASSERT_NE(function_body.end(), it) << "Failed to find return! ";
120
121   // Look for two IMMEDIATE_CRASH() opcode sequences.
122   for (int i = 0; i < 2; ++i) {
123     // BKPT #0
124     EXPECT_EQ(0xBE00, *++it);
125     // UDF #0
126     EXPECT_EQ(0xDE00, *++it);
127   }
128
129 #elif defined(ARCH_CPU_ARM64)
130
131   // A64 opcode reference: https://developer.arm.com/docs/ddi0487/latest
132   span<const uint32_t> function_body =
133       a < b ? make_span(static_cast<const uint32_t*>(a),
134                         static_cast<const uint32_t*>(b))
135             : make_span(static_cast<const uint32_t*>(b),
136                         static_cast<const uint32_t*>(a));
137   SCOPED_TRACE(HexEncode(function_body.data(), function_body.size_bytes()));
138
139   // Look for RET. There appears to be multiple valid encodings, so this is
140   // hardcoded to whatever clang currently emits...
141   auto it = std::find(function_body.begin(), function_body.end(), 0XD65F03C0);
142   ASSERT_NE(function_body.end(), it) << "Failed to find return! ";
143
144   // Look for two IMMEDIATE_CRASH() opcode sequences.
145   for (int i = 0; i < 2; ++i) {
146
147 #if defined(OS_WIN)
148
149     // BRK #F000
150     EXPECT_EQ(0XD43E0000, *++it);
151     // BRK #1
152     EXPECT_EQ(0XD4200020, *++it);
153
154 #else
155
156     // BRK #0
157     EXPECT_EQ(0XD4200000, *++it);
158     // HLT #0
159     EXPECT_EQ(0xD4400000, *++it);
160
161 #endif  //  defined(OS_WIN)
162   }
163
164 #endif  // defined(ARCH_CPU_X86_FAMILY)
165
166   UnloadNativeLibrary(helper_library);
167 }
168
169 #endif
170
171 }  // namespace base