• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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