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 #include "absl/strings/string_view.h"
19
20 #if defined(WEBRTC_ANDROID)
21 #define RTC_LOG_TAG_ANDROID "rtc"
22 #include <android/log.h> // NOLINT
23 #endif
24
25 #if defined(WEBRTC_WIN)
26 #include <windows.h>
27 #endif
28
29 #if defined(WEBRTC_WIN)
30 #define LAST_SYSTEM_ERROR (::GetLastError())
31 #elif defined(__native_client__) && __native_client__
32 #define LAST_SYSTEM_ERROR (0)
33 #elif defined(WEBRTC_POSIX)
34 #include <errno.h>
35 #define LAST_SYSTEM_ERROR (errno)
36 #endif // WEBRTC_WIN
37
38 #include "rtc_base/checks.h"
39
40 namespace {
41
42 #if defined(__GNUC__)
43 __attribute__((__format__(__printf__, 2, 3)))
44 #endif
AppendFormat(std::string * s,const char * fmt,...)45 void AppendFormat(std::string* s, const char* fmt, ...) {
46 va_list args, copy;
47 va_start(args, fmt);
48 va_copy(copy, args);
49 const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy);
50 va_end(copy);
51
52 if (predicted_length > 0) {
53 const size_t size = s->size();
54 s->resize(size + predicted_length);
55 // Pass "+ 1" to vsnprintf to include space for the '\0'.
56 std::vsnprintf(&((*s)[size]), predicted_length + 1, fmt, args);
57 }
58 va_end(args);
59 }
60 } // namespace
61
62 namespace rtc {
63 namespace webrtc_checks_impl {
64
65 #if !defined(WEBRTC_CHROMIUM_BUILD)
WriteFatalLog(absl::string_view output)66 RTC_NORETURN void WriteFatalLog(absl::string_view output) {
67 #if defined(WEBRTC_ANDROID)
68 std::string output_str(output);
69 __android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n",
70 output_str.c_str());
71 #endif
72 fflush(stdout);
73 fwrite(output.data(), output.size(), 1, stderr);
74 fflush(stderr);
75 #if defined(WEBRTC_WIN)
76 DebugBreak();
77 #endif
78 abort();
79 }
80
WriteFatalLog(const char * file,int line,absl::string_view output)81 RTC_NORETURN void WriteFatalLog(const char* file,
82 int line,
83 absl::string_view output) {
84 WriteFatalLog(output);
85 }
86
87 #endif // !defined(WEBRTC_CHROMIUM_BUILD)
88
89 #if RTC_CHECK_MSG_ENABLED
90 // Reads one argument from args, appends it to s and advances fmt.
91 // Returns true iff an argument was sucessfully parsed.
ParseArg(va_list * args,const CheckArgType ** fmt,std::string * s)92 bool ParseArg(va_list* args, const CheckArgType** fmt, std::string* s) {
93 if (**fmt == CheckArgType::kEnd)
94 return false;
95
96 switch (**fmt) {
97 case CheckArgType::kInt:
98 AppendFormat(s, "%d", va_arg(*args, int));
99 break;
100 case CheckArgType::kLong:
101 AppendFormat(s, "%ld", va_arg(*args, long));
102 break;
103 case CheckArgType::kLongLong:
104 AppendFormat(s, "%lld", va_arg(*args, long long));
105 break;
106 case CheckArgType::kUInt:
107 AppendFormat(s, "%u", va_arg(*args, unsigned));
108 break;
109 case CheckArgType::kULong:
110 AppendFormat(s, "%lu", va_arg(*args, unsigned long));
111 break;
112 case CheckArgType::kULongLong:
113 AppendFormat(s, "%llu", va_arg(*args, unsigned long long));
114 break;
115 case CheckArgType::kDouble:
116 AppendFormat(s, "%g", va_arg(*args, double));
117 break;
118 case CheckArgType::kLongDouble:
119 AppendFormat(s, "%Lg", va_arg(*args, long double));
120 break;
121 case CheckArgType::kCharP:
122 s->append(va_arg(*args, const char*));
123 break;
124 case CheckArgType::kStdString:
125 s->append(*va_arg(*args, const std::string*));
126 break;
127 case CheckArgType::kStringView: {
128 const absl::string_view sv = *va_arg(*args, const absl::string_view*);
129 s->append(sv.data(), sv.size());
130 break;
131 }
132 case CheckArgType::kVoidP:
133 AppendFormat(s, "%p", va_arg(*args, const void*));
134 break;
135 default:
136 s->append("[Invalid CheckArgType]");
137 return false;
138 }
139 (*fmt)++;
140 return true;
141 }
142
FatalLog(const char * file,int line,const char * message,const CheckArgType * fmt,...)143 RTC_NORETURN void FatalLog(const char* file,
144 int line,
145 const char* message,
146 const CheckArgType* fmt,
147 ...) {
148 va_list args;
149 va_start(args, fmt);
150
151 std::string s;
152 AppendFormat(&s,
153 "\n\n"
154 "#\n"
155 "# Fatal error in: %s, line %d\n"
156 "# last system error: %u\n"
157 "# Check failed: %s",
158 file, line, LAST_SYSTEM_ERROR, message);
159
160 if (*fmt == CheckArgType::kCheckOp) {
161 // This log message was generated by RTC_CHECK_OP, so we have to complete
162 // the error message using the operands that have been passed as the first
163 // two arguments.
164 fmt++;
165
166 std::string s1, s2;
167 if (ParseArg(&args, &fmt, &s1) && ParseArg(&args, &fmt, &s2))
168 AppendFormat(&s, " (%s vs. %s)\n# ", s1.c_str(), s2.c_str());
169 } else {
170 s.append("\n# ");
171 }
172
173 // Append all the user-supplied arguments to the message.
174 while (ParseArg(&args, &fmt, &s))
175 ;
176
177 va_end(args);
178
179 WriteFatalLog(file, line, s);
180 }
181 #else // RTC_CHECK_MSG_ENABLED
FatalLog(const char * file,int line)182 RTC_NORETURN void FatalLog(const char* file, int line) {
183 std::string s;
184 AppendFormat(&s,
185 "\n\n"
186 "#\n"
187 "# Fatal error in: %s, line %d\n"
188 "# last system error: %u\n"
189 "# Check failed.\n"
190 "# ",
191 file, line, LAST_SYSTEM_ERROR);
192 WriteFatalLog(file, line, s);
193 }
194 #endif // RTC_CHECK_MSG_ENABLED
195
196 #if RTC_DCHECK_IS_ON
197
UnreachableCodeReached(const char * file,int line)198 RTC_NORETURN void UnreachableCodeReached(const char* file, int line) {
199 std::string s;
200 AppendFormat(&s,
201 "\n\n"
202 "#\n"
203 "# Unreachable code reached: %s, line %d\n"
204 "# last system error: %u\n"
205 "# ",
206 file, line, LAST_SYSTEM_ERROR);
207 WriteFatalLog(file, line, s);
208 }
209
210 #else // !RTC_DCHECK_IS_ON
211
UnreachableCodeReached()212 RTC_NORETURN void UnreachableCodeReached() {
213 std::string s;
214 AppendFormat(&s,
215 "\n\n"
216 "#\n"
217 "# Unreachable code reached (file and line unknown)\n"
218 "# last system error: %u\n"
219 "# ",
220 LAST_SYSTEM_ERROR);
221 WriteFatalLog(s);
222 }
223
224 #endif // !RTC_DCHECK_IS_ON
225
226 } // namespace webrtc_checks_impl
227 } // namespace rtc
228
229 // 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)230 RTC_NORETURN void rtc_FatalMessage(const char* file,
231 int line,
232 const char* msg) {
233 #if RTC_CHECK_MSG_ENABLED
234 static constexpr rtc::webrtc_checks_impl::CheckArgType t[] = {
235 rtc::webrtc_checks_impl::CheckArgType::kEnd};
236 rtc::webrtc_checks_impl::FatalLog(file, line, msg, t);
237 #else
238 rtc::webrtc_checks_impl::FatalLog(file, line);
239 #endif
240 }
241