diff --git a/rtc_base/checks.cc b/rtc_base/checks.cc index 32ac8d6e8b..b8b5c9da9b 100644 --- a/rtc_base/checks.cc +++ b/rtc_base/checks.cc @@ -35,53 +35,72 @@ #include "rtc_base/checks.h" +namespace { +#if defined(__GNUC__) +__attribute__((__format__(__printf__, 2, 3))) +#endif + void AppendFormat(std::string* s, const char* fmt, ...) { + va_list args, copy; + va_start(args, fmt); + va_copy(copy, args); + const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy); + va_end(copy); + + if (predicted_length > 0) { + const size_t size = s->size(); + s->resize(size + predicted_length); + // Pass "+ 1" to vsnprintf to include space for the '\0'. + std::vsnprintf(&((*s)[size]), predicted_length + 1, fmt, args); + } + va_end(args); +} +} + namespace rtc { namespace webrtc_checks_impl { // Reads one argument from args, appends it to s and advances fmt. // Returns true iff an argument was sucessfully parsed. -bool ParseArg(va_list* args, - const CheckArgType** fmt, - std::ostream& s) { // no-presubmit-check TODO(webrtc:8982) +bool ParseArg(va_list* args, const CheckArgType** fmt, std::string* s) { if (**fmt == CheckArgType::kEnd) return false; switch (**fmt) { case CheckArgType::kInt: - s << va_arg(*args, int); + AppendFormat(s, "%d", va_arg(*args, int)); break; case CheckArgType::kLong: - s << va_arg(*args, long); + AppendFormat(s, "%ld", va_arg(*args, long)); break; case CheckArgType::kLongLong: - s << va_arg(*args, long long); + AppendFormat(s, "%lld", va_arg(*args, long long)); break; case CheckArgType::kUInt: - s << va_arg(*args, unsigned); + AppendFormat(s, "%u", va_arg(*args, unsigned)); break; case CheckArgType::kULong: - s << va_arg(*args, unsigned long); + AppendFormat(s, "%lu", va_arg(*args, unsigned long)); break; case CheckArgType::kULongLong: - s << va_arg(*args, unsigned long long); + AppendFormat(s, "%llu", va_arg(*args, unsigned long long)); break; case CheckArgType::kDouble: - s << va_arg(*args, double); + AppendFormat(s, "%g", va_arg(*args, double)); break; case CheckArgType::kLongDouble: - s << va_arg(*args, long double); + AppendFormat(s, "%Lg", va_arg(*args, long double)); break; case CheckArgType::kCharP: - s << va_arg(*args, const char*); + s->append(va_arg(*args, const char*)); break; case CheckArgType::kStdString: - s << *va_arg(*args, const std::string*); + s->append(*va_arg(*args, const std::string*)); break; case CheckArgType::kVoidP: - s << reinterpret_cast(va_arg(*args, const void*)); + AppendFormat(s, "%p", va_arg(*args, const void*)); break; default: - s << "[Invalid CheckArgType:" << static_cast(**fmt) << "]"; + s->append("[Invalid CheckArgType]"); return false; } (*fmt)++; @@ -96,9 +115,14 @@ RTC_NORETURN void FatalLog(const char* file, va_list args; va_start(args, fmt); - std::ostringstream ss; // no-presubmit-check TODO(webrtc:8982) - ss << "\n\n#\n# Fatal error in: " << file << ", line " << line - << "\n# last system error: " << LAST_SYSTEM_ERROR << "\n# Check failed: "; + std::string s; + AppendFormat(&s, + "\n\n" + "#\n" + "# Fatal error in: %s, line %d\n" + "# last system error: %u\n" + "# Check failed: %s", + file, line, LAST_SYSTEM_ERROR, message); if (*fmt == CheckArgType::kCheckOp) { // This log message was generated by RTC_CHECK_OP, so we have to complete @@ -106,20 +130,19 @@ RTC_NORETURN void FatalLog(const char* file, // two arguments. fmt++; - std::ostringstream s1, s2; // no-presubmit-check TODO(webrtc:8982) - if (ParseArg(&args, &fmt, s1) && ParseArg(&args, &fmt, s2)) - ss << message << " (" << s1.str() << " vs. " << s2.str() << ")\n# "; + std::string s1, s2; + if (ParseArg(&args, &fmt, &s1) && ParseArg(&args, &fmt, &s2)) + AppendFormat(&s, " (%s vs. %s)\n# ", s1.c_str(), s2.c_str()); } else { - ss << message << "\n# "; + s.append("\n# "); } // Append all the user-supplied arguments to the message. - while (ParseArg(&args, &fmt, ss)) + while (ParseArg(&args, &fmt, &s)) ; va_end(args); - std::string s = ss.str(); const char* output = s.c_str(); #if defined(WEBRTC_ANDROID)