1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef V8_BASE_LOGGING_H_
6 #define V8_BASE_LOGGING_H_
7
8 #include <cstdint>
9 #include <cstring>
10 #include <sstream>
11 #include <string>
12
13 #include "src/base/base-export.h"
14 #include "src/base/build_config.h"
15 #include "src/base/compiler-specific.h"
16 #include "src/base/immediate-crash.h"
17 #include "src/base/template-utils.h"
18
19 V8_BASE_EXPORT V8_NOINLINE void V8_Dcheck(const char* file, int line,
20 const char* message);
21
22 #ifdef DEBUG
23 // In debug, include file, line, and full error message for all
24 // FATAL() calls.
25 [[noreturn]] PRINTF_FORMAT(3, 4) V8_BASE_EXPORT V8_NOINLINE
26 void V8_Fatal(const char* file, int line, const char* format, ...);
27 #define FATAL(...) V8_Fatal(__FILE__, __LINE__, __VA_ARGS__)
28
29 #else
30 [[noreturn]] PRINTF_FORMAT(1, 2) V8_BASE_EXPORT V8_NOINLINE
31 void V8_Fatal(const char* format, ...);
32 #if !defined(OFFICIAL_BUILD)
33 // In non-official release, include full error message, but drop file & line
34 // numbers. It saves binary size to drop the |file| & |line| as opposed to just
35 // passing in "", 0 for them.
36 #define FATAL(...) V8_Fatal(__VA_ARGS__)
37 #else
38 // FATAL(msg) -> IMMEDIATE_CRASH()
39 // FATAL(msg, ...) -> V8_Fatal(msg, ...)
40 #define FATAL_HELPER(_7, _6, _5, _4, _3, _2, _1, _0, ...) _0
41 #define FATAL_DISCARD_ARG(arg) IMMEDIATE_CRASH()
42 #define FATAL(...) \
43 FATAL_HELPER(__VA_ARGS__, V8_Fatal, V8_Fatal, V8_Fatal, V8_Fatal, V8_Fatal, \
44 V8_Fatal, FATAL_DISCARD_ARG) \
45 (__VA_ARGS__)
46 #endif // !defined(OFFICIAL_BUILD)
47 #endif // DEBUG
48
49 #define UNIMPLEMENTED() FATAL("unimplemented code")
50 #define UNREACHABLE() FATAL("unreachable code")
51
52 namespace v8 {
53 namespace base {
54
55 class CheckMessageStream : public std::ostringstream {};
56
57 // Overwrite the default function that prints a stack trace.
58 V8_BASE_EXPORT void SetPrintStackTrace(void (*print_stack_trace_)());
59
60 // Override the default function that handles DCHECKs.
61 V8_BASE_EXPORT void SetDcheckFunction(void (*dcheck_Function)(const char*, int,
62 const char*));
63
64 // In official builds, assume all check failures can be debugged given just the
65 // stack trace.
66 #if !defined(DEBUG) && defined(OFFICIAL_BUILD)
67 #define CHECK_FAILED_HANDLER(message) FATAL("ignored")
68 #else
69 #define CHECK_FAILED_HANDLER(message) FATAL("Check failed: %s.", message)
70 #endif
71
72 // CHECK dies with a fatal error if condition is not true. It is *not*
73 // controlled by DEBUG, so the check will be executed regardless of
74 // compilation mode.
75 //
76 // We make sure CHECK et al. always evaluates their arguments, as
77 // doing CHECK(FunctionWithSideEffect()) is a common idiom.
78 #define CHECK_WITH_MSG(condition, message) \
79 do { \
80 if (V8_UNLIKELY(!(condition))) { \
81 CHECK_FAILED_HANDLER(message); \
82 } \
83 } while (false)
84 #define CHECK(condition) CHECK_WITH_MSG(condition, #condition)
85
86 #ifdef DEBUG
87
88 #define DCHECK_WITH_MSG(condition, message) \
89 do { \
90 if (V8_UNLIKELY(!(condition))) { \
91 V8_Dcheck(__FILE__, __LINE__, message); \
92 } \
93 } while (false)
94 #define DCHECK(condition) DCHECK_WITH_MSG(condition, #condition)
95
96 // Helper macro for binary operators.
97 // Don't use this macro directly in your code, use CHECK_EQ et al below.
98 #define CHECK_OP(name, op, lhs, rhs) \
99 do { \
100 if (std::string* _msg = ::v8::base::Check##name##Impl< \
101 typename ::v8::base::pass_value_or_ref<decltype(lhs)>::type, \
102 typename ::v8::base::pass_value_or_ref<decltype(rhs)>::type>( \
103 (lhs), (rhs), #lhs " " #op " " #rhs)) { \
104 FATAL("Check failed: %s.", _msg->c_str()); \
105 delete _msg; \
106 } \
107 } while (false)
108
109 #define DCHECK_OP(name, op, lhs, rhs) \
110 do { \
111 if (std::string* _msg = ::v8::base::Check##name##Impl< \
112 typename ::v8::base::pass_value_or_ref<decltype(lhs)>::type, \
113 typename ::v8::base::pass_value_or_ref<decltype(rhs)>::type>( \
114 (lhs), (rhs), #lhs " " #op " " #rhs)) { \
115 V8_Dcheck(__FILE__, __LINE__, _msg->c_str()); \
116 delete _msg; \
117 } \
118 } while (false)
119
120 #else
121
122 // Make all CHECK functions discard their log strings to reduce code
123 // bloat for official release builds.
124
125 #define CHECK_OP(name, op, lhs, rhs) \
126 do { \
127 bool _cmp = ::v8::base::Cmp##name##Impl< \
128 typename ::v8::base::pass_value_or_ref<decltype(lhs)>::type, \
129 typename ::v8::base::pass_value_or_ref<decltype(rhs)>::type>((lhs), \
130 (rhs)); \
131 CHECK_WITH_MSG(_cmp, #lhs " " #op " " #rhs); \
132 } while (false)
133
134 #define DCHECK_WITH_MSG(condition, msg) void(0);
135
136 #endif
137
138 namespace detail {
139 template <typename... Ts>
PrintToString(Ts &&...ts)140 std::string PrintToString(Ts&&... ts) {
141 CheckMessageStream oss;
142 int unused_results[]{((oss << std::forward<Ts>(ts)), 0)...};
143 (void)unused_results; // Avoid "unused variable" warning.
144 return oss.str();
145 }
146
147 template <typename T>
GetUnderlyingEnumTypeForPrinting(T val)148 auto GetUnderlyingEnumTypeForPrinting(T val) {
149 using underlying_t = typename std::underlying_type<T>::type;
150 // For single-byte enums, return a 16-bit integer to avoid printing the value
151 // as a character.
152 using int_t = typename std::conditional_t<
153 sizeof(underlying_t) != 1, underlying_t,
154 std::conditional_t<std::is_signed<underlying_t>::value, int16_t,
155 uint16_t> >;
156 return static_cast<int_t>(static_cast<underlying_t>(val));
157 }
158 } // namespace detail
159
160 // Define PrintCheckOperand<T> for each T which defines operator<< for ostream.
161 template <typename T>
162 typename std::enable_if<
163 !std::is_function<typename std::remove_pointer<T>::type>::value &&
164 !std::is_enum<T>::value &&
165 has_output_operator<T, CheckMessageStream>::value,
166 std::string>::type
PrintCheckOperand(T val)167 PrintCheckOperand(T val) {
168 return detail::PrintToString(std::forward<T>(val));
169 }
170
171 // Provide an overload for functions and function pointers. Function pointers
172 // don't implicitly convert to void* but do implicitly convert to bool, so
173 // without this function pointers are always printed as 1 or 0. (MSVC isn't
174 // standards-conforming here and converts function pointers to regular
175 // pointers, so this is a no-op for MSVC.)
176 template <typename T>
177 typename std::enable_if<
178 std::is_function<typename std::remove_pointer<T>::type>::value,
179 std::string>::type
PrintCheckOperand(T val)180 PrintCheckOperand(T val) {
181 return PrintCheckOperand(reinterpret_cast<const void*>(val));
182 }
183
184 // Define PrintCheckOperand<T> for enums with an output operator.
185 template <typename T>
186 typename std::enable_if<std::is_enum<T>::value &&
187 has_output_operator<T, CheckMessageStream>::value,
188 std::string>::type
PrintCheckOperand(T val)189 PrintCheckOperand(T val) {
190 std::string val_str = detail::PrintToString(val);
191 std::string int_str =
192 detail::PrintToString(detail::GetUnderlyingEnumTypeForPrinting(val));
193 // Printing the original enum might have printed a single non-printable
194 // character. Ignore it in that case. Also ignore if it printed the same as
195 // the integral representation.
196 // TODO(clemensb): Can we somehow statically find out if the output operator
197 // is the default one, printing the integral value?
198 if ((val_str.length() == 1 && !std::isprint(val_str[0])) ||
199 val_str == int_str) {
200 return int_str;
201 }
202 return detail::PrintToString(val_str, " (", int_str, ")");
203 }
204
205 // Define PrintCheckOperand<T> for enums without an output operator.
206 template <typename T>
207 typename std::enable_if<std::is_enum<T>::value &&
208 !has_output_operator<T, CheckMessageStream>::value,
209 std::string>::type
PrintCheckOperand(T val)210 PrintCheckOperand(T val) {
211 return detail::PrintToString(detail::GetUnderlyingEnumTypeForPrinting(val));
212 }
213
214 // Define default PrintCheckOperand<T> for non-printable types.
215 template <typename T>
216 typename std::enable_if<!has_output_operator<T, CheckMessageStream>::value &&
217 !std::is_enum<T>::value,
218 std::string>::type
PrintCheckOperand(T val)219 PrintCheckOperand(T val) {
220 return "<unprintable>";
221 }
222
223 // Define specializations for character types, defined in logging.cc.
224 #define DEFINE_PRINT_CHECK_OPERAND_CHAR(type) \
225 template <> \
226 V8_BASE_EXPORT std::string PrintCheckOperand<type>(type ch); \
227 template <> \
228 V8_BASE_EXPORT std::string PrintCheckOperand<type*>(type * cstr); \
229 template <> \
230 V8_BASE_EXPORT std::string PrintCheckOperand<const type*>(const type* cstr);
231
232 DEFINE_PRINT_CHECK_OPERAND_CHAR(char)
DEFINE_PRINT_CHECK_OPERAND_CHAR(signed char)233 DEFINE_PRINT_CHECK_OPERAND_CHAR(signed char)
234 DEFINE_PRINT_CHECK_OPERAND_CHAR(unsigned char)
235 #undef DEFINE_PRINT_CHECK_OPERAND_CHAR
236
237 // Build the error message string. This is separate from the "Impl"
238 // function template because it is not performance critical and so can
239 // be out of line, while the "Impl" code should be inline. Caller
240 // takes ownership of the returned string.
241 template <typename Lhs, typename Rhs>
242 V8_NOINLINE std::string* MakeCheckOpString(Lhs lhs, Rhs rhs, char const* msg) {
243 std::string lhs_str = PrintCheckOperand<Lhs>(lhs);
244 std::string rhs_str = PrintCheckOperand<Rhs>(rhs);
245 CheckMessageStream ss;
246 ss << msg;
247 constexpr size_t kMaxInlineLength = 50;
248 if (lhs_str.size() <= kMaxInlineLength &&
249 rhs_str.size() <= kMaxInlineLength) {
250 ss << " (" << lhs_str << " vs. " << rhs_str << ")";
251 } else {
252 ss << "\n " << lhs_str << "\n vs.\n " << rhs_str << "\n";
253 }
254 return new std::string(ss.str());
255 }
256
257 // Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
258 // in logging.cc.
259 #define EXPLICIT_CHECK_OP_INSTANTIATION(type) \
260 extern template V8_BASE_EXPORT std::string* MakeCheckOpString<type, type>( \
261 type, type, char const*); \
262 extern template V8_BASE_EXPORT std::string PrintCheckOperand<type>(type);
263
264 EXPLICIT_CHECK_OP_INSTANTIATION(int)
265 EXPLICIT_CHECK_OP_INSTANTIATION(long) // NOLINT(runtime/int)
266 EXPLICIT_CHECK_OP_INSTANTIATION(long long) // NOLINT(runtime/int)
267 EXPLICIT_CHECK_OP_INSTANTIATION(unsigned int)
268 EXPLICIT_CHECK_OP_INSTANTIATION(unsigned long) // NOLINT(runtime/int)
269 EXPLICIT_CHECK_OP_INSTANTIATION(unsigned long long) // NOLINT(runtime/int)
270 EXPLICIT_CHECK_OP_INSTANTIATION(void const*)
271 #undef EXPLICIT_CHECK_OP_INSTANTIATION
272
273 // comparison_underlying_type provides the underlying integral type of an enum,
274 // or std::decay<T>::type if T is not an enum. Booleans are converted to
275 // "unsigned int", to allow "unsigned int == bool" comparisons.
276 template <typename T>
277 struct comparison_underlying_type {
278 // std::underlying_type must only be used with enum types, thus use this
279 // {Dummy} type if the given type is not an enum.
280 enum Dummy {};
281 using decay = typename std::decay<T>::type;
282 static constexpr bool is_enum = std::is_enum<decay>::value;
283 using underlying = typename std::underlying_type<
284 typename std::conditional<is_enum, decay, Dummy>::type>::type;
285 using type_or_bool =
286 typename std::conditional<is_enum, underlying, decay>::type;
287 using type =
288 typename std::conditional<std::is_same<type_or_bool, bool>::value,
289 unsigned int, type_or_bool>::type;
290 };
291 // Cast a value to its underlying type
292 #define MAKE_UNDERLYING(Type, value) \
293 static_cast<typename comparison_underlying_type<Type>::type>(value)
294
295 // is_signed_vs_unsigned::value is true if both types are integral, Lhs is
296 // signed, and Rhs is unsigned. False in all other cases.
297 template <typename Lhs, typename Rhs>
298 struct is_signed_vs_unsigned {
299 using lhs_underlying = typename comparison_underlying_type<Lhs>::type;
300 using rhs_underlying = typename comparison_underlying_type<Rhs>::type;
301 static constexpr bool value = std::is_integral<lhs_underlying>::value &&
302 std::is_integral<rhs_underlying>::value &&
303 std::is_signed<lhs_underlying>::value &&
304 std::is_unsigned<rhs_underlying>::value;
305 };
306 // Same thing, other way around: Lhs is unsigned, Rhs signed.
307 template <typename Lhs, typename Rhs>
308 struct is_unsigned_vs_signed : public is_signed_vs_unsigned<Rhs, Lhs> {};
309
310 // Specialize the compare functions for signed vs. unsigned comparisons.
311 // std::enable_if ensures that this template is only instantiable if both Lhs
312 // and Rhs are integral types, and their signedness does not match.
313 #define MAKE_UNSIGNED(Type, value) \
314 static_cast<typename std::make_unsigned< \
315 typename comparison_underlying_type<Type>::type>::type>(value)
316 #define DEFINE_SIGNED_MISMATCH_COMP(CHECK, NAME, IMPL) \
317 template <typename Lhs, typename Rhs> \
318 V8_INLINE constexpr \
319 typename std::enable_if<CHECK<Lhs, Rhs>::value, bool>::type \
320 Cmp##NAME##Impl(Lhs lhs, Rhs rhs) { \
321 return IMPL; \
322 }
323 DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, EQ,
324 lhs >= 0 && MAKE_UNSIGNED(Lhs, lhs) ==
325 MAKE_UNDERLYING(Rhs, rhs))
326 DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, LT,
327 lhs < 0 || MAKE_UNSIGNED(Lhs, lhs) <
328 MAKE_UNDERLYING(Rhs, rhs))
329 DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, LE,
330 lhs <= 0 || MAKE_UNSIGNED(Lhs, lhs) <=
331 MAKE_UNDERLYING(Rhs, rhs))
332 DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, NE, !CmpEQImpl(lhs, rhs))
333 DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, GT, !CmpLEImpl(lhs, rhs))
334 DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, GE, !CmpLTImpl(lhs, rhs))
335 DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, EQ, CmpEQImpl(rhs, lhs))
336 DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, NE, CmpNEImpl(rhs, lhs))
337 DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, LT, CmpGTImpl(rhs, lhs))
338 DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, LE, CmpGEImpl(rhs, lhs))
339 DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, GT, CmpLTImpl(rhs, lhs))
340 DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, GE, CmpLEImpl(rhs, lhs))
341 #undef MAKE_UNSIGNED
342 #undef DEFINE_SIGNED_MISMATCH_COMP
343
344 // Helper functions for CHECK_OP macro.
345 // The (float, float) and (double, double) instantiations are explicitly
346 // externalized to ensure proper 32/64-bit comparisons on x86.
347 // The Cmp##NAME##Impl function is only instantiable if one of the two types is
348 // not integral or their signedness matches (i.e. whenever no specialization is
349 // required, see above). Otherwise it is disabled by the enable_if construct,
350 // and the compiler will pick a specialization from above.
351 #define DEFINE_CHECK_OP_IMPL(NAME, op) \
352 template <typename Lhs, typename Rhs> \
353 V8_INLINE constexpr \
354 typename std::enable_if<!is_signed_vs_unsigned<Lhs, Rhs>::value && \
355 !is_unsigned_vs_signed<Lhs, Rhs>::value, \
356 bool>::type Cmp##NAME##Impl(Lhs lhs, Rhs rhs) { \
357 return lhs op rhs; \
358 } \
359 template <typename Lhs, typename Rhs> \
360 V8_INLINE constexpr std::string* Check##NAME##Impl(Lhs lhs, Rhs rhs, \
361 char const* msg) { \
362 using LhsPassT = typename pass_value_or_ref<Lhs>::type; \
363 using RhsPassT = typename pass_value_or_ref<Rhs>::type; \
364 bool cmp = Cmp##NAME##Impl<LhsPassT, RhsPassT>(lhs, rhs); \
365 return V8_LIKELY(cmp) \
366 ? nullptr \
367 : MakeCheckOpString<LhsPassT, RhsPassT>(lhs, rhs, msg); \
368 }
369 DEFINE_CHECK_OP_IMPL(EQ, ==)
370 DEFINE_CHECK_OP_IMPL(NE, !=)
371 DEFINE_CHECK_OP_IMPL(LE, <=)
372 DEFINE_CHECK_OP_IMPL(LT, < )
373 DEFINE_CHECK_OP_IMPL(GE, >=)
374 DEFINE_CHECK_OP_IMPL(GT, > )
375 #undef DEFINE_CHECK_OP_IMPL
376
377 #define CHECK_EQ(lhs, rhs) CHECK_OP(EQ, ==, lhs, rhs)
378 #define CHECK_NE(lhs, rhs) CHECK_OP(NE, !=, lhs, rhs)
379 #define CHECK_LE(lhs, rhs) CHECK_OP(LE, <=, lhs, rhs)
380 #define CHECK_LT(lhs, rhs) CHECK_OP(LT, <, lhs, rhs)
381 #define CHECK_GE(lhs, rhs) CHECK_OP(GE, >=, lhs, rhs)
382 #define CHECK_GT(lhs, rhs) CHECK_OP(GT, >, lhs, rhs)
383 #define CHECK_NULL(val) CHECK((val) == nullptr)
384 #define CHECK_NOT_NULL(val) CHECK((val) != nullptr)
385 #define CHECK_IMPLIES(lhs, rhs) \
386 CHECK_WITH_MSG(!(lhs) || (rhs), #lhs " implies " #rhs)
387
388 } // namespace base
389 } // namespace v8
390
391
392 // The DCHECK macro is equivalent to CHECK except that it only
393 // generates code in debug builds.
394 #ifdef DEBUG
395 #define DCHECK_EQ(lhs, rhs) DCHECK_OP(EQ, ==, lhs, rhs)
396 #define DCHECK_NE(lhs, rhs) DCHECK_OP(NE, !=, lhs, rhs)
397 #define DCHECK_GT(lhs, rhs) DCHECK_OP(GT, >, lhs, rhs)
398 #define DCHECK_GE(lhs, rhs) DCHECK_OP(GE, >=, lhs, rhs)
399 #define DCHECK_LT(lhs, rhs) DCHECK_OP(LT, <, lhs, rhs)
400 #define DCHECK_LE(lhs, rhs) DCHECK_OP(LE, <=, lhs, rhs)
401 #define DCHECK_NULL(val) DCHECK((val) == nullptr)
402 #define DCHECK_NOT_NULL(val) DCHECK((val) != nullptr)
403 #define DCHECK_IMPLIES(lhs, rhs) \
404 DCHECK_WITH_MSG(!(lhs) || (rhs), #lhs " implies " #rhs)
405 #else
406 #define DCHECK(condition) ((void) 0)
407 #define DCHECK_EQ(v1, v2) ((void) 0)
408 #define DCHECK_NE(v1, v2) ((void) 0)
409 #define DCHECK_GT(v1, v2) ((void) 0)
410 #define DCHECK_GE(v1, v2) ((void) 0)
411 #define DCHECK_LT(v1, v2) ((void) 0)
412 #define DCHECK_LE(v1, v2) ((void) 0)
413 #define DCHECK_NULL(val) ((void) 0)
414 #define DCHECK_NOT_NULL(val) ((void) 0)
415 #define DCHECK_IMPLIES(v1, v2) ((void) 0)
416 #endif
417
418 #endif // V8_BASE_LOGGING_H_
419