lib/slprintf.c tiny bug on FreeBSD (may be other systems)

Michail Vidiassov master at iaas.msu.ru
Fri Feb 23 14:55:52 GMT 2001


Dear BUGbusters,

 It seems there is a bug in the slprintf function.

What is slprintf: As far as I understand it is used work around
 snprintf   implementations that do not zero terminate
 the string  in case of overflow (are there any?) and
 to return -1 in case of overflow (is the return value of
 slprintf tested for in samba? or just +'ed?).

The Bug : It seems that in FreeBSD case we lose the last byte in the buffer,
 since snprintf does put the trailing 0 in case of overflow, and so does
 slprintf => we have two zeroes instead of one.

Test output (test program, derived from slprintf.c, is attached):

 buffer size: 11
slprintf(buf,sizeof(buf)-1,"%s",str)
str:1234567890 buf:123456789
 sizeof:11 strlen:9 return code:10
str:12345678901 buf:123456789
 sizeof:11 strlen:9 return code:-1
snprintf(buf,sizeof(buf),"%s",str)
str:1234567890 buf:1234567890
 sizeof:11 strlen:10 return code:10
str:12345678901 buf:1234567890
 sizeof:11 strlen:10 return code:11

More detail:

 The return value of snprintf is dealt with in a strange way:
 snprintf man sayes:
RedHat 4.2:
                                  It is  similar  to  sprintf(3),
       except  that  n specifies the maximum number of characters
       to  produce.   The  trailing  null  character  is  counted
       towards  this  limit,  so  you  should allocate at least n
       characters for the string str.

        The  return  value is the number of characters stored, not
        including the terminating null.  If this value  equals  n,
        then there was not enough space in str for all the output.
        You should try again with a bigger output string.

FreeBSD 3.4:
     Snprintf() and vsnprintf() will write at most size-1 of the characters
     printed into the output string (the size'th character then gets the ter-
     minating `\0'); if the return value is greater than or equal to the size
     argument, the string was too short and some of the printed characters
     were discarded.

 But in vslprintf:
        int ret = vsnprintf(str, n, format, ap);
        if (ret > n || ret < 0) {
                str[n] = 0;
                return -1;
        }

 i.e in FreeBSD (and may be other cases) ret=n is an overflow condition
 that is not detected.
 In FreeBSD case ith fix is simple:
        int ret = vsnprintf(str, n+1, format, ap);
        if (ret > n || ret < 0) {
                str[n] = 0;
                return -1;
        }


                   Sincerely, Michail





More information about the samba-technical mailing list