printf.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /* Copyright (c) 2003-2004, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2018, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. /**
  6. * \file printf.c
  7. * \brief Compatibility wrappers around snprintf and its friends
  8. **/
  9. #include "lib/string/printf.h"
  10. #include "lib/err/torerr.h"
  11. #include "lib/cc/torint.h"
  12. #include "lib/malloc/malloc.h"
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. /** Replacement for snprintf. Differs from platform snprintf in two
  16. * ways: First, always NUL-terminates its output. Second, always
  17. * returns -1 if the result is truncated. (Note that this return
  18. * behavior does <i>not</i> conform to C99; it just happens to be
  19. * easier to emulate "return -1" with conformant implementations than
  20. * it is to emulate "return number that would be written" with
  21. * non-conformant implementations.) */
  22. int
  23. tor_snprintf(char *str, size_t size, const char *format, ...)
  24. {
  25. va_list ap;
  26. int r;
  27. va_start(ap,format);
  28. r = tor_vsnprintf(str,size,format,ap);
  29. va_end(ap);
  30. return r;
  31. }
  32. /** Replacement for vsnprintf; behavior differs as tor_snprintf differs from
  33. * snprintf.
  34. */
  35. int
  36. tor_vsnprintf(char *str, size_t size, const char *format, va_list args)
  37. {
  38. int r;
  39. if (size == 0)
  40. return -1; /* no place for the NUL */
  41. if (size > SIZE_T_CEILING)
  42. return -1;
  43. #ifdef _WIN32
  44. r = _vsnprintf(str, size, format, args);
  45. #else
  46. r = vsnprintf(str, size, format, args);
  47. #endif
  48. str[size-1] = '\0';
  49. if (r < 0 || r >= (ssize_t)size)
  50. return -1;
  51. return r;
  52. }
  53. /**
  54. * Portable asprintf implementation. Does a printf() into a newly malloc'd
  55. * string. Sets *<b>strp</b> to this string, and returns its length (not
  56. * including the terminating NUL character).
  57. *
  58. * You can treat this function as if its implementation were something like
  59. <pre>
  60. char buf[_INFINITY_];
  61. tor_snprintf(buf, sizeof(buf), fmt, args);
  62. *strp = tor_strdup(buf);
  63. return strlen(*strp):
  64. </pre>
  65. * Where _INFINITY_ is an imaginary constant so big that any string can fit
  66. * into it.
  67. */
  68. int
  69. tor_asprintf(char **strp, const char *fmt, ...)
  70. {
  71. int r;
  72. va_list args;
  73. va_start(args, fmt);
  74. r = tor_vasprintf(strp, fmt, args);
  75. va_end(args);
  76. if (!*strp || r < 0) {
  77. /* LCOV_EXCL_START */
  78. raw_assert_unreached_msg("Internal error in asprintf");
  79. /* LCOV_EXCL_STOP */
  80. }
  81. return r;
  82. }
  83. /**
  84. * Portable vasprintf implementation. Does a printf() into a newly malloc'd
  85. * string. Differs from regular vasprintf in the same ways that
  86. * tor_asprintf() differs from regular asprintf.
  87. */
  88. int
  89. tor_vasprintf(char **strp, const char *fmt, va_list args)
  90. {
  91. /* use a temporary variable in case *strp is in args. */
  92. char *strp_tmp=NULL;
  93. #ifdef HAVE_VASPRINTF
  94. /* If the platform gives us one, use it. */
  95. int r = vasprintf(&strp_tmp, fmt, args);
  96. if (r < 0)
  97. *strp = NULL; // LCOV_EXCL_LINE -- no cross-platform way to force this
  98. else
  99. *strp = strp_tmp;
  100. return r;
  101. #elif defined(HAVE__VSCPRINTF)
  102. /* On Windows, _vsnprintf won't tell us the length of the string if it
  103. * overflows, so we need to use _vcsprintf to tell how much to allocate */
  104. int len, r;
  105. va_list tmp_args;
  106. va_copy(tmp_args, args);
  107. len = _vscprintf(fmt, tmp_args);
  108. va_end(tmp_args);
  109. if (len < 0) {
  110. *strp = NULL;
  111. return -1;
  112. }
  113. strp_tmp = tor_malloc(len + 1);
  114. r = _vsnprintf(strp_tmp, len+1, fmt, args);
  115. if (r != len) {
  116. tor_free(strp_tmp);
  117. *strp = NULL;
  118. return -1;
  119. }
  120. *strp = strp_tmp;
  121. return len;
  122. #else
  123. /* Everywhere else, we have a decent vsnprintf that tells us how many
  124. * characters we need. We give it a try on a short buffer first, since
  125. * it might be nice to avoid the second vsnprintf call.
  126. */
  127. char buf[128];
  128. int len, r;
  129. va_list tmp_args;
  130. va_copy(tmp_args, args);
  131. /* vsnprintf() was properly checked but tor_vsnprintf() available so
  132. * why not use it? */
  133. len = tor_vsnprintf(buf, sizeof(buf), fmt, tmp_args);
  134. va_end(tmp_args);
  135. if (len < (int)sizeof(buf)) {
  136. *strp = tor_strdup(buf);
  137. return len;
  138. }
  139. strp_tmp = tor_malloc(len+1);
  140. /* use of tor_vsnprintf() will ensure string is null terminated */
  141. r = tor_vsnprintf(strp_tmp, len+1, fmt, args);
  142. if (r != len) {
  143. tor_free(strp_tmp);
  144. *strp = NULL;
  145. return -1;
  146. }
  147. *strp = strp_tmp;
  148. return len;
  149. #endif /* defined(HAVE_VASPRINTF) || ... */
  150. }