0

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
c10
  • 13
  • 4

1 Answers1

2

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 and va_copy macros shall be matched by a corresponding invocation of the va_end macro in the same function.

Consequently, print_mydb() exhibits undefined behaviour because it doesn't call va_end() on vobj before it returns.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1. Thanks for pointing out the many bugs. 2. You mean to say va_list operates on current function context only? 3. I'd planned to use this concept (if it worked) to implement deferred work handling using pthreads and queue of work-contexts with variable arguments depending on work. Any pointers to help the cause? – c10 Mar 01 '18 at 09:15
  • 1. YW. 2. Yes. 3. You are going to have to devise a different mechanism. Maybe an array of a 'universal type' (a discriminated union containing all the relevant types). You can use variadic code to parse the arguments and copy them into a (dynamically allocated) array, which is then put in the work queue for threads to collect. Fiddly — but not impossible. – Jonathan Leffler Mar 01 '18 at 09:18
  • Thanks again. I'll try as suggested. – c10 Mar 01 '18 at 09:27