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