• 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 #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