question about change in inet_ntoa.c
Bruce Evans
brde at optusnet.com.au
Tue Feb 26 18:46:27 UTC 2008
On Tue, 26 Feb 2008, ithilgore wrote:
> Giorgos Keramidas wrote:
>> On 2008-02-23 02:37, ithilgore <ithilgore.fbsd at gmail.com> wrote:
>>
>>> ithilgore wrote:
>>>
>>>> I was looking at the differences between some old FreeBSD code
>>>> and the one of 7.0-RC1 and was wondering about a change
>>>> in inet_ntoa.c
>>>>
>>>> /***** 7.0-RC1 **************/
>>>>
>>>> sprintf(buf, "%d.%d.%d.%d",
>>>> ucp[0] & 0xff,
>>>> ucp[1] & 0xff,
>>>> ucp[2] & 0xff,
>>>> ucp[3] & 0xff);
This version in libkern is best (except `buf' is static, so it is not
reentrant and thus quite broken). ucp[N] is unsigned char, but masking
with 0xff is needed to support the (unsupported) machines with more
than 8 bits in their chars. On normal machines with 8-bit chars, the
compiler will optimize away the masks so their only cost is increased
portability of the source code. POSIX now requires 8-bit chars, but
didn't when the above was written. %d is good enough after masking,
since the result is nonnegative and <= INT_MAX. %u would be a style
bug except on exotic machines with sizeof(char) == sizeof(int), since
the default promotions normally turn all the numeric printf args into
ints (not u_ints) thanks to C90's broken "value-preserving" promotion
rules.
>>>> /****** 4.11-RELEASE ***********/
>>>>
>>>>
>>>> static const char fmt[] = "%u.%u.%u%u";
>>>> if ((size_t)snprintf(dst, size, fmt, src[0], src[1], src[2], src[3])
>>>> >= size) {
This is actually in somewhere/inet_ntop.c:inet_ntop4().
Bugs in this version include:
- benign type mismatch between %u and the promoted args except on exotic
machines
- broken on exotic machines. UCHAR_MAX can be arbitarily large. Then
large values will e put in the string. sprintf() could then overrun
the buffer, but using snprintf() avoids that.
- bogus cast of snprintf's return value.
-current has a different version in libc, without the bogus cast. Many
files in libc/net including inet_ntop.c moved to libc/inet, and some
nearby FreeBSD cleanups were lost (ISC cleaned things up differently
and not so well in one case that I looked at).
>>>> ....
>>>> ....
>>>>
>>>> Was there a specific purpose of changing the more easy and simple way
>>>> of %u instead of the combination of %d and and-ing with 0xff ??
>>>> It essentially gives the same result but increases overhead (i think) in
>>>> the more
>>>> recent version.
I think the libkern version was written later, and it is better because
its author knows what is portable. It's also much simpler. After and-ing
with 0xff, we know the range of the values and don't have to understand
UCHAR_MAX to know that our code is only broken on unsupported/exotic
machines.
> On the other hand, in version 4.11 RELEASE in
> /usr/src/lib/libc/net/inet_ntoa.c &
> inet_ntop.c (actually it is inet_ntop.c code but with the same functionality)
But hard to find if you are looking for inet_ntoa.c.
There is also libstand/inet_ntoa.c. It has different bugs and style bugs.
At least in old versions, it combines the worst features of libkern and
libc (static buffer; uses sprintf() and thus can overrun on exotic machines;
otherwise mainly style bugs like libc).
> which is
> called by inet_ntoa there is :
>
> static const char *
> inet_ntop4(src, dst, size)
> const u_char *src;
> char *dst;
> size_t size;
> {
> static const char fmt[] = "%u.%u.%u.%u";
>
> if ((size_t)snprintf(dst, size, fmt, src[0], src[1], src[2], src[3])
> >= size) {
Another dubious cleanup in the -current version is to first snprintf() to a
static buffer of length 16 and copy to the caller's buffer from there.
snprintf() makes that unnecessary unless the API requires not touching the
caller's buffer on error.
> errno = ENOSPC;
> return (NULL);
> }
> return (dst);
> }
Bruce
More information about the freebsd-net
mailing list