2014-11-16 10 views
7

This blog post sostiene che il superamento di un va_list a un'altra funzione, come nel codice seguente è a rischio, e che la va_list deve prima essere copiati usando va_copy:È sicuro passare una va_list a un'altra funzione senza usare va_copy?

void 
foo_ap(const char *fmt, va_list ap) 
{ 
    char buf[128]; 

    vsnprintf(buf, sizeof(buf), fmt, ap); 

    // now, do something with buf ... 
} 

Come uno dei commenti al post del blog cita, posso vediamo come questo non sarebbe sicuro, come afferma la specifica C99 (7.15):

L'oggetto ap può essere passato come argomento ad un'altra funzione; se tale funzione richiama la macro va_arg con il parametro ap, il valore di ap nella funzione di chiamata è indeterminato e deve essere passato alla macro va_end prima di qualsiasi ulteriore riferimento a ap.

(Finché foo_ap non fa riferimento ap dopo aver passato su, la seconda parte della frase non sembra applicarsi in ogni caso.) L'autore del post dice in un altro commento che potrebbe essere sbagliato, ma forse qualcuno può aggiungere qualche chiarimento. Devo davvero usare va_copy per essere al sicuro? O ci sono piattaforme che non sono conformi alle specifiche e richiedono l'uso di va_copy?

+3

Il post del blog sembra contraddire direttamente la clausola citata dallo standard C99. L'autore del blog dice "Molto tempo fa" all'inizio, quindi la mia ipotesi è che avesse a che fare con un vecchio sistema non conforme agli standard. –

+4

È necessario solo 'va_copy' se si prevede di utilizzare' ap' dopo il ritorno di 'vsnprintf'. Ad esempio, potresti voler chiamare 'vsnprintf' due volte - una volta per determinare la dimensione del buffer richiesta, e di nuovo per formattare per reale. Se non hai più bisogno di usare 'ap' di nuovo eccetto per il suo passaggio a' va_end', non devi necessariamente 'va_copy' it. –

+0

@IgorTandetnik Se si rende il commento una risposta, lo accetterò. – nwellnhof

risposta

6

È necessario solo va_copy se si prevede di utilizzare ancora ap dopo i ritorni vsnprintf. Ad esempio, è possibile chiamare lo vsnprintf due volte, una volta per determinare la dimensione del buffer richiesta e nuovamente per la formattazione reale. Se non è necessario utilizzare nuovamente ap (eccetto forse per passarlo a va_end, se lo si stava creando con va_start), non è necessario farlo va_copy.

+0

Ho osservato implementazioni in cui un va_list si comporta come se fosse passato per valore [così gli argomenti consumati da una funzione che lo riceve tornano in esistenza quando quella funzione ritorna], e altri dove si comporta come se fosse passato per riferimento [gli argomenti rimangono consumati ]. I problemi con l'uso di una va_list dopo aver chiamato un metodo che lo usa anche non sono quindi semplicemente "teorici". – supercat

Problemi correlati