[comp.lang.c] Parameter mismatch legality question

tim@proton.amd.com (Tim Olson) (11/16/90)

Here is an interesting question that came up recently.  What is the
"legality" of the following ("dusty deck" K&R, not ANSI) code:
	
	foo();
	
	bar()
	{
		int a;
		.
		.
		foo(a);
		.
		.
	}
	
	foo(a, b, c, d)
	int a, b, c, d;
	{
		.
		.
	}

i.e. the call to a function passes fewer parameters than are declared
in the function declaration.

Since C's parameters are "call-by-value", they can normally be
modified or destroyed by the called function.  What if a compiler with
dataflow analysis decided that the lifetimes for the parameter "b" and
a local variable were non-overlapping, and decided to use the same
space (be it memory or a register) to hold them?  In the case above,
it could end up overwriting some local variable from procedure bar()!

So the question is, is the code:

	a) Legal in all cases (at least for K&R C)

	b) Legal if there is no explicit modification of "optional"
	   variables

	c) Illegal

	d) Other?

--
	-- Tim Olson
	Advanced Micro Devices
	(tim@amd.com)

gwyn@smoke.brl.mil (Doug Gwyn) (11/16/90)

In article <1990Nov15.224353.155@mozart.amd.com> tim@proton.amd.com (Tim Olson) writes:
>		foo(a);
>	foo(a, b, c, d)
>	c) Illegal

henry@zoo.toronto.edu (Henry Spencer) (11/17/90)

In article <1990Nov15.224353.155@mozart.amd.com> tim@proton.amd.com (Tim Olson) writes:
>	foo();

This appears to be meant as a declaration of `foo'; it is not legal as one
in ANSI C.  `int foo();' would be.

>		foo(a);
>	foo(a, b, c, d)
>i.e. the call to a function passes fewer parameters than are declared
>in the function declaration.

In the absence of prototypes, the effect is undefined (3.3.2.2), so your
compiler is entitled to generate code that calls the Soviet embassy, sends
your program, and then tips off the FBI that you are committing espionage.
Or if it's feeling nice, it might give you an error message.

In the presence of prototypes, a number-of-arguments mismatch is illegal
and must be diagnosed.

>Since C's parameters are "call-by-value", they can normally be
>modified or destroyed by the called function.  What if a compiler with
>dataflow analysis decided that the lifetimes for the parameter "b" and
>a local variable were non-overlapping, and decided to use the same
>space (be it memory or a register) to hold them?  In the case above,
>it could end up overwriting some local variable from procedure bar()!

Given the undefinedness of the situation, that is perfectly legitimate.
I would recommend fixing the code.
-- 
"I don't *want* to be normal!"         | Henry Spencer at U of Toronto Zoology
"Not to worry."                        |  henry@zoo.toronto.edu   utzoo!henry

tim@proton.amd.com (Tim Olson) (11/17/90)

In article <14486@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
| In article <1990Nov15.224353.155@mozart.amd.com> tim@proton.amd.com (Tim Olson) writes:
| >		foo(a);
| >	foo(a, b, c, d)
| >	c) Illegal

I like that answer, but what about, say the UNIX "open" library call,
which has the optional "mode" parameter used this way...


--
	-- Tim Olson
	Advanced Micro Devices
	(tim@amd.com)

henry@zoo.toronto.edu (Henry Spencer) (11/17/90)

In article <1990Nov16.212511.13166@mozart.amd.com> tim@amd.com (Tim Olson) writes:
>| >	c) Illegal
>
>I like that answer, but what about, say the UNIX "open" library call,
>which has the optional "mode" parameter used this way...

The only way to legally do System V's wretchedly stupidly botched open()
call, which gratuitously added an optional parameter rather than sensibly
providing a new function with three parameters to supplement open(), is
to make it a varargs function.  Varargs functions *must* have a prototype
in scope, and then follow somewhat different rules.
-- 
"I don't *want* to be normal!"         | Henry Spencer at U of Toronto Zoology
"Not to worry."                        |  henry@zoo.toronto.edu   utzoo!henry

gwyn@smoke.brl.mil (Doug Gwyn) (11/17/90)

In article <1990Nov16.212511.13166@mozart.amd.com> tim@amd.com (Tim Olson) writes:
>I like that answer, but what about, say the UNIX "open" library call,
>which has the optional "mode" parameter used this way...

Originally, open() has exactly two arguments of fixed types, but USG
decided to make it variadic when they added O_CREAT.  I doubt very
much that they worried at all about the non-portable aspects of such
an interface.  They're also the ones who made the USG 4.0/5.0 IPC
functions return (pointer_type)-1 instead of null pointers as failure
indicators.

IEEE 1003.1 decided that open() had to be officially variadic, i.e.
	extern int open( const char *path, int flags, ... );
Since this requires ANSI C support, you're best off if you let <fcntl.h>
declare open() for you.

friedl@mtndew.Tustin.CA.US (Stephen Friedl) (11/19/90)

In article <14502@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) writes:
> 
> IEEE 1003.1 decided that open() had to be officially variadic, i.e.
> 	extern int open( const char *path, int flags, ... );
> Since this requires ANSI C support, you're best off if you let <fcntl.h>
> declare open() for you.

Unless of course you are IBM building the RS6000, where the prototype
in <fcntl.h> omits the /const/ type qualifier on the pathname.  Mighty
nice of them not to burden us with qualifiers, eh?

     Steve :-(

-- 
Stephen J. Friedl, KA8CMY / I speak for me only / Tustin, CA / 3B2-kind-of-guy
+1 714 544 6561  / friedl@mtndew.Tustin.CA.US  / {uunet,attmail}!mtndew!friedl

"Gcc compiles an interesting language which is not ANSI C." - Henry Spencer

karl@ima.isc.com (Karl Heuer) (11/20/90)

In article <571@mtndew.Tustin.CA.US> friedl@mtndew.Tustin.CA.US (Stephen Friedl) writes:
>In article <14502@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) writes:
>>... you're best off if you let <fcntl.h> declare open() for you.
>
>Unless of course you are IBM building the RS6000, where the prototype
>in <fcntl.h> omits the /const/ type qualifier on the pathname.  Mighty
>nice of them not to burden us with qualifiers, eh?

In this case it's still true that the correct action is use <fcntl.h>
rather than declaring it yourself; but you should also reject the broken
implementation and replace it with a working one.

In the situation you describe, the simplest way to get a working
implementation is to edit the vendor's <fcntl.h> to fix the bug, or if this
isn't feasible, to maintain your own copy of the include directory.

Karl W. Z. Heuer (karl@ima.isc.com or uunet!ima!karl), The Walking Lint