Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > variadic function

Reply
Thread Tools

variadic function

 
 
Quentin Pope
Guest
Posts: n/a
 
      11-05-2011
Consider the variadic function with the following prototype:
int foo(int num,...);
Here 'num' specifies the number of arguments, and assume that all the
arguments that should be passed to this function are of type int.
(My question has nothing to do with the definition of the function
foo, so don't bother about it.)

If I call the function as:
foo(2,3,4,5,6,7,;/*More arguments than expected*/

Here I call foo with too many arguments than expected by its
definition.

Assuming that the prototype is visible in the scope of the function
call and the definition of function foo itself does NOT produce any
UB, please tell me if this function call produces UB or not.

I am not able to find any explicit clause from C99 which deals with
this behavior.

Though I find that:

7.19.6.1 The fprintf function
The fprintf function writes output to the stream pointed to by stream,
under control of the string pointed to by format that specifies how
subsequent arguments are converted for output. If there are
insufficient arguments for the format, the behavior is undefined. If
the format is exhausted while arguments remain, the excess arguments
are evaluated (as always) but are otherwise ignored.

This is highly specific to fprintf. I wonder if it applies to all
variadic functions.

Can I assume that the behavior of this function call is UB by
ommission?
Or am I missing something, here?

QP


***

This email and any file attachments(s) are confidential, may be legally
privileged, and are intended solely for use by the identified recipient
(s). If you received the email in error, please notify the sender and
delete the message and any copies completely from your computer.
Dissemination, distribution, or copying of this communication, in whole
or in part, by any unintended or unauthorized recipient is prohibited and
may subject you to liability under 18 U.S.C. sec. 2511. Jameston
Solutions, Inc. assumes no liability and makes no warranties or
representations that the email or any file attachments are totally secure
and/or virus free. The recipient is advised to check for viruses prior to
opening any file attached to the email. Statements contained in the email
or any file attachment may not be authorized or endorsed by Jameston
Solutions, Inc. Jameston Solutions, Inc. accepts no liability, whether in
contract, tort, or equity, for any unauthorized statement or offer of
contract communicated in the email or any file attached by the sender. No
employee or agent is authorized to conclude any binding agreement on
behalf of Jameston Solutions, Inc with another party by email without
express written confirmation

WARNING: Computer viruses can be transmitted via email. The recipient
should check this email and any attachments for the presence of viruses.
The company accepts no liability for any damage caused by any virus
transmitted by this email. E-mail transmission cannot be guaranteed to be
secure or error-free as information could be intercepted, corrupted,
lost, destroyed, arrive late or incomplete, or contain viruses. The
sender therefore does not accept liability for any errors or omissions in
the contents of this message, which arise as a result of e-mail
transmission.

Warning: Although the company has taken reasonable precautions to ensure
no viruses are present in this email, the company cannot accept
responsibility for any loss or damage arising from the use of this email
or attachments.
 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      11-05-2011
Quentin Pope <(E-Mail Removed)> writes:
> Consider the variadic function with the following prototype:
> int foo(int num,...);
> Here 'num' specifies the number of arguments, and assume that all the
> arguments that should be passed to this function are of type int.
> (My question has nothing to do with the definition of the function
> foo, so don't bother about it.)
>
> If I call the function as:
> foo(2,3,4,5,6,7,;/*More arguments than expected*/
>
> Here I call foo with too many arguments than expected by its
> definition.
>
> Assuming that the prototype is visible in the scope of the function
> call and the definition of function foo itself does NOT produce any
> UB, please tell me if this function call produces UB or not.
>
> I am not able to find any explicit clause from C99 which deals with
> this behavior.
>
> Though I find that:
>
> 7.19.6.1 The fprintf function
> The fprintf function writes output to the stream pointed to by stream,
> under control of the string pointed to by format that specifies how
> subsequent arguments are converted for output. If there are
> insufficient arguments for the format, the behavior is undefined. If
> the format is exhausted while arguments remain, the excess arguments
> are evaluated (as always) but are otherwise ignored.
>
> This is highly specific to fprintf. I wonder if it applies to all
> variadic functions.


I believe the behavior is well defined.

The call itself cannot reasonably have undefined behavior, since foo()
itself *could* have called va_arg enough times to consume all the
arguments.

Inside foo, the only potentially problematic think you're doing is
invoking va_end() before consuming all the arguments. Invoking va_arg()
when there are no more arguments is UB (C99 7.15.11.1p), but that
doesn't apply here.

There's nothing in the description of va_end() that suggests that its
behavior depends on whether previous calls to va_arg() have consumed all
the arguments.

(The behavior of fprintf() is described explicitly because there's no
requirement for fprintf() to use the <stdarg.h> mechanism; legacy
implementations would have used something else, perhaps <varargs.h>,
and fprintf() could be implemented in non-portable C or in a language
other than C.)

[...]
>
> This email and any file attachments(s) are confidential, may be legally
> privileged, and are intended solely for use by the identified recipient

[29 lines deleted]
> responsibility for any loss or damage arising from the use of this email
> or attachments.


If you can find a way to post without including this nonsense, I'm sure
we'd all appreciated it.

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
 
 
 
James Kuyper
Guest
Posts: n/a
 
      11-05-2011
On 11/05/2011 06:32 PM, Quentin Pope wrote:
> Consider the variadic function with the following prototype:
> int foo(int num,...);
> Here 'num' specifies the number of arguments, and assume that all the
> arguments that should be passed to this function are of type int.
> (My question has nothing to do with the definition of the function
> foo, so don't bother about it.)
>
> If I call the function as:
> foo(2,3,4,5,6,7,;/*More arguments than expected*/
>
> Here I call foo with too many arguments than expected by its
> definition.
>
> Assuming that the prototype is visible in the scope of the function
> call and the definition of function foo itself does NOT produce any
> UB, please tell me if this function call produces UB or not.
>
> I am not able to find any explicit clause from C99 which deals with
> this behavior.
>
> Though I find that:
>
> 7.19.6.1 The fprintf function
> The fprintf function writes output to the stream pointed to by stream,
> under control of the string pointed to by format that specifies how
> subsequent arguments are converted for output. If there are
> insufficient arguments for the format, the behavior is undefined. If
> the format is exhausted while arguments remain, the excess arguments
> are evaluated (as always) but are otherwise ignored.
>
> This is highly specific to fprintf. I wonder if it applies to all
> variadic functions.


Each variadic function must have some mechanism for determining how many
arguments it's received; there's a wide variety to choose from. However,
once that mechanism has been used, the same principles apply: if the
actual number of arguments is larger than the function expects, it won't
know that they're accessible, and so it shouldn't try to access them.
Nothing will go bad for any reason other than the direct and indirect
consequences of the fact that it didn't try to access them.

> Can I assume that the behavior of this function call is UB by
> ommission?
> Or am I missing something, here?


There is no problem here at the language level. The fact that 'num' is
supposed to be the count of the number of arguments is known only by the
implementor of foo(), and those who read the documentation for foo(). In
particular, the compiler doesn't know anything about how many arguments
foo() is expecting, and as a result must pass all 6 variable arguments
in such a way that they could be accessed using the features of
<stdarg.h>, if foo() decided to try to. It is no error for foo() to fail
to look at all the arguments that were passed to it.

The other way around is more problematic: a call to foo(8, 7, 6, 5, 4,
3, 2) informs foo(), incorrectly, that it has 8 arguments, when in fact
it only has one fixed argument and 6 variable arguments. If the body of
foo() makes an attempt to access the argument that should have come
after 2, then the behavior would be undefined (7.15.1.3p2).
--
James Kuyper
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      11-05-2011
James Kuyper <(E-Mail Removed)> writes:
> On 11/05/2011 06:32 PM, Quentin Pope wrote:
>> Consider the variadic function with the following prototype:
>> int foo(int num,...);
>> Here 'num' specifies the number of arguments, and assume that all the
>> arguments that should be passed to this function are of type int.
>> (My question has nothing to do with the definition of the function
>> foo, so don't bother about it.)
>>
>> If I call the function as:
>> foo(2,3,4,5,6,7,;/*More arguments than expected*/
>>
>> Here I call foo with too many arguments than expected by its
>> definition.
>>
>> Assuming that the prototype is visible in the scope of the function
>> call and the definition of function foo itself does NOT produce any
>> UB, please tell me if this function call produces UB or not.
>>
>> I am not able to find any explicit clause from C99 which deals with
>> this behavior.
>>
>> Though I find that:
>>
>> 7.19.6.1 The fprintf function
>> The fprintf function writes output to the stream pointed to by stream,
>> under control of the string pointed to by format that specifies how
>> subsequent arguments are converted for output. If there are
>> insufficient arguments for the format, the behavior is undefined. If
>> the format is exhausted while arguments remain, the excess arguments
>> are evaluated (as always) but are otherwise ignored.
>>
>> This is highly specific to fprintf. I wonder if it applies to all
>> variadic functions.

>
> Each variadic function must have some mechanism for determining how many
> arguments it's received; there's a wide variety to choose from. However,
> once that mechanism has been used, the same principles apply: if the
> actual number of arguments is larger than the function expects, it won't
> know that they're accessible, and so it shouldn't try to access them.
> Nothing will go bad for any reason other than the direct and indirect
> consequences of the fact that it didn't try to access them.


Note that the standard *could* have stated that the behavior of
invoking va_end() before consuming all the actual arguments with
va_arg() is undefined. There's even an argument to be made that
since it doesn't explicitly define the behavior, the behavior
is therefore undefined. But since it does define the behavior of
va_end(), and that definition makes no reference to whether va_arg()
has been used or not, I'd say that the behavior is well defined.

[...]

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Kaz Kylheku
Guest
Posts: n/a
 
      11-06-2011
On 2011-11-05, Quentin Pope <(E-Mail Removed)> wrote:
> Consider the variadic function with the following prototype:
> int foo(int num,...);
> Here 'num' specifies the number of arguments, and assume that all the
> arguments that should be passed to this function are of type int.
> (My question has nothing to do with the definition of the function
> foo, so don't bother about it.)
>
> If I call the function as:
> foo(2,3,4,5,6,7,;/*More arguments than expected*/
>
> Here I call foo with too many arguments than expected by its
> definition.


There is no way that a definition can express that, though. A variadic
function does not expect any particular number of parameters (just at least the
required ones).

A variadic funtion can fail to extract all the parameters by calling the va_arg
macro fewer times than there are parameters.

> insufficient arguments for the format, the behavior is undefined. If
> the format is exhausted while arguments remain, the excess arguments
> are evaluated (as always) but are otherwise ignored.


Exactly.

> This is highly specific to fprintf. I wonder if it applies to all
> variadic functions.


Nothing is written that all arguments must be consumed.

> Can I assume that the behavior of this function call is UB by
> ommission?


No, because there is no omission. Every step can be verified to have
a defined behavior.

"UB by omission" occurs in cases when you actually cannot infer
what the behavior should be.

The concern about what happens to arguments that are not pulled out
is a concern about some steps that the program /did not/ execute.

Look at the steps that the program /did/ execute, and are those defined?

Sometimes a program can invoke UB by neglecting to take some required steps
that a situation calls for. That kind of situation has to be spelled out.

For instance, if an input operation is done on an update stream after an output
operation, without an intervening fflush, the behavior is undefined. If this
was not spelled out, the behavior would have to be considered defined (since an
update stream is one on which you can do a mixture of reads and writes, and if
no combination is documented as broken, then you can assume it's not broken.)

> This email and any file attachments(s) are confidential, may be legally
> privileged, and are intended solely for use by the identified recipient


The above footer is egregiously excessive and netiquette-violating. I
understand it's not your fault. If you give me the e-mail address of whoever is
responsible I will share with them an outsider's perspective. You should not
have your posting stigmatized by reams of legalese garbage.
 
Reply With Quote
 
Kaz Kylheku
Guest
Posts: n/a
 
      11-06-2011
On 2011-11-05, Quentin Pope <(E-Mail Removed)> wrote:
> Consider the variadic function with the following prototype:
> int foo(int num,...);
> Here 'num' specifies the number of arguments, and assume that all the
> arguments that should be passed to this function are of type int.
> (My question has nothing to do with the definition of the function
> foo, so don't bother about it.)
>
> If I call the function as:
> foo(2,3,4,5,6,7,;/*More arguments than expected*/
>
> Here I call foo with too many arguments than expected by its
> definition.


There is no way that a definition can express that, though. A variadic
function does not expect any particular number of parameters (just at least the
required ones).

A variadic funtion can fail to extract all the parameters by calling the va_arg
macro fewer times than there are parameters.

> insufficient arguments for the format, the behavior is undefined. If
> the format is exhausted while arguments remain, the excess arguments
> are evaluated (as always) but are otherwise ignored.


Exactly.

> This is highly specific to fprintf. I wonder if it applies to all
> variadic functions.


Nothing is written that all arguments must be consumed.

> Can I assume that the behavior of this function call is UB by
> ommission?


No, because there is no omission. Every step can be verified to have
a defined behavior.

"UB by omission" occurs in cases when you actually cannot infer
what the behavior should be.

The concern about what happens to arguments that are not pulled out
is a concern about some steps that the program /did not/ execute.

Look at the steps that the program /did/ execute, and are those defined?

Sometimes a program can invoke UB by neglecting to take some required steps
that a situation calls for. That kind of situation has to be spelled out.

For instance, if an input operation is done on an update stream after an output
operation, without an intervening fflush, the behavior is undefined. If this
was not spelled out, the behavior would have to be considered defined (since an
update stream is one on which you can do a mixture of reads and writes, and if
no combination is documented as broken, then you can assume it's not broken.)

> This email and any file attachments(s) are confidential, may be legally
> privileged, and are intended solely for use by the identified recipient


The above footer is egregiously excessive and netiquette-violating. I
understand it's not your fault. If you give me the e-mail address of whoever is
responsible I will share with them an outsider's perspective. You should not
have your posting stigmatized by reams of legalese garbage.
 
Reply With Quote
 
Kaz Kylheku
Guest
Posts: n/a
 
      11-06-2011
On 2011-11-05, Keith Thompson <(E-Mail Removed)> wrote:
> Note that the standard *could* have stated that the behavior of
> invoking va_end() before consuming all the actual arguments with
> va_arg() is undefined. There's even an argument to be made that
> since it doesn't explicitly define the behavior, the behavior
> is therefore undefined.


That's essentially the same argument as saying that since the standard omits to
say that you must write the line "foo" at the end of every text stream, it is
UB by omission if a program fails to do that.

Whenever something that the program /does not do/ causes its behavior
to be undefined, that must be spelled out.
 
Reply With Quote
 
Barry Schwarz
Guest
Posts: n/a
 
      11-06-2011
On Sat, 5 Nov 2011 22:32:21 +0000 (UTC), Quentin Pope
<(E-Mail Removed)> wrote:

>Consider the variadic function with the following prototype:
>int foo(int num,...);
>Here 'num' specifies the number of arguments, and assume that all the
>arguments that should be passed to this function are of type int.
>(My question has nothing to do with the definition of the function
>foo, so don't bother about it.)
>
>If I call the function as:
>foo(2,3,4,5,6,7,;/*More arguments than expected*/
>
>Here I call foo with too many arguments than expected by its
>definition.


Not by its definition which specifies only that the function call must
have at least one argument. So your concern is actually about foo's
execution.

For sake of discussion, I will assume you meant that num contains the
number of variable arguments, not the total number of arguments.
Consider the similar situation where argument 1 is actually 6.
Everything "matches". But during execution, after processing argument
3, foo decides there is some condition which warrants terminating its
execution and returning to the caller. (Like free() determining that
the input argument is NULL so there is no reason to do any more work.)
However, foo is designed with sound programming practices in mind and
as part of exiting cleans up after itself, including calling va_end
(as required by 7.15.1.3-2). Since this situation occurs in lots of
functions, C's utility as a programming language would be pretty
limited if this by itself led to undefined behavior (and you would
also see a requirement in the standard of the form "Do not call va_end
after va_start unless va_arg has been called to process every argument
in the calling sequence"). From the implementation's point of view
(compiler, linker, run-time library, etc), this situation is the same
as the one you described. The function will ignore some arguments. No
one cares if it is because the value of num "hid" some of them or
because the function decided they weren't needed. The result must be
the same for C to be a practical language.

--
Remove del for email
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      11-06-2011
Barry Schwarz <(E-Mail Removed)> writes:
> On Sat, 5 Nov 2011 22:32:21 +0000 (UTC), Quentin Pope
> <(E-Mail Removed)> wrote:
>
>>Consider the variadic function with the following prototype:
>>int foo(int num,...);
>>Here 'num' specifies the number of arguments, and assume that all the
>>arguments that should be passed to this function are of type int.
>>(My question has nothing to do with the definition of the function
>>foo, so don't bother about it.)
>>
>>If I call the function as:
>>foo(2,3,4,5,6,7,;/*More arguments than expected*/
>>
>>Here I call foo with too many arguments than expected by its
>>definition.

>
> Not by its definition which specifies only that the function call must
> have at least one argument. So your concern is actually about foo's
> execution.
>
> For sake of discussion, I will assume you meant that num contains the
> number of variable arguments, not the total number of arguments.
> Consider the similar situation where argument 1 is actually 6.
> Everything "matches". But during execution, after processing argument
> 3, foo decides there is some condition which warrants terminating its
> execution and returning to the caller. (Like free() determining that
> the input argument is NULL so there is no reason to do any more work.)
> However, foo is designed with sound programming practices in mind and
> as part of exiting cleans up after itself, including calling va_end
> (as required by 7.15.1.3-2). Since this situation occurs in lots of
> functions, C's utility as a programming language would be pretty
> limited if this by itself led to undefined behavior (and you would
> also see a requirement in the standard of the form "Do not call va_end
> after va_start unless va_arg has been called to process every argument
> in the calling sequence"). From the implementation's point of view
> (compiler, linker, run-time library, etc), this situation is the same
> as the one you described. The function will ignore some arguments. No
> one cares if it is because the value of num "hid" some of them or
> because the function decided they weren't needed. The result must be
> the same for C to be a practical language.


I don't quite follow this.

To be clear, I think we've established that there's no problem
with a variadic function processing only some of its arguments
(i.e., invoking va_end() without having used va_arg() to process
all the arguments).

But if the language were defined differently, I don't see that
it would be much of a problem. I can't think of many realistic
scenarios where it would even make sense to pass more arguments
to a variadic function than it's going to process. For example,
"foo(2,3,4,5,6,7,;", though its behavior is well defined, is
probably a programming error.

The variadic functions I've seen either use a format string to
specify the number and types of the following arguments, or use
a special value, typically a null pointer, as an end marker.
In both cases, a correct call will result in all the arguments
being processed.

If the standard did have the requirement you mention: "Do not call
va_end after va_start unless va_arg has been called to process
every argument in the calling sequence", what great inconvenience
would it cause?

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Quentin Pope
Guest
Posts: n/a
 
      11-07-2011
On Sat, 05 Nov 2011 15:50:59 -0700, Keith Thompson wrote:

> Quentin Pope <(E-Mail Removed)> writes:
>> Consider the variadic function with the following prototype: int
>> foo(int num,...);
>> Here 'num' specifies the number of arguments, and assume that all the
>> arguments that should be passed to this function are of type int. (My
>> question has nothing to do with the definition of the function foo, so
>> don't bother about it.)
>>
>> If I call the function as:
>> foo(2,3,4,5,6,7,;/*More arguments than expected*/
>>
>> Here I call foo with too many arguments than expected by its
>> definition.
>>
>> Assuming that the prototype is visible in the scope of the function
>> call and the definition of function foo itself does NOT produce any UB,
>> please tell me if this function call produces UB or not.
>>
>> I am not able to find any explicit clause from C99 which deals with
>> this behavior.
>>
>> Though I find that:
>>
>> 7.19.6.1 The fprintf function
>> The fprintf function writes output to the stream pointed to by stream,
>> under control of the string pointed to by format that specifies how
>> subsequent arguments are converted for output. If there are
>> insufficient arguments for the format, the behavior is undefined. If
>> the format is exhausted while arguments remain, the excess arguments
>> are evaluated (as always) but are otherwise ignored.
>>
>> This is highly specific to fprintf. I wonder if it applies to all
>> variadic functions.

>
> I believe the behavior is well defined.
>
> The call itself cannot reasonably have undefined behavior, since foo()
> itself *could* have called va_arg enough times to consume all the
> arguments.
>
> Inside foo, the only potentially problematic think you're doing is
> invoking va_end() before consuming all the arguments. Invoking va_arg()
> when there are no more arguments is UB (C99 7.15.11.1p), but that
> doesn't apply here.
>
> There's nothing in the description of va_end() that suggests that its
> behavior depends on whether previous calls to va_arg() have consumed all
> the arguments.
>
> (The behavior of fprintf() is described explicitly because there's no
> requirement for fprintf() to use the <stdarg.h> mechanism; legacy
> implementations would have used something else, perhaps <varargs.h>, and
> fprintf() could be implemented in non-portable C or in a language other
> than C.)
>
> [...]
>>
>> This email and any file attachments(s) are confidential, may be legally
>> privileged, and are intended solely for use by the identified recipient

> [29 lines deleted]
>> responsibility for any loss or damage arising from the use of this
>> email or attachments.

>
> If you can find a way to post without including this nonsense, I'm sure
> we'd all appreciated it.


Thanks for the helpful answers. Sorry about the legalese - I accidentally
used the wrong sig block, which I have to include on work emails to avoid
certain kinds of legal liability.

// QP
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Call again a variadic function (... variable number of arguments)with same arguments that its variadic wrapper moreau.steve@gmail.com C Programming 3 12-31-2008 07:13 AM
variadic function calling variadic function goldfita@signalsguru.net C Programming 5 05-03-2006 05:23 PM
Using variadic functions within variadic functions pinkfloydhomer@gmail.com C Programming 2 02-27-2006 05:47 AM
Variadic functions calling variadic functions with the argument list, HLL bit shifts on LE processors Ross A. Finlayson C Programming 19 03-10-2005 03:57 AM
is casting a variadic function to a non-variadic one legal? Colin Walters C Programming 2 02-13-2004 10:55 PM



Advertisments