GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/util/safe_print.cpp Lines: 73 102 71.6 %
Date: 2021-03-22 Branches: 43 84 51.2 %

Line Exec Source
1
/*********************                                                        */
2
/*! \file safe_print.cpp
3
 ** \verbatim
4
 ** Top contributors (to current version):
5
 **   Andres Noetzli
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 Definition of print functions that are safe to use in a signal
13
 ** 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. All output is written to file
18
 ** descriptors using the async-signal-safe write() function.
19
 **/
20
21
#include "safe_print.h"
22
23
#include <time.h>
24
#include <unistd.h>
25
26
#include <cstdlib>
27
28
/* Size of buffers used */
29
#define BUFFER_SIZE 20
30
31
namespace CVC4 {
32
33
template <>
34
6
void safe_print(int fd, const std::string& msg) {
35
  // Print characters one by one instead of using
36
  // string::data()/string::c_str() to avoid allocations (pre-c++11)
37
96
  for (size_t i = 0; i < msg.length(); i++) {
38
90
    if (write(fd, &(msg[i]), 1) != 1) {
39
      abort();
40
    }
41
  }
42
6
}
43
44
template <>
45
14
void safe_print(int fd, const int64_t& _i) {
46
  char buf[BUFFER_SIZE];
47
14
  int64_t i = _i;
48
49
14
  if (i == 0) {
50
    safe_print(fd, "0");
51
    return;
52
14
  } else if (i < 0) {
53
2
    safe_print(fd, "-");
54
2
    i *= -1;
55
  }
56
57
  // This loop fills the buffer from the end. The number of elements in the
58
  // buffer is BUFER_SIZE - idx - 1 and they start at position idx + 1.
59
14
  ssize_t idx = BUFFER_SIZE - 1;
60
70
  while (i != 0 && idx >= 0) {
61
28
    buf[idx] = '0' + i % 10;
62
28
    i /= 10;
63
28
    idx--;
64
  }
65
66
14
  ssize_t nbyte = BUFFER_SIZE - idx - 1;
67
14
  if (write(fd, buf + idx + 1, nbyte) != nbyte) {
68
    abort();
69
  }
70
}
71
72
template <>
73
void safe_print(int fd, const int32_t& i) {
74
  safe_print<int64_t>(fd, i);
75
}
76
77
template <>
78
12
void safe_print(int fd, const uint64_t& _i) {
79
  char buf[BUFFER_SIZE];
80
12
  uint64_t i = _i;
81
82
12
  if (i == 0) {
83
2
    safe_print(fd, "0");
84
2
    return;
85
  }
86
87
  // This loop fills the buffer from the end. The number of elements in the
88
  // buffer is BUFER_SIZE - idx - 1 and they start at position idx + 1.
89
10
  ssize_t idx = BUFFER_SIZE - 1;
90
30
  while (i != 0 && idx >= 0) {
91
10
    buf[idx] = '0' + i % 10;
92
10
    i /= 10;
93
10
    idx--;
94
  }
95
96
10
  ssize_t nbyte = BUFFER_SIZE - idx - 1;
97
10
  if (write(fd, buf + idx + 1, nbyte) != nbyte) {
98
    abort();
99
  }
100
}
101
102
template <>
103
void safe_print(int fd, const uint32_t& i) {
104
  safe_print<uint64_t>(fd, i);
105
}
106
107
template <>
108
6
void safe_print(int fd, const double& _d) {
109
  // Note: this print function for floating-point values is optimized for
110
  // simplicity, not correctness or performance.
111
  char buf[BUFFER_SIZE];
112
6
  double d = _d;
113
114
6
  ssize_t i = 0;
115
6
  int64_t v = static_cast<int64_t>(d);
116
6
  d -= v;
117
118
6
  if (d < 0.0) {
119
2
    d *= -1.0;
120
  }
121
122
6
  safe_print<int64_t>(fd, v);
123
6
  safe_print(fd, ".");
124
125
  // Print decimal digits as long as the remaining value is larger than zero
126
  // and print at least one digit.
127
18
  while (i == 0 || (d > 0.0 && i < BUFFER_SIZE)) {
128
6
    d *= 10.0;
129
6
    char c = static_cast<char>(d);
130
6
    buf[i] = '0' + c;
131
6
    d -= c;
132
6
    i++;
133
  }
134
135
6
  if (write(fd, buf, i) != i) {
136
    abort();
137
  }
138
6
}
139
140
template <>
141
void safe_print(int fd, const float& f) {
142
  safe_print<double>(fd, (double)f);
143
}
144
145
template <>
146
2
void safe_print(int fd, const bool& b) {
147
2
  if (b) {
148
2
    safe_print(fd, "true");
149
  } else {
150
    safe_print(fd, "false");
151
  }
152
2
}
153
154
template <>
155
2
void safe_print(int fd, void* const& addr) {
156
2
  safe_print_hex(fd, (uint64_t)addr);
157
2
}
158
159
template <>
160
void safe_print(int fd, const timespec& t) {
161
  safe_print<uint64_t>(fd, t.tv_sec);
162
  safe_print(fd, ".");
163
  safe_print_right_aligned(fd, t.tv_nsec, 9);
164
}
165
166
2
void safe_print_hex(int fd, uint64_t i) {
167
  char buf[BUFFER_SIZE];
168
169
2
  safe_print(fd, "0x");
170
2
  if (i == 0) {
171
    safe_print(fd, "0");
172
    return;
173
  }
174
175
  // This loop fills the buffer from the end. The number of elements in the
176
  // buffer is BUFER_SIZE - idx - 1 and they start at position idx + 1.
177
2
  ssize_t idx = BUFFER_SIZE - 1;
178
34
  while (i != 0 && idx >= 0) {
179
16
    char current = i % 16;
180
16
    if (current <= 9) {
181
      buf[idx] = '0' + current;
182
    } else {
183
16
      buf[idx] = 'a' + current - 10;
184
    }
185
16
    i /= 16;
186
16
    idx--;
187
  }
188
189
2
  ssize_t nbyte = BUFFER_SIZE - idx - 1;
190
2
  if (write(fd, buf + idx + 1, nbyte) != nbyte) {
191
    abort();
192
  }
193
}
194
195
2
void safe_print_right_aligned(int fd, uint64_t i, ssize_t width) {
196
  char buf[BUFFER_SIZE];
197
198
  // Make sure that the result fits in the buffer
199
2
  width = (width < BUFFER_SIZE) ? width : BUFFER_SIZE;
200
201
20
  for (ssize_t j = 0; j < width; j++) {
202
18
    buf[j] = '0';
203
  }
204
205
2
  ssize_t idx = width - 1;
206
2
  while (i != 0 && idx >= 0) {
207
    buf[idx] = '0' + i % 10;
208
    i /= 10;
209
    idx--;
210
  }
211
212
2
  if (write(fd, buf, width) != width) {
213
    abort();
214
  }
215
2
}
216
217
} /* CVC4 namespace */