Tor  0.4.7.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/string/printf.h"
12 #include "lib/err/torerr.h"
13 #include "lib/cc/torint.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.) */
26 int
27 tor_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  */
40 int
41 tor_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 #ifdef _WIN32
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  */
74 int
75 tor_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  */
95 int
96 tor_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:52
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