1 /* Copyright (c) 2003-2004, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
8 * \brief Compatibility wrappers around snprintf and its friends
11 #include "lib/cc/torint.h"
12 #include "lib/string/printf.h"
13 #include "lib/err/torerr.h"
14 #include "lib/malloc/malloc.h"
19 /** Replacement for snprintf. Differs from platform snprintf in two
20 * ways: First, always NUL-terminates its output. Second, always
21 * returns -1 if the result is truncated. (Note that this return
22 * behavior does <i>not</i> conform to C99; it just happens to be
23 * easier to emulate "return -1" with conformant implementations than
24 * it is to emulate "return number that would be written" with
25 * non-conformant implementations.) */
27 tor_snprintf(char *str
, size_t size
, const char *format
, ...)
32 r
= tor_vsnprintf(str
,size
,format
,ap
);
37 /** Replacement for vsnprintf; behavior differs as tor_snprintf differs from
41 tor_vsnprintf(char *str
, size_t size
, const char *format
, va_list args
)
45 return -1; /* no place for the NUL */
46 if (size
> SIZE_T_CEILING
)
48 #if defined(_WIN32) && !defined(HAVE_VSNPRINTF)
49 r
= _vsnprintf(str
, size
, format
, args
);
51 r
= vsnprintf(str
, size
, format
, args
);
54 if (r
< 0 || r
>= (ssize_t
)size
)
60 * Portable asprintf implementation. Does a printf() into a newly malloc'd
61 * string. Sets *<b>strp</b> to this string, and returns its length (not
62 * including the terminating NUL character).
64 * You can treat this function as if its implementation were something like
67 tor_snprintf(buf, sizeof(buf), fmt, args);
68 *strp = tor_strdup(buf);
71 * Where _INFINITY_ is an imaginary constant so big that any string can fit
75 tor_asprintf(char **strp
, const char *fmt
, ...)
80 r
= tor_vasprintf(strp
, fmt
, args
);
82 if (!*strp
|| r
< 0) {
84 raw_assert_unreached_msg("Internal error in asprintf");
91 * Portable vasprintf implementation. Does a printf() into a newly malloc'd
92 * string. Differs from regular vasprintf in the same ways that
93 * tor_asprintf() differs from regular asprintf.
96 tor_vasprintf(char **strp
, const char *fmt
, va_list args
)
98 /* use a temporary variable in case *strp is in args. */
100 #ifdef HAVE_VASPRINTF
101 /* If the platform gives us one, use it. */
102 int r
= vasprintf(&strp_tmp
, fmt
, args
);
104 *strp
= NULL
; // LCOV_EXCL_LINE -- no cross-platform way to force this
108 #elif defined(HAVE__VSCPRINTF)
109 /* On Windows, _vsnprintf won't tell us the length of the string if it
110 * overflows, so we need to use _vcsprintf to tell how much to allocate */
113 va_copy(tmp_args
, args
);
114 len
= _vscprintf(fmt
, tmp_args
);
120 strp_tmp
= tor_malloc((size_t)len
+ 1);
121 r
= _vsnprintf(strp_tmp
, (size_t)len
+1, fmt
, args
);
130 /* Everywhere else, we have a decent vsnprintf that tells us how many
131 * characters we need. We give it a try on a short buffer first, since
132 * it might be nice to avoid the second vsnprintf call.
134 /* XXXX This code spent a number of years broken (see bug 30651). It is
135 * possible that no Tor users actually run on systems without vasprintf() or
136 * _vscprintf(). If so, we should consider removing this code. */
140 va_copy(tmp_args
, args
);
141 /* Use vsnprintf to retrieve needed length. tor_vsnprintf() is not an
142 * option here because it will simply return -1 if buf is not large enough
143 * to hold the complete string.
145 len
= vsnprintf(buf
, sizeof(buf
), fmt
, tmp_args
);
147 buf
[sizeof(buf
) - 1] = '\0';
152 if (len
< (int)sizeof(buf
)) {
153 *strp
= tor_strdup(buf
);
156 strp_tmp
= tor_malloc((size_t)len
+1);
157 /* use of tor_vsnprintf() will ensure string is null terminated */
158 r
= tor_vsnprintf(strp_tmp
, (size_t)len
+1, fmt
, args
);
166 #endif /* defined(HAVE_VASPRINTF) || ... */