1 /*
2 * Copyright 2006 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 // Most of this was borrowed (with minor modifications) from V8's and Chromium's
12 // src/base/logging.cc.
13
14 #include <cstdarg>
15 #include <cstdio>
16 #include <cstdlib>
17
18 #if defined(WEBRTC_ANDROID)
19 #define RTC_LOG_TAG_ANDROID "rtc"
20 #include <android/log.h> // NOLINT
21 #endif
22
23 #if defined(WEBRTC_WIN)
24 #include <windows.h>
25 #endif
26
27 #if defined(WEBRTC_WIN)
28 #define LAST_SYSTEM_ERROR (::GetLastError())
29 #elif defined(__native_client__) && __native_client__
30 #define LAST_SYSTEM_ERROR (0)
31 #elif defined(WEBRTC_POSIX)
32 #include <errno.h>
33 #define LAST_SYSTEM_ERROR (errno)
34 #endif // WEBRTC_WIN
35
36 #include "rtc_base/checks.h"
37
38 namespace {
39 #if defined(__GNUC__)
40 __attribute__((__format__(__printf__, 2, 3)))
41 #endif
AppendFormat(std::string * s,const char * fmt,...)42 void AppendFormat(std::string* s, const char* fmt, ...) {
43 va_list args, copy;
44 va_start(args, fmt);
45 va_copy(copy, args);
46 const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy);
47 va_end(copy);
48
49 if (predicted_length > 0) {
50 const size_t size = s->size();
51 s->resize(size + predicted_length);
52 // Pass "+ 1" to vsnprintf to include space for the '\0'.
53 std::vsnprintf(&((*s)[size]), predicted_length + 1, fmt, args);
54 }
55 va_end(args);
56 }
57 } // namespace
58
59 namespace rtc {
60 namespace webrtc_checks_impl {
61
62 #if RTC_CHECK_MSG_ENABLED
63 // Reads one argument from args, appends it to s and advances fmt.
64 // Returns true iff an argument was sucessfully parsed.
ParseArg(va_list * args,const CheckArgType ** fmt,std::string * s)65 bool ParseArg(va_list* args, const CheckArgType** fmt, std::string* s) {
66 if (**fmt == CheckArgType::kEnd)
67 return false;
68
69 switch (**fmt) {
70 case CheckArgType::kInt:
71 AppendFormat(s, "%d", va_arg(*args, int));
72 break;
73 case CheckArgType::kLong:
74 AppendFormat(s, "%ld", va_arg(*args, long));
75 break;
76 case CheckArgType::kLongLong:
77 AppendFormat(s, "%lld", va_arg(*args, long long));
78 break;
79 case CheckArgType::kUInt:
80 AppendFormat(s, "%u", va_arg(*args, unsigned));
81 break;
82 case CheckArgType::kULong:
83 AppendFormat(s, "%lu", va_arg(*args, unsigned long));
84 break;
85 case CheckArgType::kULongLong:
86 AppendFormat(s, "%llu", va_arg(*args, unsigned long long));
87 break;
88 case CheckArgType::kDouble:
89 AppendFormat(s, "%g", va_arg(*args, double));
90 break;
91 case CheckArgType::kLongDouble:
92 AppendFormat(s, "%Lg", va_arg(*args, long double));
93 break;
94 case CheckArgType::kCharP:
95 s->append(va_arg(*args, const char*));
96 break;
97 case CheckArgType::kStdString:
98 s->append(*va_arg(*args, const std::string*));
99 break;
100 case CheckArgType::kStringView: {
101 const absl::string_view sv = *va_arg(*args, const absl::string_view*);
102 s->append(sv.data(), sv.size());
103 break;
104 }
105 case CheckArgType::kVoidP:
106 AppendFormat(s, "%p", va_arg(*args, const void*));
107 break;
108 default:
109 s->append("[Invalid CheckArgType]");
110 return false;
111 }
112 (*fmt)++;
113 return true;
114 }
115
FatalLog(const char * file,int line,const char * message,const CheckArgType * fmt,...)116 RTC_NORETURN void FatalLog(const char* file,
117 int line,
118 const char* message,
119 const CheckArgType* fmt,
120 ...) {
121 va_list args;
122 va_start(args, fmt);
123
124 std::string s;
125 AppendFormat(&s,
126 "\n\n"
127 "#\n"
128 "# Fatal error in: %s, line %d\n"
129 "# last system error: %u\n"
130 "# Check failed: %s",
131 file, line, LAST_SYSTEM_ERROR, message);
132
133 if (*fmt == CheckArgType::kCheckOp) {
134 // This log message was generated by RTC_CHECK_OP, so we have to complete
135 // the error message using the operands that have been passed as the first
136 // two arguments.
137 fmt++;
138
139 std::string s1, s2;
140 if (ParseArg(&args, &fmt, &s1) && ParseArg(&args, &fmt, &s2))
141 AppendFormat(&s, " (%s vs. %s)\n# ", s1.c_str(), s2.c_str());
142 } else {
143 s.append("\n# ");
144 }
145
146 // Append all the user-supplied arguments to the message.
147 while (ParseArg(&args, &fmt, &s))
148 ;
149
150 va_end(args);
151
152 const char* output = s.c_str();
153
154 #if defined(WEBRTC_ANDROID)
155 __android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", output);
156 #endif
157
158 fflush(stdout);
159 fprintf(stderr, "%s", output);
160 fflush(stderr);
161 #if defined(WEBRTC_WIN)
162 DebugBreak();
163 #endif
164 abort();
165 }
166 #else // RTC_CHECK_MSG_ENABLED
167 RTC_NORETURN void FatalLog(const char* file, int line) {
168 std::string s;
169 AppendFormat(&s,
170 "\n\n"
171 "#\n"
172 "# Fatal error in: %s, line %d\n"
173 "# last system error: %u\n"
174 "# Check failed.\n"
175 "# ",
176 file, line, LAST_SYSTEM_ERROR);
177 const char* output = s.c_str();
178
179 #if defined(WEBRTC_ANDROID)
180 __android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", output);
181 #endif
182
183 fflush(stdout);
184 fprintf(stderr, "%s", output);
185 fflush(stderr);
186 #if defined(WEBRTC_WIN)
187 DebugBreak();
188 #endif
189 abort();
190 }
191 #endif // RTC_CHECK_MSG_ENABLED
192
193 } // namespace webrtc_checks_impl
194 } // namespace rtc
195
196 // Function to call from the C version of the RTC_CHECK and RTC_DCHECK macros.
rtc_FatalMessage(const char * file,int line,const char * msg)197 RTC_NORETURN void rtc_FatalMessage(const char* file,
198 int line,
199 const char* msg) {
200 #if RTC_CHECK_MSG_ENABLED
201 static constexpr rtc::webrtc_checks_impl::CheckArgType t[] = {
202 rtc::webrtc_checks_impl::CheckArgType::kEnd};
203 rtc::webrtc_checks_impl::FatalLog(file, line, msg, t);
204 #else
205 rtc::webrtc_checks_impl::FatalLog(file, line);
206 #endif
207 }
208