• 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/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