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>
next in thread | raw e-mail | index | archive | help
>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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199508270107.LAA23799>