Switch to folly symbolizer
[folly.git] / folly / String.cpp
1 /*
2  * Copyright 2013 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "folly/String.h"
18 #include "folly/Format.h"
19
20 #include <cerrno>
21 #include <cstdarg>
22 #include <cstring>
23 #include <stdexcept>
24 #include <iterator>
25 #include <glog/logging.h>
26
27 #undef FOLLY_DEMANGLE
28
29 #if defined(__GNUG__) && __GNUG__ >= 4
30 # include <cxxabi.h>
31 # define FOLLY_DEMANGLE 1
32
33 // From libiberty
34 //
35 // TODO(tudorb): Detect this with autoconf for the open-source version.
36 //
37 // __attribute__((weak)) doesn't work, because cplus_demangle_v3_callback
38 // is exported by an object file in libiberty.a, and the ELF spec says
39 // "The link editor does not extract archive members to resolve undefined weak
40 // symbols" (but, interestingly enough, will resolve undefined weak symbols
41 // with definitions from archive members that were extracted in order to
42 // resolve an undefined global (strong) symbol)
43
44 # ifndef DMGL_NO_OPTS
45 #  define FOLLY_DEFINED_DMGL 1
46 #  define DMGL_NO_OPTS    0          /* For readability... */
47 #  define DMGL_PARAMS     (1 << 0)   /* Include function args */
48 #  define DMGL_ANSI       (1 << 1)   /* Include const, volatile, etc */
49 #  define DMGL_JAVA       (1 << 2)   /* Demangle as Java rather than C++. */
50 #  define DMGL_VERBOSE    (1 << 3)   /* Include implementation details.  */
51 #  define DMGL_TYPES      (1 << 4)   /* Also try to demangle type encodings.  */
52 #  define DMGL_RET_POSTFIX (1 << 5)  /* Print function return types (when
53                                         present) after function signature */
54 # endif
55
56 extern "C" int cplus_demangle_v3_callback(
57     const char* mangled,
58     int options,  // We use DMGL_PARAMS | DMGL_TYPES, aka 0x11
59     void (*callback)(const char*, size_t, void*),
60     void* arg);
61
62 #endif
63
64 namespace folly {
65
66 namespace {
67
68 inline void stringPrintfImpl(std::string& output, const char* format,
69                              va_list args) {
70   // Tru to the space at the end of output for our output buffer.
71   // Find out write point then inflate its size temporarily to its
72   // capacity; we will later shrink it to the size needed to represent
73   // the formatted string.  If this buffer isn't large enough, we do a
74   // resize and try again.
75
76   const auto write_point = output.size();
77   auto remaining = output.capacity() - write_point;
78   output.resize(output.capacity());
79
80   va_list args_copy;
81   va_copy(args_copy, args);
82   int bytes_used = vsnprintf(&output[write_point], remaining, format,
83                              args_copy);
84   va_end(args_copy);
85   if (bytes_used < 0) {
86     throw std::runtime_error(
87       to<std::string>("Invalid format string; snprintf returned negative "
88                       "with format string: ", format));
89   } else if (bytes_used < remaining) {
90     // There was enough room, just shrink and return.
91     output.resize(write_point + bytes_used);
92   } else {
93     output.resize(write_point + bytes_used + 1);
94     remaining = bytes_used + 1;
95     va_list args_copy;
96     va_copy(args_copy, args);
97     bytes_used = vsnprintf(&output[write_point], remaining, format,
98                            args_copy);
99     va_end(args_copy);
100     if (bytes_used + 1 != remaining) {
101       throw std::runtime_error(
102         to<std::string>("vsnprint retry did not manage to work "
103                         "with format string: ", format));
104     }
105     output.resize(write_point + bytes_used);
106   }
107 }
108
109 }  // anon namespace
110
111 std::string stringPrintf(const char* format, ...) {
112   // snprintf will tell us how large the output buffer should be, but
113   // we then have to call it a second time, which is costly.  By
114   // guestimating the final size, we avoid the double snprintf in many
115   // cases, resulting in a performance win.  We use this constructor
116   // of std::string to avoid a double allocation, though it does pad
117   // the resulting string with nul bytes.  Our guestimation is twice
118   // the format string size, or 32 bytes, whichever is larger.  This
119   // is a hueristic that doesn't affect correctness but attempts to be
120   // reasonably fast for the most common cases.
121   std::string ret(std::max(32UL, strlen(format) * 2), '\0');
122   ret.resize(0);
123
124   va_list ap;
125   va_start(ap, format);
126   stringPrintfImpl(ret, format, ap);
127   va_end(ap);
128   return ret;
129 }
130
131 // Basic declarations; allow for parameters of strings and string
132 // pieces to be specified.
133 std::string& stringAppendf(std::string* output, const char* format, ...) {
134   va_list ap;
135   va_start(ap, format);
136   stringPrintfImpl(*output, format, ap);
137   va_end(ap);
138   return *output;
139 }
140
141 void stringPrintf(std::string* output, const char* format, ...) {
142   output->clear();
143   va_list ap;
144   va_start(ap, format);
145   stringPrintfImpl(*output, format, ap);
146   va_end(ap);
147 };
148
149 namespace {
150
151 struct PrettySuffix {
152   const char* suffix;
153   double val;
154 };
155
156 const PrettySuffix kPrettyTimeSuffixes[] = {
157   { "s ", 1e0L },
158   { "ms", 1e-3L },
159   { "us", 1e-6L },
160   { "ns", 1e-9L },
161   { "ps", 1e-12L },
162   { "s ", 0 },
163   { 0, 0 },
164 };
165
166 const PrettySuffix kPrettyBytesMetricSuffixes[] = {
167   { "TB", 1e12L },
168   { "GB", 1e9L },
169   { "MB", 1e6L },
170   { "kB", 1e3L },
171   { "B ", 0L },
172   { 0, 0 },
173 };
174
175 const PrettySuffix kPrettyBytesBinarySuffixes[] = {
176   { "TB", int64_t(1) << 40 },
177   { "GB", int64_t(1) << 30 },
178   { "MB", int64_t(1) << 20 },
179   { "kB", int64_t(1) << 10 },
180   { "B ", 0L },
181   { 0, 0 },
182 };
183
184 const PrettySuffix kPrettyBytesBinaryIECSuffixes[] = {
185   { "TiB", int64_t(1) << 40 },
186   { "GiB", int64_t(1) << 30 },
187   { "MiB", int64_t(1) << 20 },
188   { "KiB", int64_t(1) << 10 },
189   { "B  ", 0L },
190   { 0, 0 },
191 };
192
193 const PrettySuffix kPrettyUnitsMetricSuffixes[] = {
194   { "tril", 1e12L },
195   { "bil",  1e9L },
196   { "M",    1e6L },
197   { "k",    1e3L },
198   { " ",      0  },
199   { 0, 0 },
200 };
201
202 const PrettySuffix kPrettyUnitsBinarySuffixes[] = {
203   { "T", int64_t(1) << 40 },
204   { "G", int64_t(1) << 30 },
205   { "M", int64_t(1) << 20 },
206   { "k", int64_t(1) << 10 },
207   { " ", 0 },
208   { 0, 0 },
209 };
210
211 const PrettySuffix kPrettyUnitsBinaryIECSuffixes[] = {
212   { "Ti", int64_t(1) << 40 },
213   { "Gi", int64_t(1) << 30 },
214   { "Mi", int64_t(1) << 20 },
215   { "Ki", int64_t(1) << 10 },
216   { "  ", 0 },
217   { 0, 0 },
218 };
219
220 const PrettySuffix* const kPrettySuffixes[PRETTY_NUM_TYPES] = {
221   kPrettyTimeSuffixes,
222   kPrettyBytesMetricSuffixes,
223   kPrettyBytesBinarySuffixes,
224   kPrettyBytesBinaryIECSuffixes,
225   kPrettyUnitsMetricSuffixes,
226   kPrettyUnitsBinarySuffixes,
227   kPrettyUnitsBinaryIECSuffixes,
228 };
229
230 }  // namespace
231
232 std::string prettyPrint(double val, PrettyType type, bool addSpace) {
233   char buf[100];
234
235   // pick the suffixes to use
236   assert(type >= 0);
237   assert(type < PRETTY_NUM_TYPES);
238   const PrettySuffix* suffixes = kPrettySuffixes[type];
239
240   // find the first suffix we're bigger than -- then use it
241   double abs_val = fabs(val);
242   for (int i = 0; suffixes[i].suffix; ++i) {
243     if (abs_val >= suffixes[i].val) {
244       snprintf(buf, sizeof buf, "%.4g%s%s",
245                (suffixes[i].val ? (val / suffixes[i].val)
246                                 : val),
247                (addSpace ? " " : ""),
248                suffixes[i].suffix);
249       return std::string(buf);
250     }
251   }
252
253   // no suffix, we've got a tiny value -- just print it in sci-notation
254   snprintf(buf, sizeof buf, "%.4g", val);
255   return std::string(buf);
256 }
257
258 std::string hexDump(const void* ptr, size_t size) {
259   std::ostringstream os;
260   hexDump(ptr, size, std::ostream_iterator<StringPiece>(os, "\n"));
261   return os.str();
262 }
263
264 fbstring errnoStr(int err) {
265   int savedErrno = errno;
266
267   // Ensure that we reset errno upon exit.
268   auto guard(makeGuard([&] { errno = savedErrno; }));
269
270   char buf[1024];
271   buf[0] = '\0';
272
273   fbstring result;
274
275   // https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/strerror_r.3.html
276   // http://www.kernel.org/doc/man-pages/online/pages/man3/strerror.3.html
277 #if defined(__APPLE__) || defined(__FreeBSD__) || \
278     ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
279   // Using XSI-compatible strerror_r
280   int r = strerror_r(err, buf, sizeof(buf));
281
282   // OSX/FreeBSD use EINVAL and Linux uses -1 so just check for non-zero
283   if (r != 0) {
284     result = to<fbstring>(
285       "Unknown error ", err,
286       " (strerror_r failed with error ", errno, ")");
287   } else {
288     result.assign(buf);
289   }
290 #else
291   // Using GNU strerror_r
292   result.assign(strerror_r(err, buf, sizeof(buf)));
293 #endif
294
295   return result;
296 }
297
298 namespace {
299
300 // glibc doesn't have strlcpy
301 size_t my_strlcpy(char* dest, const char* src, size_t size) {
302   size_t len = strlen(src);
303   if (size != 0) {
304     size_t n = std::min(len, size - 1);  // always null terminate!
305     memcpy(dest, src, n);
306     dest[n] = '\0';
307   }
308   return len;
309 }
310
311 }  // namespace
312
313 #ifdef FOLLY_DEMANGLE
314
315 fbstring demangle(const char* name) {
316   int status;
317   size_t len = 0;
318   // malloc() memory for the demangled type name
319   char* demangled = abi::__cxa_demangle(name, nullptr, &len, &status);
320   if (status != 0) {
321     return name;
322   }
323   // len is the length of the buffer (including NUL terminator and maybe
324   // other junk)
325   return fbstring(demangled, strlen(demangled), len, AcquireMallocatedString());
326 }
327
328 namespace {
329
330 struct DemangleBuf {
331   char* dest;
332   size_t remaining;
333   size_t total;
334 };
335
336 void demangleCallback(const char* str, size_t size, void* p) {
337   DemangleBuf* buf = static_cast<DemangleBuf*>(p);
338   size_t n = std::min(buf->remaining, size);
339   memcpy(buf->dest, str, n);
340   buf->dest += n;
341   buf->remaining -= n;
342   buf->total += size;
343 }
344
345 }  // namespace
346
347 size_t demangle(const char* name, char* out, size_t outSize) {
348   DemangleBuf dbuf;
349   dbuf.dest = out;
350   dbuf.remaining = outSize ? outSize - 1 : 0;   // leave room for null term
351   dbuf.total = 0;
352
353   // Unlike most library functions, this returns 1 on success and 0 on failure
354   int status = cplus_demangle_v3_callback(
355       name,
356       DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES,
357       demangleCallback,
358       &dbuf);
359   if (status == 0) {  // failed, return original
360     return my_strlcpy(out, name, outSize);
361   }
362   if (outSize != 0) {
363     *dbuf.dest = '\0';
364   }
365   return dbuf.total;
366 }
367
368 #else
369
370 fbstring demangle(const char* name) {
371   return name;
372 }
373
374 size_t demangle(const char* name, char* out, size_t outSize) {
375   return my_strlcpy(out, name, outSize);
376 }
377
378 #endif
379 #undef FOLLY_DEMANGLE
380
381 namespace detail {
382
383 size_t hexDumpLine(const void* ptr, size_t offset, size_t size,
384                    std::string& line) {
385   // Line layout:
386   // 8: address
387   // 1: space
388   // (1+2)*16: hex bytes, each preceded by a space
389   // 1: space separating the two halves
390   // 3: "  |"
391   // 16: characters
392   // 1: "|"
393   // Total: 78
394   line.clear();
395   line.reserve(78);
396   const uint8_t* p = reinterpret_cast<const uint8_t*>(ptr) + offset;
397   size_t n = std::min(size - offset, size_t(16));
398   format("{:08x} ", offset).appendTo(line);
399
400   for (size_t i = 0; i < n; i++) {
401     if (i == 8) {
402       line.push_back(' ');
403     }
404     format(" {:02x}", p[i]).appendTo(line);
405   }
406
407   // 3 spaces for each byte we're not printing, one separating the halves
408   // if necessary
409   line.append(3 * (16 - n) + (n <= 8), ' ');
410   line.append("  |");
411
412   for (size_t i = 0; i < n; i++) {
413     char c = (p[i] >= 32 && p[i] <= 126 ? static_cast<char>(p[i]) : '.');
414     line.push_back(c);
415   }
416   line.append(16 - n, ' ');
417   line.push_back('|');
418   DCHECK_EQ(line.size(), 78);
419
420   return n;
421 }
422
423 } // namespace detail
424
425 }   // namespace folly
426
427 #ifdef FOLLY_DEFINED_DMGL
428 # undef FOLLY_DEFINED_DMGL
429 # undef DMGL_NO_OPTS
430 # undef DMGL_PARAMS
431 # undef DMGL_ANSI
432 # undef DMGL_JAVA
433 # undef DMGL_VERBOSE
434 # undef DMGL_TYPES
435 # undef DMGL_RET_POSTFIX
436 #endif
437