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