1 //===- llvm/unittest/Support/CrashRecoveryTest.cpp ------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/Support/Compiler.h"
10 #include "llvm/Support/CrashRecoveryContext.h"
11 #include "gtest/gtest.h"
12 
13 #ifdef _WIN32
14 #define WIN32_LEAN_AND_MEAN
15 #define NOGDI
16 #include <windows.h>
17 #endif
18 
19 using namespace llvm;
20 using namespace llvm::sys;
21 
22 static int GlobalInt = 0;
23 static void nullDeref() { *(volatile int *)0x10 = 0; }
24 static void incrementGlobal() { ++GlobalInt; }
25 static void llvmTrap() { LLVM_BUILTIN_TRAP; }
26 
27 TEST(CrashRecoveryTest, Basic) {
28   llvm::CrashRecoveryContext::Enable();
29   GlobalInt = 0;
30   EXPECT_TRUE(CrashRecoveryContext().RunSafely(incrementGlobal));
31   EXPECT_EQ(1, GlobalInt);
32   EXPECT_FALSE(CrashRecoveryContext().RunSafely(nullDeref));
33   EXPECT_FALSE(CrashRecoveryContext().RunSafely(llvmTrap));
34 }
35 
36 struct IncrementGlobalCleanup : CrashRecoveryContextCleanup {
37   IncrementGlobalCleanup(CrashRecoveryContext *CRC)
38       : CrashRecoveryContextCleanup(CRC) {}
39   virtual void recoverResources() { ++GlobalInt; }
40 };
41 
42 static void noop() {}
43 
44 TEST(CrashRecoveryTest, Cleanup) {
45   llvm::CrashRecoveryContext::Enable();
46   GlobalInt = 0;
47   {
48     CrashRecoveryContext CRC;
49     CRC.registerCleanup(new IncrementGlobalCleanup(&CRC));
50     EXPECT_TRUE(CRC.RunSafely(noop));
51   } // run cleanups
52   EXPECT_EQ(1, GlobalInt);
53 
54   GlobalInt = 0;
55   {
56     CrashRecoveryContext CRC;
57     CRC.registerCleanup(new IncrementGlobalCleanup(&CRC));
58     EXPECT_FALSE(CRC.RunSafely(nullDeref));
59   } // run cleanups
60   EXPECT_EQ(1, GlobalInt);
61 }
62 
63 #ifdef _WIN32
64 static void raiseIt() {
65   RaiseException(123, EXCEPTION_NONCONTINUABLE, 0, NULL);
66 }
67 
68 TEST(CrashRecoveryTest, RaiseException) {
69   llvm::CrashRecoveryContext::Enable();
70   EXPECT_FALSE(CrashRecoveryContext().RunSafely(raiseIt));
71 }
72 
73 static void outputString() {
74   OutputDebugStringA("output for debugger\n");
75 }
76 
77 TEST(CrashRecoveryTest, CallOutputDebugString) {
78   llvm::CrashRecoveryContext::Enable();
79   EXPECT_TRUE(CrashRecoveryContext().RunSafely(outputString));
80 }
81 
82 #endif
83