GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/util/safe_print.h Lines: 0 15 0.0 %
Date: 2021-11-05 Branches: 0 32 0.0 %

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