Re-using a 'va_list'

J

Joerg Schoen

Hi folks!

I have a function that gets a 'va_list'. I am passing the
'va_list' two times to a function like 'vprintf' to print
it out.

I thought that this was portable until I came across a
platform (AS/400) where it fails: The 'va_list' is actually
defined as some some kind of an array, so passing it happens
by *reference*: The first user will destroy it and the second
time it does not work.

My question is: Does the standard allow this and AS/400 is
broken or am I invoking undefined behaviour?

Below is a test program

---------------- snip --------------------------
/*
* Test if a va_list argument can be used to traverse the
* variable arguments more than once.
*/
#include <stdio.h>
#include <stdarg.h>

static void scanargs(int dest[2],va_list ap)
{
dest[0] = va_arg(ap,int);
dest[1] = va_arg(ap,int);
}

static void teststdarg(int dest[4], ...)
{
va_list ap;

va_start(ap,dest);

scanargs(dest,ap);
scanargs(dest + 2,ap);

va_end(ap);
}

int main(int argc,char *argv[])
{
int a[4];

teststdarg(a,1,2,3,4);

if((a[0] == 1 && a[1] == 2) &&
(a[2] == 1 && a[3] == 2) || (a[2] == 3 && a[3] == 4)) {
if(a[2] == 1)
printf("We can use a 'va_list' at least twice.\n");
else
printf("WARNING: Reusing 'va_list' gives different results!\n");
} else {
fprintf(stderr,"ERROR: Something is very bad here!\n");
exit(20);
}

return 0;
}
---------------- snap --------------------------
 
J

Jeremy Yallop

Joerg said:
I have a function that gets a 'va_list'. I am passing the
'va_list' two times to a function like 'vprintf' to print
it out.

I thought that this was portable until I came across a
platform (AS/400) where it fails: The 'va_list' is actually
defined as some some kind of an array, so passing it happens
by *reference*: The first user will destroy it and the second
time it does not work.

That's permissible behaviour. You should re-initialize the list
with va_start before attempting to use it again.
static void teststdarg(int dest[4], ...)
{
va_list ap;

va_start(ap,dest);

scanargs(dest,ap);
scanargs(dest + 2,ap);

va_end(ap);
}

This should be written as

static void teststdarg(int dest[4], ...)
{
va_list ap;

va_start(ap,dest);
scanargs(dest,ap);
va_end(ap);

va_start(ap, dest);
scanargs(dest + 2,ap);
va_end(ap);
}

Jeremy.
 
L

lawrence.jones

Jeremy Yallop said:
That's permissible behaviour. You should re-initialize the list
with va_start before attempting to use it again.

Which is fine if you're creating the va_arg in the first place, but is a
bit difficult if it's comming from somewhere else (e.g., being passed to
you as a parameter). That's why C99 has va_copy().

-Larry Jones

Talk about someone easy to exploit! -- Calvin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top