GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/util/safe_print.h Lines: 13 15 86.7 %
Date: 2021-03-23 Branches: 5 32 15.6 %

Line Exec Source
1
/*********************                                                        */
2
/*! \file safe_print.h
3
 ** \verbatim
4
 ** Top contributors (to current version):
5
 **   Andres Noetzli, Mathias Preiner
6
 ** This file is part of the CVC4 project.
7
 ** Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 ** in the top-level source directory and their institutional affiliations.
9
 ** All rights reserved.  See the file COPYING in the top-level source
10
 ** directory for licensing information.\endverbatim
11
 **
12
 ** \brief Print functions that are safe to use in a signal handler.
13
 **
14
 ** Signal handlers only allow a very limited set of operations, e.g. dynamic
15
 ** memory allocation is not possible. This set of functions can be used to
16
 ** print information from a signal handler.
17
 **
18
 ** The safe_print function takes a template parameter T and prints an argument
19
 ** of type const T& to avoid copying, e.g. when printing std::strings. For
20
 ** consistency, we also pass primitive types by reference (otherwise, functions
21
 ** in statistics_registry.h would require specialization or we would have to
22
 ** use function overloading).
23
 **
24
 ** If there exists a function `toString(obj)` for a given object, it will be
25
 ** used automatically. This is useful for printing enum values for example.
26
 ** IMPORTANT: The `toString(obj)` function *must not* perform any allocations
27
 ** or call other functions that are not async-signal-safe.
28
 **
29
 ** This header is a "cvc4_private_library.h" header because it is private but
30
 ** the safe_print functions are used in the driver. See also the description
31
 ** of "statistics_registry.h" for more information on
32
 ** "cvc4_private_library.h".
33
 **/
34
35
#include "cvc4_private_library.h"
36
37
#ifndef CVC4__SAFE_PRINT_H
38
#define CVC4__SAFE_PRINT_H
39
40
#include <unistd.h>
41
42
#include <cstring>
43
#include <string>
44
45
#include "cvc4_export.h"
46
47
namespace CVC4 {
48
49
/**
50
 * Prints arrays of chars (e.g. string literals) of length N. Safe to use in a
51
 * signal handler.
52
 */
53
template <size_t N>
54
84
void CVC4_EXPORT safe_print(int fd, const char (&msg)[N])
55
{
56
84
  ssize_t nb = N - 1;
57
84
  if (write(fd, msg, nb) != nb) {
58
    abort();
59
  }
60
84
}
61
62
/**
63
 * The default method for converting an object to a string for safe printing.
64
 * This method simply returns "<unsupported>". The `long` argument is used to
65
 * indicate that we do not prefer this method over the version that calls
66
 * `toString()`.
67
 */
68
template <typename T>
69
2
const char* toStringImpl(const T& obj, long)
70
{
71
2
  return "<unsupported>";
72
}
73
74
/**
75
 * Returns the result of calling `toString(obj)`. This method is only defined
76
 * if such an overload of `toString()` exists. To detect the existence of such
77
 * a method, we use SFINAE and a trailing return type. The trailing return type
78
 * is necessary because it allows us to refer to `obj`. The `int` argument is
79
 * used to prefer this version of the function instead of the one that prints
80
 * "<unsupported>".
81
 */
82
template <typename T>
83
4
auto toStringImpl(const T& obj, int) -> decltype(toString(obj))
84
{
85
4
  return toString(obj);
86
}
87
88
/**
89
 * Prints a variable of type T. Safe to use in a signal handler. The default
90
 * implementation either prints "<unsupported>" or the result of calling
91
 * `toString(obj)` if such a method exists (this is useful for printing enum
92
 * values for example without implementing a template specialization here).
93
 *
94
 * @param fd The file descriptor to print to
95
 * @param obj The object to print
96
 */
97
template <typename T>
98
6
void CVC4_EXPORT safe_print(int fd, const T& obj)
99
{
100
6
  const char* s =
101
      toStringImpl(obj, /* prefer the method that uses `toString()` */ 0);
102
6
  ssize_t slen = static_cast<ssize_t>(strlen(s));
103
6
  if (write(fd, s, slen) != slen)
104
  {
105
    abort();
106
  }
107
6
}
108
109
template <>
110
void CVC4_EXPORT safe_print(int fd, const std::string& msg);
111
template <>
112
void CVC4_EXPORT safe_print(int fd, const int64_t& _i);
113
template <>
114
void CVC4_EXPORT safe_print(int fd, const int32_t& i);
115
template <>
116
void CVC4_EXPORT safe_print(int fd, const uint64_t& _i);
117
template <>
118
void CVC4_EXPORT safe_print(int fd, const uint32_t& i);
119
template <>
120
void CVC4_EXPORT safe_print(int fd, const double& _d);
121
template <>
122
void CVC4_EXPORT safe_print(int fd, const float& f);
123
template <>
124
void CVC4_EXPORT safe_print(int fd, const bool& b);
125
template <>
126
void CVC4_EXPORT safe_print(int fd, void* const& addr);
127
template <>
128
void CVC4_EXPORT safe_print(int fd, const timespec& t);
129
130
/** Prints an integer in hexadecimal. Safe to use in a signal handler. */
131
void safe_print_hex(int fd, uint64_t i);
132
133
/**
134
 * Prints a right aligned number. Fills up remaining space with zeros. Safe to
135
 * use in a signal handler.
136
 */
137
void safe_print_right_aligned(int fd, uint64_t i, ssize_t width);
138
139
} /* CVC4 namespace */
140
141
#endif /* CVC4__SAFE_PRINT_H */