Date: Sun, 27 Aug 1995 11:07:50 +1000 From: Bruce Evans <bde@zeta.org.au> To: CVS-commiters@freefall.FreeBSD.org, bde@freefall.FreeBSD.org, cvs-sys@freefall.FreeBSD.org Subject: Re: cvs commit: src/sys/vm vm_map.h vm_map.c Message-ID: <199508270107.LAA23799@godzilla.zeta.org.au>
index | next in thread | raw e-mail
>bde 95/08/26 16:18:39
> Modified: sys/vm vm_map.h vm_map.c
> Log:
> Change vm_map_print() to have the correct number and type of args for
> a ddb command.
Mach apparently used lint to get the args right for all the old ddb
commands. We used neither prototypes nor lint and got the args wrong
for almost all the recently added ddb commands. We will soon use
-Wstrict-prototypes to avoid mismatched args. This is painful to get
right for function pointers. `gcc -Wstrict-prototypes' warns about
incomplete function pointer types in structs, so we want complete
function pointer types in structs, but completing them exposed about
2000 abuses of incomplete function pointers, including many easy to
fix gratuitous ones like the above.
The abuses include the following:
1) for syscalls. The conversion from the application's args is
magic, but it would be nice to limit the type puns to one stage.
Currently, for the i386, the following occurs:
a) the app pushes the args onto the user stack.
b) the args are copied and converted from the user stack to a
local array `int args[8]'. The conversion is actually null.
It works by magic.
c) the address of the kernel copy of the args is passed to the
function that handles the syscall, e.g., open(). The address
has type `int *' and is magically converted to a `struct
foo_args *' for the function foo(). The effect of the call is
undefined because the arg types are incompatible. This is
with the function pointer type (*sy_call)() having an empty
arg list. If (*sy_call)() is declared to match the way it is
used (this is what I do now), then there are hundreds of
warnings about bogus initializations of sysent structs. If
(*sy_call)() is declared right for calling foo(), then it is
wrong for calling bar(), although it is very unlikely that
`struct foo_args *' is physicaly, incompatible with `struct
bar_args *'. Perhaps the right method is to pass a `void *'
or `int *' and convert it in each function, like you have to
do for qsort(). This would be painful because there are so
many functions.
2) for protoswitch functions. The number and type of args sometimes
depends on the protocol. This is OK if the function pointer
type is incomplete and the number and type of args in the callers
matches the number and type of args in the callees, but this can't
be checked at compile time using prototypes and more importantly,
the incomplete function pointer types cause noisy warnings when
you turn on enough type checking to check plain function calls.
Perhaps the right method is to use an arbitrary complete function
pointer type in the struct and cast it in the calls. This would
be relatively painless because there aren't many calls.
3) for vfs switch functions. The args are copied and converted
(wasting time and space) to vop_foo_args structs. I think there
is no problem at run time (the machine-generated conversion
functions in vnode_if.h correspond to the conversions that
would fix syscall functions), but if the vnode function pointer
types are made complete then gcc warns about thousands of
compile-time conversions without casts in the vfs initializers.
Adding casts would defeat type checking. Perhaps the right
method is to use an arbitrary complete function pointer type
in the struct and cast it in the conversion functions. This
would be relativly painless because the casts can be machine-
generated.
If everything passed the correct number and type of args then we
could compile the kernel with -mrtd -mregparm to save a few cycles.
-mregparm is officially supported for the i386 in gcc-2.7.0.
Bruce
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199508270107.LAA23799>
