As in this example, if I call tsub directly from main, output is as expected. If pthread mode is enabled for tsub, this doesn't give expected output.
va_list vobj;
void *tsub (void *arg)
{
printf ("vobj: %d, %f\n", va_arg (vobj, int), va_arg (vobj, double));
return NULL;
}
void print_mydb (char *name, ...)
{
va_list ap;
va_start (ap, name);
va_copy (vobj, ap);
va_end (ap);
}
int main (void)
{
pthread_t tid;
print_mydb ("b10", 6, 5.23);
#if 1
printf ("THREADY!!!!!\n");
pthread_create (&tid, NULL, tsub, (void *)vobj);
pthread_join (tid, NULL);
#else
tsub (NULL);
#endif
return 0;
}
Output for direct tsub call:
vobj: 6, 5.230000
Output for pthread invocation for tsub:
THREADY!!!!!
vobj: 0, 0.000000
AFAICS, you're invoking undefined behaviour both times; it just sometimes works (seems to work in this context) and sometimes doesn't. When print_mydb()
returns, the copied vobj
is pointing at invalid data — the function call that provided the data (argument list) it points at has returned, so the content of vobj
is now meaningless. It doesn't matter whether you call tsub()
directly or via pthread_create()
, you're abusing memory once passed to print_mydb()
. It breaks worse when pthread_create()
tramples on the memory as it is called.
Further, the function that calls va_copy()
must call va_end()
on the copied list before it returns. C11 §7.16.1 Variable argument list access macros ¶1
Each invocation of the
va_start
andva_copy
macros shall be matched by a corresponding invocation of theva_end
macro in the same function.
Consequently, print_mydb()
exhibits undefined behaviour because it doesn't call va_end()
on vobj
before it returns.