1 // Copyright 2019 The Chromium 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 TOOLS_CDDL_LOGGING_H_ 6 #define TOOLS_CDDL_LOGGING_H_ 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 11 #include <cstdlib> 12 #include <iostream> 13 #include <string> 14 #include <utility> 15 16 #define CHECK(condition) (condition) ? (void)0 : Logger::Abort(#condition) 17 18 #define CHECK_EQ(a, b) CHECK((a) == (b)) 19 #define CHECK_NE(a, b) CHECK((a) != (b)) 20 #define CHECK_LT(a, b) CHECK((a) < (b)) 21 #define CHECK_LE(a, b) CHECK((a) <= (b)) 22 #define CHECK_GT(a, b) CHECK((a) > (b)) 23 #define CHECK_GE(a, b) CHECK((a) >= (b)) 24 25 // TODO(crbug.com/openscreen/75): 26 // #1: This class has no state, so it doesn't need to be a singleton, just 27 // a collection of static functions. 28 // 29 // #2: Convert to stream oriented logging to clean up security warnings. 30 class Logger { 31 public: 32 // Writes a log to the global singleton instance of Logger. 33 template <typename... Args> Log(const std::string & message,Args &&...args)34 static void Log(const std::string& message, Args&&... args) { 35 Logger::Get()->WriteLog(message, std::forward<Args>(args)...); 36 } 37 38 // Writes an error to the global singleton instance of Logger. 39 template <typename... Args> Error(const std::string & message,Args &&...args)40 static void Error(const std::string& message, Args&&... args) { 41 Logger::Get()->WriteError(message, std::forward<Args>(args)...); 42 } 43 44 // Returns the singleton instance of Logger. 45 static Logger* Get(); 46 47 // Aborts the program after logging the condition that caused the 48 // CHECK-failure. 49 static void Abort(const char* condition); 50 51 private: 52 // Creates and initializes the logging file associated with this logger. 53 void InitializeInstance(); 54 55 // Limit calling the constructor/destructor to from within this same class. 56 Logger(); 57 58 // Represents whether this instance has been initialized. 59 bool is_initialized_; 60 61 // Singleton instance of logger. At the beginning of runtime it's initiated to 62 // nullptr due to zero initialization. 63 static Logger* singleton_; 64 65 // Exits the program if initialization has not occured. 66 void VerifyInitialized(); 67 68 // fprintf doesn't like passing strings as parameters, so use overloads to 69 // convert all C++ std::string types into C strings. 70 template <class T> MakePrintable(const T data)71 T MakePrintable(const T data) { 72 return data; 73 } 74 75 const char* MakePrintable(const std::string& data); 76 77 // Writes a log message to this instance of Logger's text file. 78 template <typename... Args> WriteToStream(const std::string & message,Args &&...args)79 void WriteToStream(const std::string& message, Args&&... args) { 80 VerifyInitialized(); 81 82 // NOTE: wihout the #pragma suppressions, the below line fails. There is a 83 // warning generated since the compiler is attempting to prevent a string 84 // format vulnerability. This is not a risk for us since this code is only 85 // used at compile time. The below #pragma commands suppress the warning for 86 // just the one dprintf(...) line. 87 // For more details: https://www.owasp.org/index.php/Format_string_attack 88 char* str_buffer; 89 #if defined(__clang__) 90 #pragma clang diagnostic push 91 #pragma clang diagnostic ignored "-Wformat-security" 92 #elif defined(__GNUC__) 93 #pragma GCC diagnostic push 94 #pragma GCC diagnostic ignored "-Wformat-security" 95 #endif // defined(__clang__) 96 int byte_count = asprintf(&str_buffer, message.c_str(), 97 this->MakePrintable(std::forward<Args>(args))...); 98 #if defined(__clang__) 99 #pragma clang diagnostic pop 100 #elif defined(__GNUC__) 101 #pragma GCC diagnostic pop 102 #endif // defined(__clang__) 103 CHECK_GE(byte_count, 0); 104 std::cerr << str_buffer << std::endl; 105 free(str_buffer); 106 } 107 108 // Writes an error message. 109 template <typename... Args> WriteError(const std::string & message,Args &&...args)110 void WriteError(const std::string& message, Args&&... args) { 111 WriteToStream("Error: " + message, std::forward<Args>(args)...); 112 } 113 114 // Writes a log message. 115 template <typename... Args> WriteLog(const std::string & message,Args &&...args)116 void WriteLog(const std::string& message, Args&&... args) { 117 WriteToStream(message, std::forward<Args>(args)...); 118 } 119 }; 120 121 #endif // TOOLS_CDDL_LOGGING_H_ 122