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