// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef TOOLS_CDDL_LOGGING_H_ #define TOOLS_CDDL_LOGGING_H_ #include #include #include #include #include #include #define CHECK(condition) (condition) ? (void)0 : Logger::Abort(#condition) #define CHECK_EQ(a, b) CHECK((a) == (b)) #define CHECK_NE(a, b) CHECK((a) != (b)) #define CHECK_LT(a, b) CHECK((a) < (b)) #define CHECK_LE(a, b) CHECK((a) <= (b)) #define CHECK_GT(a, b) CHECK((a) > (b)) #define CHECK_GE(a, b) CHECK((a) >= (b)) // TODO(crbug.com/openscreen/75): // #1: This class has no state, so it doesn't need to be a singleton, just // a collection of static functions. // // #2: Convert to stream oriented logging to clean up security warnings. class Logger { public: // Writes a log to the global singleton instance of Logger. template static void Log(const std::string& message, Args&&... args) { Logger::Get()->WriteLog(message, std::forward(args)...); } // Writes an error to the global singleton instance of Logger. template static void Error(const std::string& message, Args&&... args) { Logger::Get()->WriteError(message, std::forward(args)...); } // Returns the singleton instance of Logger. static Logger* Get(); // Aborts the program after logging the condition that caused the // CHECK-failure. static void Abort(const char* condition); private: // Creates and initializes the logging file associated with this logger. void InitializeInstance(); // Limit calling the constructor/destructor to from within this same class. Logger(); // Represents whether this instance has been initialized. bool is_initialized_; // Singleton instance of logger. At the beginning of runtime it's initiated to // nullptr due to zero initialization. static Logger* singleton_; // Exits the program if initialization has not occured. void VerifyInitialized(); // fprintf doesn't like passing strings as parameters, so use overloads to // convert all C++ std::string types into C strings. template T MakePrintable(const T data) { return data; } const char* MakePrintable(const std::string& data); // Writes a log message to this instance of Logger's text file. template void WriteToStream(const std::string& message, Args&&... args) { VerifyInitialized(); // NOTE: wihout the #pragma suppressions, the below line fails. There is a // warning generated since the compiler is attempting to prevent a string // format vulnerability. This is not a risk for us since this code is only // used at compile time. The below #pragma commands suppress the warning for // just the one dprintf(...) line. // For more details: https://www.owasp.org/index.php/Format_string_attack char* str_buffer; #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wformat-security" #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-security" #endif // defined(__clang__) int byte_count = asprintf(&str_buffer, message.c_str(), this->MakePrintable(std::forward(args))...); #if defined(__clang__) #pragma clang diagnostic pop #elif defined(__GNUC__) #pragma GCC diagnostic pop #endif // defined(__clang__) CHECK_GE(byte_count, 0); std::cerr << str_buffer << std::endl; free(str_buffer); } // Writes an error message. template void WriteError(const std::string& message, Args&&... args) { WriteToStream("Error: " + message, std::forward(args)...); } // Writes a log message. template void WriteLog(const std::string& message, Args&&... args) { WriteToStream(message, std::forward(args)...); } }; #endif // TOOLS_CDDL_LOGGING_H_