Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(41)

Side by Side Diff: chrome/browser/mac/exception_processor_unittest.mm

Issue 2543813003: [Mac] Modify the ObjC exception preprocessor to make some exceptions fatal. (Closed)
Patch Set: Address comments Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/mac/exception_processor.mm ('k') | chrome/test/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "chrome/browser/chrome_browser_application_mac.h" 5 #import "chrome/browser/mac/exception_processor.h"
6 6
7 #import <Cocoa/Cocoa.h> 7 #import <Cocoa/Cocoa.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <sys/wait.h>
9 10
10 #include <memory> 11 #include "base/mac/os_crash_dumps.h"
11
12 #include "base/metrics/histogram_macros.h" 12 #include "base/metrics/histogram_macros.h"
13 #include "base/metrics/histogram_samples.h" 13 #include "base/metrics/histogram_samples.h"
14 #include "base/metrics/statistics_recorder.h" 14 #include "base/metrics/statistics_recorder.h"
15 #include "testing/gtest/include/gtest/gtest.h" 15 #include "testing/gtest/include/gtest/gtest.h"
16 16
17 using base::HistogramBase; 17 using base::HistogramBase;
18 using base::HistogramSamples; 18 using base::HistogramSamples;
19 using base::StatisticsRecorder; 19 using base::StatisticsRecorder;
20 20
21 namespace chrome_browser_application_mac { 21 namespace chrome {
22 22
23 // Generate an NSException with the given name. 23 // Generate an NSException with the given name.
24 NSException* ExceptionNamed(NSString* name) { 24 NSException* ExceptionNamed(NSString* name) {
25 return [NSException exceptionWithName:name 25 return [NSException exceptionWithName:name
26 reason:@"No reason given" 26 reason:@"No reason given"
27 userInfo:nil]; 27 userInfo:nil];
28 } 28 }
29 29
30 // Helper to keep binning expectations readible. 30 // Helper to keep binning expectations readible.
31 size_t BinForExceptionNamed(NSString* name) { 31 size_t BinForExceptionNamed(NSString* name) {
32 return BinForException(ExceptionNamed(name)); 32 return BinForException(ExceptionNamed(name));
33 } 33 }
34 34
35 TEST(ChromeApplicationMacTest, ExceptionBinning) { 35 TEST(ExceptionProcessorTest, ExceptionBinning) {
36 // These exceptions must be in this order. 36 // These exceptions must be in this order.
37 EXPECT_EQ(BinForExceptionNamed(NSGenericException), 0U); 37 EXPECT_EQ(BinForExceptionNamed(NSGenericException), 0U);
38 EXPECT_EQ(BinForExceptionNamed(NSRangeException), 1U); 38 EXPECT_EQ(BinForExceptionNamed(NSRangeException), 1U);
39 EXPECT_EQ(BinForExceptionNamed(NSInvalidArgumentException), 2U); 39 EXPECT_EQ(BinForExceptionNamed(NSInvalidArgumentException), 2U);
40 EXPECT_EQ(BinForExceptionNamed(NSMallocException), 3U); 40 EXPECT_EQ(BinForExceptionNamed(NSMallocException), 3U);
41 41
42 // Random other exceptions map to |kUnknownNSException|. 42 // Random other exceptions map to |kUnknownNSException|.
43 EXPECT_EQ(BinForExceptionNamed(@"CustomName"), kUnknownNSException); 43 EXPECT_EQ(BinForExceptionNamed(@"CustomName"), kUnknownNSException);
44 EXPECT_EQ(BinForExceptionNamed(@"Custom Name"), kUnknownNSException); 44 EXPECT_EQ(BinForExceptionNamed(@"Custom Name"), kUnknownNSException);
45 EXPECT_EQ(BinForExceptionNamed(@""), kUnknownNSException); 45 EXPECT_EQ(BinForExceptionNamed(@""), kUnknownNSException);
46 EXPECT_EQ(BinForException(nil), kUnknownNSException); 46 EXPECT_EQ(BinForException(nil), kUnknownNSException);
47 } 47 }
48 48
49 TEST(ChromeApplicationMacTest, RecordException) { 49 TEST(ExceptionProcessorTest, RecordException) {
50 // Start up a histogram recorder. 50 // Start up a histogram recorder.
51 // TODO(rtenneti): Leaks StatisticsRecorder and will update suppressions. 51 // TODO(rtenneti): Leaks StatisticsRecorder and will update suppressions.
52 base::StatisticsRecorder::Initialize(); 52 base::StatisticsRecorder::Initialize();
53 53
54 StatisticsRecorder::Histograms histograms; 54 StatisticsRecorder::Histograms histograms;
55 StatisticsRecorder::GetSnapshot("OSX.NSException", &histograms); 55 StatisticsRecorder::GetSnapshot("OSX.NSException", &histograms);
56 EXPECT_EQ(0U, histograms.size()); 56 EXPECT_EQ(0U, histograms.size());
57 57
58 // Record some known exceptions. 58 // Record some known exceptions.
59 RecordExceptionWithUma(ExceptionNamed(NSGenericException)); 59 RecordExceptionWithUma(ExceptionNamed(NSGenericException));
(...skipping 24 matching lines...) Expand all
84 EXPECT_EQ(3, samples->GetCount(2)); 84 EXPECT_EQ(3, samples->GetCount(2));
85 EXPECT_EQ(2, samples->GetCount(3)); 85 EXPECT_EQ(2, samples->GetCount(3));
86 86
87 // The unknown exceptions should end up in the overflow bucket. 87 // The unknown exceptions should end up in the overflow bucket.
88 EXPECT_TRUE(histograms[0]->HasConstructionArguments(1, 88 EXPECT_TRUE(histograms[0]->HasConstructionArguments(1,
89 kUnknownNSException, 89 kUnknownNSException,
90 kUnknownNSException + 1)); 90 kUnknownNSException + 1));
91 EXPECT_EQ(4, samples->GetCount(kUnknownNSException)); 91 EXPECT_EQ(4, samples->GetCount(kUnknownNSException));
92 } 92 }
93 93
94 } // chrome_browser_application_mac 94 void RaiseExceptionInRunLoop() {
95 CFRunLoopRef run_loop = CFRunLoopGetCurrent();
96
97 CFRunLoopPerformBlock(run_loop, kCFRunLoopCommonModes, ^{
98 [NSException raise:@"ThrowExceptionInRunLoop" format:nil];
99 });
100 CFRunLoopPerformBlock(run_loop, kCFRunLoopCommonModes, ^{
101 CFRunLoopStop(run_loop);
102 });
103 CFRunLoopRun();
104 }
105
106 void ThrowExceptionInRunLoop() {
107 base::mac::DisableOSCrashDumps();
108 chrome::InstallObjcExceptionPreprocessor();
109
110 RaiseExceptionInRunLoop();
111
112 fprintf(stderr, "TEST FAILED\n");
113 exit(1);
114 }
115
116 // Tests that when the preprocessor is installed, exceptions thrown from
117 // a runloop callout are made fatal, so that the stack trace is useful.
118 TEST(ExceptionProcessorTest, ThrowExceptionInRunLoop) {
119 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
120 EXPECT_DEATH(ThrowExceptionInRunLoop(),
121 ".*FATAL:exception_processor\\.mm.*"
122 "Terminating from Objective-C exception:.*");
123 }
124
125 void ThrowAndCatchExceptionInRunLoop() {
126 base::mac::DisableOSCrashDumps();
127 chrome::InstallObjcExceptionPreprocessor();
128
129 CFRunLoopRef run_loop = CFRunLoopGetCurrent();
130 CFRunLoopPerformBlock(run_loop, kCFRunLoopCommonModes, ^{
131 @try {
132 [NSException raise:@"ObjcExceptionPreprocessCaught" format:nil];
133 } @catch (id exception) {
134 }
135 });
136
137 CFRunLoopPerformBlock(run_loop, kCFRunLoopCommonModes, ^{
138 CFRunLoopStop(run_loop);
139 });
140
141 CFRunLoopRun();
142
143 fprintf(stderr, "TEST PASS\n");
144 exit(0);
145 }
146
147 // Tests that exceptions can still be caught when the preprocessor is enabled.
148 TEST(ExceptionProcessorTest, ThrowAndCatchExceptionInRunLoop) {
149 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
150 EXPECT_EXIT(ThrowAndCatchExceptionInRunLoop(),
151 [](int exit_code) -> bool {
152 return WEXITSTATUS(exit_code) == 0;
153 },
154 ".*TEST PASS.*");
155 }
156
157 void ThrowExceptionInRunLoopWithoutProcessor() {
158 base::mac::DisableOSCrashDumps();
159 chrome::UninstallObjcExceptionPreprocessor();
160
161 @try {
162 RaiseExceptionInRunLoop();
163 } @catch (id exception) {
164 fprintf(stderr, "TEST PASS\n");
165 exit(0);
166 }
167
168 fprintf(stderr, "TEST FAILED\n");
169 exit(1);
170 }
171
172 // Tests basic exception handling when the preprocessor is disabled.
173 TEST(ExceptionProcessorTest, ThrowExceptionInRunLoopWithoutProcessor) {
174 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
175 EXPECT_EXIT(ThrowExceptionInRunLoopWithoutProcessor(),
176 [](int exit_code) -> bool {
177 return WEXITSTATUS(exit_code) == 0;
178 },
179 ".*TEST PASS.*");
180 }
181
182 } // namespace chrome
OLDNEW
« no previous file with comments | « chrome/browser/mac/exception_processor.mm ('k') | chrome/test/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698