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