come aiutare il programmatore di scrittura chiamate printf sicuri e corretti in C?

StackOverflow https://stackoverflow.com/questions/1969832

  •  21-09-2019
  •  | 
  •  

Domanda

[Aggiornamento organizzazione e il contenuto per chiarezza]

La vera domanda

Quale sarebbe un buon modo, per la C, per aiutare un programmatore, mentre s / he sta digitando, scrivere le chiamate sicure e corrette per proiettare-specifica funzioni di debug printf-come?

macro C? funzioni wrapper C? Code Editor macro o modelli? Altro?

Fondo Domande e risposte

Molto software utilizza printf o funzioni printf-like per il debug, sia ad-hoc quando c'è un problema, o per i registri di debug. Eppure è soggetto a errori.

Q1:? Come facciamo a sapere
A1: Gli analizzatori statici hanno le categorie per gli errori printf-disadattamento - si tratta di una classe comune di errori - e spesso di vedere questi strumenti chiamano tali avvertenze sul codice C

.

Q2:? Quali sono le sottoclassi di questo errore
A2: identificatore di formato Principalmente, sbagliato, e il numero sbagliato di identificatori di formato. Spesso il vero errore è il contrario:. Tipo di variabile sbagliato, o numero errato di variabili per la stampa-out

Q3:? Perché ci preoccupiamo
A3: Nella migliore delle ipotesi, fa sì che le informazioni di registrazione sbagliato e impedisce il debug. Nel peggiore dei casi, si blocca il software.

Q4:? Qualcuno ha provato a fare qualcosa su questo problema
A4: Certo, anche se non ho visto alcuna per C (al contrario di C ++ o altro), per esempio:

http://www.ddj.com/cpp/184401999?pgno=1 http://mi.eng.cam.ac .uk / ~ er258 / CVD / tag / html / group__printf.html

Ciò che manca per me in queste offerte e gli altri, oltre al fatto che in questo momento sto guardando un prodotto scritto in C e la necessità di risolvere il problema per C, è che si tratta di soluzioni dopo-il-fatto. Essi possono evitare le collisioni, e in grado di fornire spiegazioni premonitori di cosa è andato storto, e che qualcosa è andato storto, ma certamente non può indovinare che cosa l'intenzione del programmatore era (vedi spec. Q & sopra A # 2).

Q5:? Perché utilizzando printf quindi soggetto a errori
A5:. Perché scrivere una chiamata printf richiede al programmatore di mescolare i tipi ei numeri di variabili, identificatori di formato, liberi costanti stringa di testo, e la punteggiatura - tutti che appaiono molto simili gli uni agli altri - su una riga insieme

È stato utile?

Soluzione

Utilizzare un compilatore in grado di controllare i tipi e formato di un printf(). La maggior parte dei compilatori moderni dovrebbero essere in grado di farlo. Per GCC, -Wall è tuo amico (o -Wformat se si desidera solo i controlli del formato). Vedere la opzioni di avviso per i dettagli.

Oltre a questo, l'unica opzione è quella di aggiungere un #define printf ILLEGAL_DO_NOT_USE a un file di intestazione comune dei vostri progetti e fornire una funzione diversa che fa lo stesso lavoro in modo sicuro. Buona fortuna con questo approccio;)

[EDIT] Il tuo problema è che il C non è possibile allegare informazioni sul tipo di qualcosa di passato come parametro di per sé. Allora, cosa si potrebbe fare è qualcosa in queste righe:

safe_printf_like_function("%d %s %c\n", INT_TYPE(value), STRING_TYPE(s), CHAR_TYPE(c));

Le macro devono contenere calchi al tipo (in modo che il compilatore può notare che il tipo è sbagliato, come si passa in) più esso deve espandersi a qualcosa che trasporta le informazioni sul tipo.

Svantaggio: ogni programmatore C sta per urlare nell'angoscia se si presenta loro una tale API. C non è solo significa per essere in questo modo. C è a rischio. Periodo. E 'destinata ad essere pericoloso. In base alla progettazione, l'abitudine e tradizione. Se si vuole una rete di sicurezza, C non è per voi.

Detto questo, si può raggiungere un certo livello di sicurezza in C ma ad un costo: È necessario vietare l'uso di varargs in qualsiasi parte del codice. Puntatori e array devono essere avvolti in codice che controlla le dimensioni, ecc Quindi sì, è possibile, ma non è più C.

la faccia esso, C è del 1972. E 'antica e si vede. Per quasi 35 anni, nessuno è riuscito a trovare un modo intelligente per rendere sicura C (vedi C ++ per un tentativo e la quantità di successo si può aspettare).

Altri suggerimenti

gcc fornisce -Wformat a mettere in guardia circa printf / scanf / strftime / strfmon errori di formato.

$ gcc -Wformat -c -o test.o test.c
test.c: In function ‘main’:
test.c:5: warning: format ‘%s’ expects type ‘char *’,
          but argument 2 has type ‘int’
$ cat test.c
#include <stdio.h>

int main(int argc, const char *argv[])
{
     printf("%s\n", 0);
     return 0;
}

In GCC, c'è un costruito in modo per impedire l'uso di funzioni:

#pragma GCC poison printf

E 'meglio di "-Wall" perché è un errore, non un avvertimento. Non ho idea di come printf sarebbe stato sostituito -. Forse da un sacco di funzioni specializzate

GCC pragma

La fortuna migliore che ho avuto è stato quello di utilizzare strumenti come lint o splint e lanciare un attacco assoluto quando roba non passava al 100%. In combinazione con una sorta di ispezione del codice (per gestire i casi in cui gli avvertimenti vengono giustamente soppressi), questo è stato sufficiente per ottenere il lavoro fatto, anche se non era sicuramente una soluzione ideale.

Non è un problema facile da risolvere. Se avete intenzione di scrivere modelli specifici (come, ad esempio, "%s: %d", è possibile utilizzare una (preferibilmente) una funzione wrapper macro o. Non sarà possibile duplicare la funzionalità di printf() senza duplicare la complessità.

editor di codice sarà difficile per verificare, dal momento che la determinazione tipi di valore (che è necessario per evitare disallineamenti) richiede l'analisi del programma di C. E 'possibile che il compilatore C stesso per mettere in guardia, ma non molti lo fanno (mi piacerebbe che se lo facessero).

C ++ evita il problema con iostreams, che sfruttano l'overloading degli operatori, ma che non è un'opzione in C.

Una regola che posso dare è di non stampare una variabile stringa come printf(string);. Usare sempre printf(%s, string); invece, dal momento che evita difficili da trovare bug se c'è un segno di percentuale nella stringa.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top