1 // Copyright 2020 The Chromium Authors
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/check.h"
6
7 #include "base/check_op.h"
8 #include "base/debug/alias.h"
9 #include "base/debug/dump_without_crashing.h"
10 #include "base/feature_list.h"
11 #include "base/features.h"
12 #include "base/logging.h"
13 #include "base/thread_annotations.h"
14 #include "build/build_config.h"
15
16 #if !BUILDFLAG(IS_NACL)
17 #include "base/debug/crash_logging.h"
18 #endif // !BUILDFLAG(IS_NACL)
19
20 namespace logging {
21
22 namespace {
23
DumpWithoutCrashing(LogMessage * log_message,const base::Location & location)24 void DumpWithoutCrashing(LogMessage* log_message,
25 const base::Location& location) {
26 // Copy the LogMessage message to stack memory to make sure it can be
27 // recovered in crash dumps. This is easier to recover in minidumps than crash
28 // keys during local debugging.
29 DEBUG_ALIAS_FOR_CSTR(log_message_str, log_message->BuildCrashString().c_str(),
30 1024);
31
32 // Report from the same location at most once every 30 days (unless the
33 // process has died). This attempts to prevent us from flooding ourselves with
34 // repeat reports for the same bug.
35 base::debug::DumpWithoutCrashing(location, base::Days(30));
36 }
37
NotReachedDumpWithoutCrashing(LogMessage * log_message,const base::Location & location)38 void NotReachedDumpWithoutCrashing(LogMessage* log_message,
39 const base::Location& location) {
40 #if !BUILDFLAG(IS_NACL)
41 SCOPED_CRASH_KEY_STRING1024("Logging", "NOTREACHED_MESSAGE",
42 log_message->BuildCrashString());
43 #endif // !BUILDFLAG(IS_NACL)
44 DumpWithoutCrashing(log_message, location);
45 }
46
DCheckDumpWithoutCrashing(LogMessage * log_message,const base::Location & location)47 void DCheckDumpWithoutCrashing(LogMessage* log_message,
48 const base::Location& location) {
49 #if !BUILDFLAG(IS_NACL)
50 SCOPED_CRASH_KEY_STRING1024("Logging", "DCHECK_MESSAGE",
51 log_message->BuildCrashString());
52 #endif // !BUILDFLAG(IS_NACL)
53 DumpWithoutCrashing(log_message, location);
54 }
55
DumpWillBeCheckDumpWithoutCrashing(LogMessage * log_message,const base::Location & location)56 void DumpWillBeCheckDumpWithoutCrashing(LogMessage* log_message,
57 const base::Location& location) {
58 #if !BUILDFLAG(IS_NACL)
59 SCOPED_CRASH_KEY_STRING1024("Logging", "DUMP_WILL_BE_CHECK_MESSAGE",
60 log_message->BuildCrashString());
61 #endif // !BUILDFLAG(IS_NACL)
62 DumpWithoutCrashing(log_message, location);
63 }
64
65 class NotReachedLogMessage : public LogMessage {
66 public:
NotReachedLogMessage(const base::Location & location,LogSeverity severity)67 NotReachedLogMessage(const base::Location& location, LogSeverity severity)
68 : LogMessage(location.file_name(), location.line_number(), severity),
69 location_(location) {}
~NotReachedLogMessage()70 ~NotReachedLogMessage() override {
71 if (severity() != logging::LOGGING_FATAL) {
72 NotReachedDumpWithoutCrashing(this, location_);
73 }
74 }
75
76 private:
77 const base::Location location_;
78 };
79
80 class DCheckLogMessage : public LogMessage {
81 public:
82 using LogMessage::LogMessage;
DCheckLogMessage(const base::Location & location,LogSeverity severity)83 DCheckLogMessage(const base::Location& location, LogSeverity severity)
84 : LogMessage(location.file_name(), location.line_number(), severity),
85 location_(location) {}
~DCheckLogMessage()86 ~DCheckLogMessage() override {
87 if (severity() != logging::LOGGING_FATAL) {
88 DCheckDumpWithoutCrashing(this, location_);
89 }
90 }
91
92 private:
93 const base::Location location_;
94 };
95
96 class DumpWillBeCheckLogMessage : public LogMessage {
97 public:
98 using LogMessage::LogMessage;
DumpWillBeCheckLogMessage(const base::Location & location,LogSeverity severity)99 DumpWillBeCheckLogMessage(const base::Location& location,
100 LogSeverity severity)
101 : LogMessage(location.file_name(), location.line_number(), severity),
102 location_(location) {}
~DumpWillBeCheckLogMessage()103 ~DumpWillBeCheckLogMessage() override {
104 if (severity() != logging::LOGGING_FATAL) {
105 DumpWillBeCheckDumpWithoutCrashing(this, location_);
106 }
107 }
108
109 private:
110 const base::Location location_;
111 };
112
113 #if BUILDFLAG(IS_WIN)
114 class DCheckWin32ErrorLogMessage : public Win32ErrorLogMessage {
115 public:
DCheckWin32ErrorLogMessage(const base::Location & location,LogSeverity severity,SystemErrorCode err)116 DCheckWin32ErrorLogMessage(const base::Location& location,
117 LogSeverity severity,
118 SystemErrorCode err)
119 : Win32ErrorLogMessage(location.file_name(),
120 location.line_number(),
121 severity,
122 err),
123 location_(location) {}
~DCheckWin32ErrorLogMessage()124 ~DCheckWin32ErrorLogMessage() override {
125 if (severity() != logging::LOGGING_FATAL) {
126 DCheckDumpWithoutCrashing(this, location_);
127 }
128 }
129
130 private:
131 const base::Location location_;
132 };
133 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
134 class DCheckErrnoLogMessage : public ErrnoLogMessage {
135 public:
DCheckErrnoLogMessage(const base::Location & location,LogSeverity severity,SystemErrorCode err)136 DCheckErrnoLogMessage(const base::Location& location,
137 LogSeverity severity,
138 SystemErrorCode err)
139 : ErrnoLogMessage(location.file_name(),
140 location.line_number(),
141 severity,
142 err),
143 location_(location) {}
~DCheckErrnoLogMessage()144 ~DCheckErrnoLogMessage() override {
145 if (severity() != logging::LOGGING_FATAL) {
146 DCheckDumpWithoutCrashing(this, location_);
147 }
148 }
149
150 private:
151 const base::Location location_;
152 };
153 #endif // BUILDFLAG(IS_WIN)
154
155 } // namespace
156
Check(const char * condition,const base::Location & location)157 CheckError CheckError::Check(const char* condition,
158 const base::Location& location) {
159 auto* const log_message = new LogMessage(
160 location.file_name(), location.line_number(), LOGGING_FATAL);
161 log_message->stream() << "Check failed: " << condition << ". ";
162 return CheckError(log_message);
163 }
164
CheckOp(char * log_message_str,const base::Location & location)165 CheckError CheckError::CheckOp(char* log_message_str,
166 const base::Location& location) {
167 auto* const log_message = new LogMessage(
168 location.file_name(), location.line_number(), LOGGING_FATAL);
169 log_message->stream() << log_message_str;
170 free(log_message_str);
171 return CheckError(log_message);
172 }
173
DCheck(const char * condition,const base::Location & location)174 CheckError CheckError::DCheck(const char* condition,
175 const base::Location& location) {
176 auto* const log_message = new DCheckLogMessage(location, LOGGING_DCHECK);
177 log_message->stream() << "Check failed: " << condition << ". ";
178 return CheckError(log_message);
179 }
180
DCheckOp(char * log_message_str,const base::Location & location)181 CheckError CheckError::DCheckOp(char* log_message_str,
182 const base::Location& location) {
183 auto* const log_message = new DCheckLogMessage(
184 location.file_name(), location.line_number(), LOGGING_DCHECK);
185 log_message->stream() << log_message_str;
186 free(log_message_str);
187 return CheckError(log_message);
188 }
189
DumpWillBeCheck(const char * condition,const base::Location & location)190 CheckError CheckError::DumpWillBeCheck(const char* condition,
191 const base::Location& location) {
192 auto* const log_message = new DumpWillBeCheckLogMessage(
193 location, DCHECK_IS_ON() ? LOGGING_DCHECK : LOGGING_ERROR);
194 log_message->stream() << "Check failed: " << condition << ". ";
195 return CheckError(log_message);
196 }
197
DumpWillBeCheckOp(char * log_message_str,const base::Location & location)198 CheckError CheckError::DumpWillBeCheckOp(char* log_message_str,
199 const base::Location& location) {
200 auto* const log_message = new DumpWillBeCheckLogMessage(
201 location, DCHECK_IS_ON() ? LOGGING_DCHECK : LOGGING_ERROR);
202 log_message->stream() << log_message_str;
203 free(log_message_str);
204 return CheckError(log_message);
205 }
206
PCheck(const char * condition,const base::Location & location)207 CheckError CheckError::PCheck(const char* condition,
208 const base::Location& location) {
209 SystemErrorCode err_code = logging::GetLastSystemErrorCode();
210 #if BUILDFLAG(IS_WIN)
211 auto* const log_message = new Win32ErrorLogMessage(
212 location.file_name(), location.line_number(), LOGGING_FATAL, err_code);
213 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
214 auto* const log_message = new ErrnoLogMessage(
215 location.file_name(), location.line_number(), LOGGING_FATAL, err_code);
216 #endif
217 log_message->stream() << "Check failed: " << condition << ". ";
218 return CheckError(log_message);
219 }
220
PCheck(const base::Location & location)221 CheckError CheckError::PCheck(const base::Location& location) {
222 return PCheck("", location);
223 }
224
DPCheck(const char * condition,const base::Location & location)225 CheckError CheckError::DPCheck(const char* condition,
226 const base::Location& location) {
227 SystemErrorCode err_code = logging::GetLastSystemErrorCode();
228 #if BUILDFLAG(IS_WIN)
229 auto* const log_message =
230 new DCheckWin32ErrorLogMessage(location, LOGGING_DCHECK, err_code);
231 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
232 auto* const log_message =
233 new DCheckErrnoLogMessage(location, LOGGING_DCHECK, err_code);
234 #endif
235 log_message->stream() << "Check failed: " << condition << ". ";
236 return CheckError(log_message);
237 }
238
DumpWillBeNotReachedNoreturn(const base::Location & location)239 CheckError CheckError::DumpWillBeNotReachedNoreturn(
240 const base::Location& location) {
241 auto* const log_message = new DumpWillBeCheckLogMessage(
242 location, DCHECK_IS_ON() ? LOGGING_DCHECK : LOGGING_ERROR);
243 log_message->stream() << "NOTREACHED hit. ";
244 return CheckError(log_message);
245 }
246
NotImplemented(const char * function,const base::Location & location)247 CheckError CheckError::NotImplemented(const char* function,
248 const base::Location& location) {
249 auto* const log_message = new LogMessage(
250 location.file_name(), location.line_number(), LOGGING_ERROR);
251 log_message->stream() << "Not implemented reached in " << function;
252 return CheckError(log_message);
253 }
254
stream()255 std::ostream& CheckError::stream() {
256 return log_message_->stream();
257 }
258
~CheckError()259 CheckError::~CheckError() {
260 // TODO(crbug.com/1409729): Consider splitting out CHECK from DCHECK so that
261 // the destructor can be marked [[noreturn]] and we don't need to check
262 // severity in the destructor.
263 const bool is_fatal = log_message_->severity() == LOGGING_FATAL;
264 // Note: This function ends up in crash stack traces. If its full name
265 // changes, the crash server's magic signature logic needs to be updated.
266 // See cl/306632920.
267 delete log_message_;
268
269 // Make sure we crash even if LOG(FATAL) has been overridden.
270 // TODO(crbug.com/1409729): Remove severity checking in the destructor when
271 // LOG(FATAL) is [[noreturn]] and can't be overridden.
272 if (is_fatal) {
273 base::ImmediateCrash();
274 }
275 }
276
NotReached(const base::Location & location)277 NotReachedError NotReachedError::NotReached(const base::Location& location) {
278 const LogSeverity severity = []() {
279 // NOTREACHED() instances may be hit before base::FeatureList is enabled.
280 if (base::FeatureList::GetInstance() &&
281 base::FeatureList::IsEnabled(base::features::kNotReachedIsFatal)) {
282 return LOGGING_FATAL;
283 }
284 return DCHECK_IS_ON() ? LOGGING_DCHECK : LOGGING_ERROR;
285 }();
286 auto* const log_message = new NotReachedLogMessage(location, severity);
287
288 // TODO(pbos): Consider a better message for NotReached(), this is here to
289 // match existing behavior + test expectations.
290 log_message->stream() << "Check failed: false. ";
291 return NotReachedError(log_message);
292 }
293
TriggerNotReached()294 void NotReachedError::TriggerNotReached() {
295 // This triggers a NOTREACHED() error as the returned NotReachedError goes out
296 // of scope.
297 NotReached()
298 << "NOTREACHED log messages are omitted in official builds. Sorry!";
299 }
300
301 NotReachedError::~NotReachedError() = default;
302
NotReachedNoreturnError(const base::Location & location)303 NotReachedNoreturnError::NotReachedNoreturnError(const base::Location& location)
304 : CheckError([location]() {
305 auto* const log_message = new LogMessage(
306 location.file_name(), location.line_number(), LOGGING_FATAL);
307 log_message->stream() << "NOTREACHED hit. ";
308 return log_message;
309 }()) {}
310
311 // Note: This function ends up in crash stack traces. If its full name changes,
312 // the crash server's magic signature logic needs to be updated. See
313 // cl/306632920.
~NotReachedNoreturnError()314 NotReachedNoreturnError::~NotReachedNoreturnError() {
315 delete log_message_;
316
317 // Make sure we die if we haven't.
318 // TODO(crbug.com/1409729): Replace this with NOTREACHED_NORETURN() once
319 // LOG(FATAL) is [[noreturn]].
320 base::ImmediateCrash();
321 }
322
RawCheckFailure(const char * message)323 void RawCheckFailure(const char* message) {
324 RawLog(LOGGING_FATAL, message);
325 __builtin_unreachable();
326 }
327
328 } // namespace logging
329