• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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