/********************* */ /*! \file safe_print.h ** \verbatim ** Top contributors (to current version): ** Andres Noetzli, Mathias Preiner ** This file is part of the CVC4 project. ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS ** in the top-level source directory) and their institutional affiliations. ** All rights reserved. See the file COPYING in the top-level source ** directory for licensing information.\endverbatim ** ** \brief Print functions that are safe to use in a signal handler. ** ** Signal handlers only allow a very limited set of operations, e.g. dynamic ** memory allocation is not possible. This set of functions can be used to ** print information from a signal handler. ** ** The safe_print function takes a template parameter T and prints an argument ** of type const T& to avoid copying, e.g. when printing std::strings. For ** consistency, we also pass primitive types by reference (otherwise, functions ** in statistics_registry.h would require specialization or we would have to ** use function overloading). ** ** If there exists a function `toString(obj)` for a given object, it will be ** used automatically. This is useful for printing enum values for example. ** IMPORTANT: The `toString(obj)` function *must not* perform any allocations ** or call other functions that are not async-signal-safe. ** ** This header is a "cvc4_private_library.h" header because it is private but ** the safe_print functions are used in the driver. See also the description ** of "statistics_registry.h" for more information on ** "cvc4_private_library.h". **/ #include "cvc4_private_library.h" #ifndef CVC4__SAFE_PRINT_H #define CVC4__SAFE_PRINT_H #if __cplusplus >= 201103L // For c++11 and newer #include #else #include #endif #include #include #include #include "lib/clock_gettime.h" #include "util/result.h" namespace CVC4 { /** * Prints arrays of chars (e.g. string literals) of length N. Safe to use in a * signal handler. */ template void CVC4_PUBLIC safe_print(int fd, const char (&msg)[N]) { ssize_t nb = N - 1; if (write(fd, msg, nb) != nb) { abort(); } } /** * The default method for converting an object to a string for safe printing. * This method simply returns "". The `long` argument is used to * indicate that we do not prefer this method over the version that calls * `toString()`. */ template const char* toStringImpl(const T& obj, long) { return ""; } /** * Returns the result of calling `toString(obj)`. This method is only defined * if such an overload of `toString()` exists. To detect the existence of such * a method, we use SFINAE and a trailing return type. The trailing return type * is necessary because it allows us to refer to `obj`. The `int` argument is * used to prefer this version of the function instead of the one that prints * "". */ template auto toStringImpl(const T& obj, int) -> decltype(toString(obj)) { return toString(obj); } /** * Prints a variable of type T. Safe to use in a signal handler. The default * implementation either prints "" or the result of calling * `toString(obj)` if such a method exists (this is useful for printing enum * values for example without implementing a template specialization here). * * @param fd The file descriptor to print to * @param obj The object to print */ template void CVC4_PUBLIC safe_print(int fd, const T& obj) { const char* s = toStringImpl(obj, /* prefer the method that uses `toString()` */ 0); ssize_t slen = static_cast(strlen(s)); if (write(fd, s, slen) != slen) { abort(); } } template <> void CVC4_PUBLIC safe_print(int fd, const std::string& msg); template <> void CVC4_PUBLIC safe_print(int fd, const int64_t& _i); template <> void CVC4_PUBLIC safe_print(int fd, const int32_t& i); template <> void CVC4_PUBLIC safe_print(int fd, const uint64_t& _i); template <> void CVC4_PUBLIC safe_print(int fd, const uint32_t& i); template <> void CVC4_PUBLIC safe_print(int fd, const double& _d); template <> void CVC4_PUBLIC safe_print(int fd, const float& f); template <> void CVC4_PUBLIC safe_print(int fd, const bool& b); template <> void CVC4_PUBLIC safe_print(int fd, void* const& addr); template <> void CVC4_PUBLIC safe_print(int fd, const timespec& t); /** Prints an integer in hexadecimal. Safe to use in a signal handler. */ void safe_print_hex(int fd, uint64_t i); /** * Prints a right aligned number. Fills up remaining space with zeros. Safe to * use in a signal handler. */ void safe_print_right_aligned(int fd, uint64_t i, ssize_t width); } /* CVC4 namespace */ #endif /* CVC4__SAFE_PRINT_H */