Tor 0.4.9.0-alpha-dev
printf.c
Go to the documentation of this file.
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 */
5
6/**
7 * \file printf.c
8 * \brief Compatibility wrappers around snprintf and its friends
9 **/
10
11#include "lib/cc/torint.h"
12#include "lib/string/printf.h"
13#include "lib/err/torerr.h"
14#include "lib/malloc/malloc.h"
15
16#include <stdlib.h>
17#include <stdio.h>
18
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.) */
26int
27tor_snprintf(char *str, size_t size, const char *format, ...)
28{
29 va_list ap;
30 int r;
31 va_start(ap,format);
32 r = tor_vsnprintf(str,size,format,ap);
33 va_end(ap);
34 return r;
35}
36
37/** Replacement for vsnprintf; behavior differs as tor_snprintf differs from
38 * snprintf.
39 */
40int
41tor_vsnprintf(char *str, size_t size, const char *format, va_list args)
42{
43 int r;
44 if (size == 0)
45 return -1; /* no place for the NUL */
46 if (size > SIZE_T_CEILING)
47 return -1;
48#if defined(_WIN32) && !defined(HAVE_VSNPRINTF)
49 r = _vsnprintf(str, size, format, args);
50#else
51 r = vsnprintf(str, size, format, args);
52#endif
53 str[size-1] = '\0';
54 if (r < 0 || r >= (ssize_t)size)
55 return -1;
56 return r;
57}
58
59/**
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).
63 *
64 * You can treat this function as if its implementation were something like
65 <pre>
66 char buf[_INFINITY_];
67 tor_snprintf(buf, sizeof(buf), fmt, args);
68 *strp = tor_strdup(buf);
69 return strlen(*strp):
70 </pre>
71 * Where _INFINITY_ is an imaginary constant so big that any string can fit
72 * into it.
73 */
74int
75tor_asprintf(char **strp, const char *fmt, ...)
76{
77 int r;
78 va_list args;
79 va_start(args, fmt);
80 r = tor_vasprintf(strp, fmt, args);
81 va_end(args);
82 if (!*strp || r < 0) {
83 /* LCOV_EXCL_START */
84 raw_assert_unreached_msg("Internal error in asprintf");
85 /* LCOV_EXCL_STOP */
86 }
87 return r;
88}
89
90/**
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.
94 */
95int
96tor_vasprintf(char **strp, const char *fmt, va_list args)
97{
98 /* use a temporary variable in case *strp is in args. */
99 char *strp_tmp=NULL;
100#ifdef HAVE_VASPRINTF
101 /* If the platform gives us one, use it. */
102 int r = vasprintf(&strp_tmp, fmt, args);
103 if (r < 0)
104 *strp = NULL; // LCOV_EXCL_LINE -- no cross-platform way to force this
105 else
106 *strp = strp_tmp;
107 return r;
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 */
111 int len, r;
112 va_list tmp_args;
113 va_copy(tmp_args, args);
114 len = _vscprintf(fmt, tmp_args);
115 va_end(tmp_args);
116 if (len < 0) {
117 *strp = NULL;
118 return -1;
119 }
120 strp_tmp = tor_malloc((size_t)len + 1);
121 r = _vsnprintf(strp_tmp, (size_t)len+1, fmt, args);
122 if (r != len) {
123 tor_free(strp_tmp);
124 *strp = NULL;
125 return -1;
126 }
127 *strp = strp_tmp;
128 return len;
129#else
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.
133 */
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. */
137 char buf[128];
138 int len, r;
139 va_list tmp_args;
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.
144 */
145 len = vsnprintf(buf, sizeof(buf), fmt, tmp_args);
146 va_end(tmp_args);
147 buf[sizeof(buf) - 1] = '\0';
148 if (len < 0) {
149 *strp = NULL;
150 return -1;
151 }
152 if (len < (int)sizeof(buf)) {
153 *strp = tor_strdup(buf);
154 return len;
155 }
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);
159 if (r != len) {
160 tor_free(strp_tmp);
161 *strp = NULL;
162 return -1;
163 }
164 *strp = strp_tmp;
165 return len;
166#endif /* defined(HAVE_VASPRINTF) || ... */
167}
Headers for util_malloc.c.
#define tor_free(p)
Definition: malloc.h:56
int tor_vsnprintf(char *str, size_t size, const char *format, va_list args)
Definition: printf.c:41
int tor_vasprintf(char **strp, const char *fmt, va_list args)
Definition: printf.c:96
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
int tor_snprintf(char *str, size_t size, const char *format,...)
Definition: printf.c:27
Header for printf.c.
Headers for torerr.c.
Integer definitions used throughout Tor.
#define SIZE_T_CEILING
Definition: torint.h:126