LCOV - code coverage report
Current view: top level - lib/string - printf.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 29 29 100.0 %
Date: 2021-11-24 03:28:48 Functions: 4 4 100.0 %

          Line data    Source code
       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      161650 : tor_snprintf(char *str, size_t size, const char *format, ...)
      28             : {
      29      161650 :   va_list ap;
      30      161650 :   int r;
      31      161650 :   va_start(ap,format);
      32      161650 :   r = tor_vsnprintf(str,size,format,ap);
      33      161650 :   va_end(ap);
      34      161650 :   return r;
      35             : }
      36             : 
      37             : /** Replacement for vsnprintf; behavior differs as tor_snprintf differs from
      38             :  * snprintf.
      39             :  */
      40             : int
      41      172563 : tor_vsnprintf(char *str, size_t size, const char *format, va_list args)
      42             : {
      43      172563 :   int r;
      44      172563 :   if (size == 0)
      45             :     return -1; /* no place for the NUL */
      46      172562 :   if (size > SIZE_T_CEILING)
      47             :     return -1;
      48             : #ifdef _WIN32
      49             :   r = _vsnprintf(str, size, format, args);
      50             : #else
      51      172562 :   r = vsnprintf(str, size, format, args);
      52             : #endif
      53      172562 :   str[size-1] = '\0';
      54      172562 :   if (r < 0 || r >= (ssize_t)size)
      55          22 :     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      198274 : tor_asprintf(char **strp, const char *fmt, ...)
      76             : {
      77      198274 :   int r;
      78      198274 :   va_list args;
      79      198274 :   va_start(args, fmt);
      80      198274 :   r = tor_vasprintf(strp, fmt, args);
      81      198274 :   va_end(args);
      82      198274 :   if (!*strp || r < 0) {
      83             :     /* LCOV_EXCL_START */
      84             :     raw_assert_unreached_msg("Internal error in asprintf");
      85             :     /* LCOV_EXCL_STOP */
      86             :   }
      87      198274 :   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      230469 : tor_vasprintf(char **strp, const char *fmt, va_list args)
      97             : {
      98             :   /* use a temporary variable in case *strp is in args. */
      99      230469 :   char *strp_tmp=NULL;
     100             : #ifdef HAVE_VASPRINTF
     101             :   /* If the platform gives us one, use it. */
     102      230469 :   int r = vasprintf(&strp_tmp, fmt, args);
     103      230469 :   if (r < 0)
     104             :     *strp = NULL; // LCOV_EXCL_LINE -- no cross-platform way to force this
     105             :   else
     106      230469 :     *strp = strp_tmp;
     107      230469 :   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             : }

Generated by: LCOV version 1.14