blob: 98c30df47de4aa3a7354d0e15bbb111e039e75d3 [file] [log] [blame]
rsleevi@chromium.orgde3a6cf2012-04-06 12:53:02 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
glider@chromium.org0f9756f2009-12-17 21:37:58 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
glider@chromium.org71a6e932011-10-05 22:22:50 +09004//
5// This file contains intentional memory errors, some of which may lead to
6// crashes if the test is ran without special memory testing tools. We use these
7// errors to verify the sanity of the tools.
glider@chromium.org0f9756f2009-12-17 21:37:58 +09008
avia6a6a682015-12-27 07:15:14 +09009#include <stddef.h>
10
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +090011#include "base/atomicops.h"
Scott Violet04992cc2018-02-22 11:08:08 +090012#include "base/cfi_buildflags.h"
sebmarchand@chromium.orgd117d7a2014-06-14 17:29:37 +090013#include "base/debug/asan_invalid_access.h"
14#include "base/debug/profiler.h"
timurrrr@chromium.orgf39c3ff2010-05-14 17:24:42 +090015#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
brettw@chromium.org5b5f5e02011-01-01 10:01:06 +090016#include "base/threading/thread.h"
avia6a6a682015-12-27 07:15:14 +090017#include "build/build_config.h"
glider@chromium.org0f9756f2009-12-17 21:37:58 +090018#include "testing/gtest/include/gtest/gtest.h"
19
brettw@chromium.org61391822011-01-01 05:02:16 +090020namespace base {
21
glider@chromium.org0f9756f2009-12-17 21:37:58 +090022namespace {
23
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +090024const base::subtle::Atomic32 kMagicValue = 42;
glider@chromium.org0f9756f2009-12-17 21:37:58 +090025
glider@chromium.org71a6e932011-10-05 22:22:50 +090026// Helper for memory accesses that can potentially corrupt memory or cause a
27// crash during a native run.
Sigurdur Asgeirsson0fa54ec2018-03-30 06:50:51 +090028#if defined(ADDRESS_SANITIZER)
glider@chromium.orga3b3c432012-10-24 23:11:02 +090029#if defined(OS_IOS)
30// EXPECT_DEATH is not supported on IOS.
31#define HARMFUL_ACCESS(action,error_regexp) do { action; } while (0)
32#else
glider@chromium.org71a6e932011-10-05 22:22:50 +090033#define HARMFUL_ACCESS(action,error_regexp) EXPECT_DEATH(action,error_regexp)
Sigurdur Asgeirsson0fa54ec2018-03-30 06:50:51 +090034#endif // !OS_IOS
glider@chromium.org71a6e932011-10-05 22:22:50 +090035#else
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +090036#define HARMFUL_ACCESS(action, error_regexp)
37#define HARMFUL_ACCESS_IS_NOOP
glider@chromium.org71a6e932011-10-05 22:22:50 +090038#endif
39
earthdok@chromium.org5a5e4652014-01-16 14:31:41 +090040void DoReadUninitializedValue(char *ptr) {
eugenis@google.com7634fc52012-05-16 17:42:08 +090041 // Comparison with 64 is to prevent clang from optimizing away the
thakis@chromium.org987f8332011-09-19 01:39:12 +090042 // jump -- valgrind only catches jumps and conditional moves, but clang uses
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +090043 // the borrow flag if the condition is just `*ptr == '\0'`. We no longer
44 // support valgrind, but this constant should be fine to keep as-is.
eugenis@google.com7634fc52012-05-16 17:42:08 +090045 if (*ptr == 64) {
earthdok@chromium.org5a5e4652014-01-16 14:31:41 +090046 VLOG(1) << "Uninit condition is true";
timurrrr@chromium.org46315442010-09-23 18:12:37 +090047 } else {
earthdok@chromium.org5a5e4652014-01-16 14:31:41 +090048 VLOG(1) << "Uninit condition is false";
timurrrr@chromium.org46315442010-09-23 18:12:37 +090049 }
50}
51
earthdok@chromium.org5a5e4652014-01-16 14:31:41 +090052void ReadUninitializedValue(char *ptr) {
53#if defined(MEMORY_SANITIZER)
54 EXPECT_DEATH(DoReadUninitializedValue(ptr),
55 "use-of-uninitialized-value");
56#else
57 DoReadUninitializedValue(ptr);
58#endif
59}
60
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +090061#ifndef HARMFUL_ACCESS_IS_NOOP
timurrrr@chromium.org4597f342010-03-26 21:54:44 +090062void ReadValueOutOfArrayBoundsLeft(char *ptr) {
pkasting@chromium.org4baea272010-10-19 08:57:49 +090063 char c = ptr[-2];
64 VLOG(1) << "Reading a byte out of bounds: " << c;
timurrrr@chromium.org4597f342010-03-26 21:54:44 +090065}
66
67void ReadValueOutOfArrayBoundsRight(char *ptr, size_t size) {
pkasting@chromium.org4baea272010-10-19 08:57:49 +090068 char c = ptr[size + 1];
69 VLOG(1) << "Reading a byte out of bounds: " << c;
timurrrr@chromium.org4597f342010-03-26 21:54:44 +090070}
71
timurrrr@chromium.org4597f342010-03-26 21:54:44 +090072void WriteValueOutOfArrayBoundsLeft(char *ptr) {
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +090073 ptr[-1] = kMagicValue;
timurrrr@chromium.org4597f342010-03-26 21:54:44 +090074}
75
timurrrr@chromium.org4597f342010-03-26 21:54:44 +090076void WriteValueOutOfArrayBoundsRight(char *ptr, size_t size) {
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +090077 ptr[size] = kMagicValue;
timurrrr@chromium.org4597f342010-03-26 21:54:44 +090078}
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +090079#endif // HARMFUL_ACCESS_IS_NOOP
timurrrr@chromium.org4597f342010-03-26 21:54:44 +090080
81void MakeSomeErrors(char *ptr, size_t size) {
timurrrr@chromium.org46315442010-09-23 18:12:37 +090082 ReadUninitializedValue(ptr);
mithro@mithis.com62c72272013-12-18 14:31:33 +090083
glider@chromium.org71a6e932011-10-05 22:22:50 +090084 HARMFUL_ACCESS(ReadValueOutOfArrayBoundsLeft(ptr),
mithro@mithis.com62c72272013-12-18 14:31:33 +090085 "2 bytes to the left");
glider@chromium.org71a6e932011-10-05 22:22:50 +090086 HARMFUL_ACCESS(ReadValueOutOfArrayBoundsRight(ptr, size),
mithro@mithis.com62c72272013-12-18 14:31:33 +090087 "1 bytes to the right");
glider@chromium.org71a6e932011-10-05 22:22:50 +090088 HARMFUL_ACCESS(WriteValueOutOfArrayBoundsLeft(ptr),
mithro@mithis.com62c72272013-12-18 14:31:33 +090089 "1 bytes to the left");
glider@chromium.org71a6e932011-10-05 22:22:50 +090090 HARMFUL_ACCESS(WriteValueOutOfArrayBoundsRight(ptr, size),
mithro@mithis.com62c72272013-12-18 14:31:33 +090091 "0 bytes to the right");
timurrrr@chromium.org4597f342010-03-26 21:54:44 +090092}
93
glider@chromium.orgb311fbc2010-10-14 17:25:54 +090094} // namespace
95
96// A memory leak detector should report an error in this test.
97TEST(ToolsSanityTest, MemoryLeak) {
thakis@chromium.org1a3c5d12011-11-01 20:08:09 +090098 // Without the |volatile|, clang optimizes away the next two lines.
99 int* volatile leak = new int[256]; // Leak some memory intentionally.
glider@chromium.orgb311fbc2010-10-14 17:25:54 +0900100 leak[4] = 1; // Make sure the allocated memory is used.
101}
102
Sigurdur Asgeirsson0fa54ec2018-03-30 06:50:51 +0900103#if (defined(ADDRESS_SANITIZER) && defined(OS_IOS))
glider@chromium.orga3b3c432012-10-24 23:11:02 +0900104// Because iOS doesn't support death tests, each of the following tests will
Sigurdur Asgeirsson0fa54ec2018-03-30 06:50:51 +0900105// crash the whole program under Asan.
glider@chromium.orga3b3c432012-10-24 23:11:02 +0900106#define MAYBE_AccessesToNewMemory DISABLED_AccessesToNewMemory
107#define MAYBE_AccessesToMallocMemory DISABLED_AccessesToMallocMemory
glider@chromium.org738e89d2014-05-14 20:50:37 +0900108#else
109#define MAYBE_AccessesToNewMemory AccessesToNewMemory
110#define MAYBE_AccessesToMallocMemory AccessesToMallocMemory
Sigurdur Asgeirsson0fa54ec2018-03-30 06:50:51 +0900111#endif // (defined(ADDRESS_SANITIZER) && defined(OS_IOS))
glider@chromium.orge43d0062014-05-15 01:04:30 +0900112
113// The following tests pass with Clang r170392, but not r172454, which
114// makes AddressSanitizer detect errors in them. We disable these tests under
115// AddressSanitizer until we fully switch to Clang r172454. After that the
116// tests should be put back under the (defined(OS_IOS) || defined(OS_WIN))
117// clause above.
118// See also http://crbug.com/172614.
Sigurdur Asgeirsson0fa54ec2018-03-30 06:50:51 +0900119#if defined(ADDRESS_SANITIZER)
glider@chromium.org738e89d2014-05-14 20:50:37 +0900120#define MAYBE_SingleElementDeletedWithBraces \
121 DISABLED_SingleElementDeletedWithBraces
glider@chromium.orge43d0062014-05-15 01:04:30 +0900122#define MAYBE_ArrayDeletedWithoutBraces DISABLED_ArrayDeletedWithoutBraces
tzik@chromium.orgf65e67e2014-07-18 11:40:40 +0900123#else
124#define MAYBE_ArrayDeletedWithoutBraces ArrayDeletedWithoutBraces
125#define MAYBE_SingleElementDeletedWithBraces SingleElementDeletedWithBraces
Sigurdur Asgeirsson0fa54ec2018-03-30 06:50:51 +0900126#endif // defined(ADDRESS_SANITIZER)
tzik@chromium.orgf65e67e2014-07-18 11:40:40 +0900127
glider@chromium.orga3b3c432012-10-24 23:11:02 +0900128TEST(ToolsSanityTest, MAYBE_AccessesToNewMemory) {
timurrrr@chromium.org4597f342010-03-26 21:54:44 +0900129 char *foo = new char[10];
130 MakeSomeErrors(foo, 10);
131 delete [] foo;
glider@chromium.org71a6e932011-10-05 22:22:50 +0900132 // Use after delete.
133 HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free");
timurrrr@chromium.org4597f342010-03-26 21:54:44 +0900134}
135
glider@chromium.orga3b3c432012-10-24 23:11:02 +0900136TEST(ToolsSanityTest, MAYBE_AccessesToMallocMemory) {
timurrrr@chromium.org4597f342010-03-26 21:54:44 +0900137 char *foo = reinterpret_cast<char*>(malloc(10));
138 MakeSomeErrors(foo, 10);
139 free(foo);
glider@chromium.org71a6e932011-10-05 22:22:50 +0900140 // Use after free.
141 HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free");
timurrrr@chromium.org4597f342010-03-26 21:54:44 +0900142}
143
Sigurdur Asgeirsson0fa54ec2018-03-30 06:50:51 +0900144#if defined(ADDRESS_SANITIZER)
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +0900145
hanse03e7f72015-05-20 02:03:14 +0900146static int* allocateArray() {
147 // Clang warns about the mismatched new[]/delete if they occur in the same
148 // function.
149 return new int[10];
150}
151
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +0900152// This test may corrupt memory if not compiled with AddressSanitizer.
glider@chromium.orga3b3c432012-10-24 23:11:02 +0900153TEST(ToolsSanityTest, MAYBE_ArrayDeletedWithoutBraces) {
thakis@chromium.orgc3846f82011-09-19 01:30:12 +0900154 // Without the |volatile|, clang optimizes away the next two lines.
hanse03e7f72015-05-20 02:03:14 +0900155 int* volatile foo = allocateArray();
glider@chromium.orge43d0062014-05-15 01:04:30 +0900156 delete foo;
timurrrr@chromium.org4597f342010-03-26 21:54:44 +0900157}
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +0900158#endif
timurrrr@chromium.org4597f342010-03-26 21:54:44 +0900159
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +0900160#if defined(ADDRESS_SANITIZER)
hanse03e7f72015-05-20 02:03:14 +0900161static int* allocateScalar() {
162 // Clang warns about the mismatched new/delete[] if they occur in the same
163 // function.
164 return new int;
165}
166
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +0900167// This test may corrupt memory if not compiled with AddressSanitizer.
glider@chromium.orga3b3c432012-10-24 23:11:02 +0900168TEST(ToolsSanityTest, MAYBE_SingleElementDeletedWithBraces) {
thakis@chromium.orgc3846f82011-09-19 01:30:12 +0900169 // Without the |volatile|, clang optimizes away the next two lines.
hanse03e7f72015-05-20 02:03:14 +0900170 int* volatile foo = allocateScalar();
pph34r@gmail.com80271292011-10-01 03:52:04 +0900171 (void) foo;
glider@chromium.orge43d0062014-05-15 01:04:30 +0900172 delete [] foo;
timurrrr@chromium.org4597f342010-03-26 21:54:44 +0900173}
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +0900174#endif
timurrrr@chromium.org4597f342010-03-26 21:54:44 +0900175
Sigurdur Asgeirsson0fa54ec2018-03-30 06:50:51 +0900176#if defined(ADDRESS_SANITIZER)
sebmarchand@chromium.orgd117d7a2014-06-14 17:29:37 +0900177
glider@chromium.org4b5cd882011-11-08 18:28:49 +0900178TEST(ToolsSanityTest, DISABLED_AddressSanitizerNullDerefCrashTest) {
glider@chromium.org2fa52d02011-10-13 02:18:24 +0900179 // Intentionally crash to make sure AddressSanitizer is running.
180 // This test should not be ran on bots.
181 int* volatile zero = NULL;
182 *zero = 0;
183}
glider@chromium.org4b5cd882011-11-08 18:28:49 +0900184
185TEST(ToolsSanityTest, DISABLED_AddressSanitizerLocalOOBCrashTest) {
186 // Intentionally crash to make sure AddressSanitizer is instrumenting
187 // the local variables.
188 // This test should not be ran on bots.
189 int array[5];
190 // Work around the OOB warning reported by Clang.
191 int* volatile access = &array[5];
192 *access = 43;
193}
194
195namespace {
196int g_asan_test_global_array[10];
197} // namespace
198
199TEST(ToolsSanityTest, DISABLED_AddressSanitizerGlobalOOBCrashTest) {
200 // Intentionally crash to make sure AddressSanitizer is instrumenting
201 // the global variables.
202 // This test should not be ran on bots.
203
204 // Work around the OOB warning reported by Clang.
205 int* volatile access = g_asan_test_global_array - 1;
206 *access = 43;
207}
208
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +0900209#ifndef HARMFUL_ACCESS_IS_NOOP
sebmarchand@chromium.orgd117d7a2014-06-14 17:29:37 +0900210TEST(ToolsSanityTest, AsanHeapOverflow) {
211 HARMFUL_ACCESS(debug::AsanHeapOverflow() ,"to the right");
212}
213
214TEST(ToolsSanityTest, AsanHeapUnderflow) {
215 HARMFUL_ACCESS(debug::AsanHeapUnderflow(), "to the left");
216}
217
218TEST(ToolsSanityTest, AsanHeapUseAfterFree) {
219 HARMFUL_ACCESS(debug::AsanHeapUseAfterFree(), "heap-use-after-free");
220}
221
Sigurdur Asgeirsson0fa54ec2018-03-30 06:50:51 +0900222#if defined(OS_WIN)
Sigurdur Asgeirssonad07f722018-04-05 00:44:04 +0900223// The ASAN runtime doesn't detect heap corruption, this needs fixing before
224// ASAN builds can ship to the wild. See https://crbug.com/818747.
225TEST(ToolsSanityTest, DISABLED_AsanCorruptHeapBlock) {
sebmarchand@chromium.orgd117d7a2014-06-14 17:29:37 +0900226 HARMFUL_ACCESS(debug::AsanCorruptHeapBlock(), "");
227}
228
Sigurdur Asgeirssonad07f722018-04-05 00:44:04 +0900229TEST(ToolsSanityTest, DISABLED_AsanCorruptHeap) {
sebmarchand@chromium.orgd117d7a2014-06-14 17:29:37 +0900230 // This test will kill the process by raising an exception, there's no
231 // particular string to look for in the stack trace.
232 EXPECT_DEATH(debug::AsanCorruptHeap(), "");
233}
Sigurdur Asgeirsson0fa54ec2018-03-30 06:50:51 +0900234#endif // OS_WIN
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +0900235#endif // !HARMFUL_ACCESS_IS_NOOP
sebmarchand@chromium.orgd117d7a2014-06-14 17:29:37 +0900236
Sigurdur Asgeirsson0fa54ec2018-03-30 06:50:51 +0900237#endif // ADDRESS_SANITIZER
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +0900238
239namespace {
240
241// We use caps here just to ensure that the method name doesn't interfere with
242// the wildcarded suppressions.
243class TOOLS_SANITY_TEST_CONCURRENT_THREAD : public PlatformThread::Delegate {
244 public:
245 explicit TOOLS_SANITY_TEST_CONCURRENT_THREAD(bool *value) : value_(value) {}
Chris Watkinsd155d9f2017-11-29 16:16:38 +0900246 ~TOOLS_SANITY_TEST_CONCURRENT_THREAD() override = default;
dcheng7dc8df52014-10-21 19:54:51 +0900247 void ThreadMain() override {
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +0900248 *value_ = true;
249
250 // Sleep for a few milliseconds so the two threads are more likely to live
251 // simultaneously. Otherwise we may miss the report due to mutex
252 // lock/unlock's inside thread creation code in pure-happens-before mode...
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900253 PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +0900254 }
255 private:
256 bool *value_;
257};
258
259class ReleaseStoreThread : public PlatformThread::Delegate {
260 public:
261 explicit ReleaseStoreThread(base::subtle::Atomic32 *value) : value_(value) {}
Chris Watkinsd155d9f2017-11-29 16:16:38 +0900262 ~ReleaseStoreThread() override = default;
dcheng7dc8df52014-10-21 19:54:51 +0900263 void ThreadMain() override {
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +0900264 base::subtle::Release_Store(value_, kMagicValue);
265
266 // Sleep for a few milliseconds so the two threads are more likely to live
267 // simultaneously. Otherwise we may miss the report due to mutex
268 // lock/unlock's inside thread creation code in pure-happens-before mode...
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900269 PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +0900270 }
271 private:
272 base::subtle::Atomic32 *value_;
273};
274
275class AcquireLoadThread : public PlatformThread::Delegate {
276 public:
277 explicit AcquireLoadThread(base::subtle::Atomic32 *value) : value_(value) {}
Chris Watkinsd155d9f2017-11-29 16:16:38 +0900278 ~AcquireLoadThread() override = default;
dcheng7dc8df52014-10-21 19:54:51 +0900279 void ThreadMain() override {
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +0900280 // Wait for the other thread to make Release_Store
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900281 PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +0900282 base::subtle::Acquire_Load(value_);
283 }
284 private:
285 base::subtle::Atomic32 *value_;
286};
287
288void RunInParallel(PlatformThread::Delegate *d1, PlatformThread::Delegate *d2) {
289 PlatformThreadHandle a;
290 PlatformThreadHandle b;
291 PlatformThread::Create(0, d1, &a);
292 PlatformThread::Create(0, d2, &b);
293 PlatformThread::Join(a);
294 PlatformThread::Join(b);
295}
296
glider@chromium.orgc75e1372014-06-26 22:10:50 +0900297#if defined(THREAD_SANITIZER)
298void DataRace() {
glider@chromium.org7bb5ece2013-03-23 20:28:17 +0900299 bool *shared = new bool(false);
300 TOOLS_SANITY_TEST_CONCURRENT_THREAD thread1(shared), thread2(shared);
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +0900301 RunInParallel(&thread1, &thread2);
glider@chromium.org7bb5ece2013-03-23 20:28:17 +0900302 EXPECT_TRUE(*shared);
303 delete shared;
glider@chromium.orgc75e1372014-06-26 22:10:50 +0900304 // We're in a death test - crash.
305 CHECK(0);
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +0900306}
glider@chromium.orgc75e1372014-06-26 22:10:50 +0900307#endif
308
309} // namespace
310
311#if defined(THREAD_SANITIZER)
312// A data race detector should report an error in this test.
313TEST(ToolsSanityTest, DataRace) {
314 // The suppression regexp must match that in base/debug/tsan_suppressions.cc.
315 EXPECT_DEATH(DataRace(), "1 race:base/tools_sanity_unittest.cc");
316}
317#endif
timurrrr@chromium.orgb1d5c022011-05-11 03:03:34 +0900318
319TEST(ToolsSanityTest, AnnotateBenignRace) {
320 bool shared = false;
321 ANNOTATE_BENIGN_RACE(&shared, "Intentional race - make sure doesn't show up");
322 TOOLS_SANITY_TEST_CONCURRENT_THREAD thread1(&shared), thread2(&shared);
323 RunInParallel(&thread1, &thread2);
324 EXPECT_TRUE(shared);
325}
326
327TEST(ToolsSanityTest, AtomicsAreIgnored) {
328 base::subtle::Atomic32 shared = 0;
329 ReleaseStoreThread thread1(&shared);
330 AcquireLoadThread thread2(&shared);
331 RunInParallel(&thread1, &thread2);
332 EXPECT_EQ(kMagicValue, shared);
glider@chromium.org0f9756f2009-12-17 21:37:58 +0900333}
brettw@chromium.org61391822011-01-01 05:02:16 +0900334
Vlad Tsyrklevichca1cd2f2017-10-14 04:35:24 +0900335#if BUILDFLAG(CFI_ENFORCEMENT_TRAP)
Peter Collingbourne473708a2017-10-13 04:51:27 +0900336#if defined(OS_WIN)
337#define CFI_ERROR_MSG "EXCEPTION_ILLEGAL_INSTRUCTION"
338#elif defined(OS_ANDROID)
339// TODO(pcc): Produce proper stack dumps on Android and test for the correct
340// si_code here.
341#define CFI_ERROR_MSG "^$"
342#else
Vlad Tsyrklevichee84f432017-08-16 08:45:10 +0900343#define CFI_ERROR_MSG "ILL_ILLOPN"
Peter Collingbourne473708a2017-10-13 04:51:27 +0900344#endif
Vlad Tsyrklevichca1cd2f2017-10-14 04:35:24 +0900345#elif BUILDFLAG(CFI_ENFORCEMENT_DIAGNOSTIC)
Vlad Tsyrklevichee84f432017-08-16 08:45:10 +0900346#define CFI_ERROR_MSG "runtime error: control flow integrity check"
Vlad Tsyrklevichca1cd2f2017-10-14 04:35:24 +0900347#endif // BUILDFLAG(CFI_ENFORCEMENT_TRAP || CFI_ENFORCEMENT_DIAGNOSTIC)
pcc85bb7552015-07-31 09:19:06 +0900348
Vlad Tsyrklevichee84f432017-08-16 08:45:10 +0900349#if defined(CFI_ERROR_MSG)
krasind7c57c32016-07-13 12:24:34 +0900350class A {
351 public:
352 A(): n_(0) {}
353 virtual void f() { n_++; }
354 protected:
355 int n_;
356};
357
358class B: public A {
359 public:
360 void f() override { n_--; }
361};
362
Vlad Tsyrklevichee84f432017-08-16 08:45:10 +0900363class C: public B {
364 public:
365 void f() override { n_ += 2; }
366};
367
krasind7c57c32016-07-13 12:24:34 +0900368NOINLINE void KillVptrAndCall(A *obj) {
369 *reinterpret_cast<void **>(obj) = 0;
370 obj->f();
371}
372
Vlad Tsyrklevichee84f432017-08-16 08:45:10 +0900373TEST(ToolsSanityTest, BadVirtualCallNull) {
krasind7c57c32016-07-13 12:24:34 +0900374 A a;
375 B b;
Vlad Tsyrklevichee84f432017-08-16 08:45:10 +0900376 EXPECT_DEATH({ KillVptrAndCall(&a); KillVptrAndCall(&b); }, CFI_ERROR_MSG);
krasind7c57c32016-07-13 12:24:34 +0900377}
378
Vlad Tsyrklevichee84f432017-08-16 08:45:10 +0900379NOINLINE void OverwriteVptrAndCall(B *obj, A *vptr) {
380 *reinterpret_cast<void **>(obj) = *reinterpret_cast<void **>(vptr);
381 obj->f();
382}
383
384TEST(ToolsSanityTest, BadVirtualCallWrongType) {
385 A a;
386 B b;
387 C c;
388 EXPECT_DEATH({ OverwriteVptrAndCall(&b, &a); OverwriteVptrAndCall(&b, &c); },
389 CFI_ERROR_MSG);
390}
391
392// TODO(pcc): remove CFI_CAST_CHECK, see https://crbug.com/626794.
Vlad Tsyrklevichca1cd2f2017-10-14 04:35:24 +0900393#if BUILDFLAG(CFI_CAST_CHECK)
Vlad Tsyrklevichee84f432017-08-16 08:45:10 +0900394TEST(ToolsSanityTest, BadDerivedCast) {
395 A a;
396 EXPECT_DEATH((void)(B*)&a, CFI_ERROR_MSG);
397}
398
399TEST(ToolsSanityTest, BadUnrelatedCast) {
400 class A {
401 virtual void f() {}
402 };
403
404 class B {
405 virtual void f() {}
406 };
407
408 A a;
409 EXPECT_DEATH((void)(B*)&a, CFI_ERROR_MSG);
410}
Vlad Tsyrklevichca1cd2f2017-10-14 04:35:24 +0900411#endif // BUILDFLAG(CFI_CAST_CHECK)
Vlad Tsyrklevichee84f432017-08-16 08:45:10 +0900412
Vlad Tsyrklevichca1cd2f2017-10-14 04:35:24 +0900413#endif // CFI_ERROR_MSG
pcc85bb7552015-07-31 09:19:06 +0900414
Mostyn Bramley-Moorecd7f8272017-12-07 04:13:21 +0900415#undef CFI_ERROR_MSG
416#undef MAYBE_AccessesToNewMemory
417#undef MAYBE_AccessesToMallocMemory
418#undef MAYBE_ArrayDeletedWithoutBraces
419#undef MAYBE_SingleElementDeletedWithBraces
420#undef HARMFUL_ACCESS
421#undef HARMFUL_ACCESS_IS_NOOP
422
brettw@chromium.org61391822011-01-01 05:02:16 +0900423} // namespace base