svn commit: r188098 - head/lib/libc/string

Bruce Evans brde at optusnet.com.au
Wed Feb 4 03:28:04 PST 2009


On Tue, 3 Feb 2009, Christoph Mallon wrote:

> Warner Losh schrieb:
>> Modified: head/lib/libc/string/strmode.c
>> ==============================================================================
>> --- head/lib/libc/string/strmode.c	Tue Feb  3 20:01:51 2009 
>> (r188097)
>> +++ head/lib/libc/string/strmode.c	Tue Feb  3 20:25:36 2009 
>> (r188098)
>> @@ -38,7 +38,7 @@ __FBSDID("$FreeBSD$");
>>  #include <string.h>
>>   void
>> -strmode(mode_t mode, char *p)
>> +strmode(/* mode_t */ int mode, char *p)
>>  {
>>  	 /* print type */
>>  	switch (mode & S_IFMT) {
>
> The manpage states that the first parameter of strmode() is a mode_t. What's 
> wrong - the implementation (both in header and definition) or the 
> documentation?

The man page is wrong.  strtomode() should take an int arg (actually
the default (unary) promotion of a mode_t) for the the same reasons
that memchr() does -- because these interfaces should be usable by K&R
compilers and/or by standard C compilers without a protoype in scope.
Even if this is no longer required, binary compatibily requires the
interfaces to be the same as the ones that used to be required.  The
requirement for binary compatibility also prevents "fixing" interfaces
to be "ANSI" in headers (if you "fix" prototypes there then you will
get obscure runtime errors instead of tinderbox errors).

mode_t causes even more problems on systems with 16-bit ints since its
default promotion is unsigned int.  Thus the correct declaration of
strmode() is machine-dependent.  Similarly for memchr() on systems
with sizeof(char) == sizeof(int).  Standard C doesn't support variant
interfaces so memchr() cannot work quite right on such systems.

This problem used to be much larger for POSIX.  POSIX.1-1988 didn't
require prototypes, but it required use of mode_t and lots of other
probably-sub-integer typedefed types too much in its interfaces (unlike
standard C which uses ints and longs too much), and it declares all
its interfaces using prototypes so the ones that involve sub-integer
types cannot be implemented by either K&R compilers or Standard C
compilers (for K&R, sub-integer types are not supported, and for
Standard C the literal prototypes don't match the default promotions).

Now, POSIX requires prototypes (to be supported by the compiler), and,
like standard C, it requires a prototype to be in scope if the type
of any function parameter is incompatible with its default promotion,
so the problems are limited mainly to loss of bits on exotic machines
in the forced conversions between signed and unsigned values.  Since
the prototypes aren't variant, sometimes there are forced conversions
that mess up the values even if the initial and final types are the
same.

I probably missed fixing strmode.3 because of the gcc bug that you pointed
out -- the prototype is incompatible with the declaration in strmode.3, so
the behaviour is undefined, but gcc's implementation of the undefined
behaviour is to do the right thing if a prototype is in scope and to do
the wrong thing if a prototype is not in scope.  Since my man page checker
puts the wrong prototype in scope but doesn't put the correct prototype
from string.h in scope, the error goes undetected.

Bruce


More information about the svn-src-head mailing list