PDA

View Full Version : [C] Funzioni da evitare


maxithron
07-06-2004, 11:30
Salve ragazzi, allora, posto quello che mi è venuto dopo aver spesso riflettuto su quanta informazione sia didattica che professionale è a disposizione di tutti i programmatori, di qualsiasi livello:

Capita di rado che si parli di funzioni da evitare per eliminare fastidiosi problemi come buffer overflow etc..

Proporrei quindi, se siete d'accordo, di farne un elenco che ritengo possa essere utile sia a chi comincia con la programmazione, in modo da adeguarsi subito ad un buon modo di pensare, sia per i + esperti come.....'ripasso'

Poi, magari, volendo ampliare il discorso, si potrebbe fare che al posto della funzione da evitare si posti la 'buona' che la sostituisce.

Saluti.

ilsensine
07-06-2004, 11:40
La "classica" gets; da sostituire con fgets o simili.

Cmq i buffer overflow più spesso dipendono da inaccurata programmazione, più che da funzioni di libreria pericolose.

cionci
07-06-2004, 12:03
Anche la sprintf può essere pericola se il programma è fatto male (ad esempio dimensionando male la stringa)...

VegetaSSJ5
07-06-2004, 12:11
per favore potere spiegare anche perchè la funzione è da evitare e scrivere anche i parametri delle funzioni "buone e cattive"? tutti coloro che sono niubbi come me ve ne saranno molto grati... :ave:

cionci
07-06-2004, 12:19
Per la gets è semplicissimo:

char *gets( char *buffer );

Se buffer è stato allocato di dimensione più piccola di quella immessa allora c'è un buffer overflow (e non evitabile in alcun modo)...

Lo stesso problema c'è con la (*)scanf leggendo una stringa...
scanf("%s", buffer);

Per evitare bisogna leggere le stringhe da file o dallo stdin tramite:

char *fgets( char *string, int n, FILE *stream );

VegetaSSJ5
07-06-2004, 12:45
Originariamente inviato da cionci
Per la gets è semplicissimo:

char *gets( char *buffer );

Se buffer è stato allocato di dimensione più piccola di quella immessa allora c'è un buffer overflow (e non evitabile in alcun modo)...

Lo stesso problema c'è con la (*)scanf leggendo una stringa...
scanf("%s", buffer);

Per evitare bisogna leggere le stringhe da file o dallo stdin tramite:

char *fgets( char *string, int n, FILE *stream );
ecco adesso sì!;) potresti spiegarmi cos'è l'int n della fgets? è il numero massimo di caratteri che si possono leggere giusto? per leggere da stdin dobbiamo specificare stdin nel campo FILE *stream giusto?

Ziosilvio
07-06-2004, 12:55
Originariamente inviato da VegetaSSJ5
potresti spiegarmi cos'è l'int n della fgets? è il numero massimo di caratteri che si possono leggere giusto?
No, e' il massimo spazio che fgets deve considerare gia' allocato.
Quindi, il numero massimo di caratteri che si possono leggere e' n-1, perche' nel totale va messo il carattere nullo di fine stringa.
per leggere da stdin dobbiamo specificare stdin nel campo FILE *stream giusto?
Giusto.

Gogeta ss4
07-06-2004, 12:57
per la gets basta mettere una fflush(stdin) prima di usarla, anzi è molto comoda da usare,io la uso sempre:)

ilsensine
07-06-2004, 13:20
Originariamente inviato da cionci
Lo stesso problema c'è con la (*)scanf leggendo una stringa...
scanf("%s", buffer);

char s[16];
scanf("%15s", s);

Ziosilvio
07-06-2004, 14:24
Originariamente inviato da Gogeta ss4
per la gets basta mettere una fflush(stdin) prima di usarla
Funziona con molti compilatori, ma non e' standard.
(Lo standard C89, per default, non definisce il comportamento di fflush su uno stream di input.)
Io, di solito, quando devo assicurarmi la lettura di una riga "nuova", leggo un carattere per volta dallo stream di input (e lo scarto) finche' non trovo un EOF o un newline; ma mi sembra di ricordare che neanche questo metodo e' universale...
E poi non mi e' chiaro (ma potrei aver capito male io) perche' questo dovrebbe risolvere il problema di buffer overflow con gets.

fpucci
07-06-2004, 14:45
Programmo in C da 15 anni ed ormai ritengo che non esiston funzioni pericolose.
Il pericolo viene determinato, secondo me, da chi le usa, ossia il programmatore che "non sa quello che fa".

Per cvi capita il buffer overflow, la colpa non è della funzione in sé ma di chi ha sottodimensionato il buffer oppure ha non saputo gestire il particolare evento.

E' chiaro che nel momento in cui utilizzo una primitiva devo fare attenzione a tutti le implicazioni...

cionci
07-06-2004, 15:03
Originariamente inviato da Gogeta ss4
per la gets basta mettere una fflush(stdin) prima di usarla, anzi è molto comoda da usare,io la uso sempre:)
Non mi sembra che, standard o non standard, risolva il problema...

cionci
07-06-2004, 15:14
Originariamente inviato da ilsensine
char s[16];
scanf("%15s", s);
Certo questo risolve per scanf...ma in quanti la usano così ;)

Comunque fra le fuinzioni di input sicuramente quella più insicura è la gets...ma bisogna stare attenti su qualsiasi funzioen di input che non permette di specificare il numero di byte o strutture da leggere...

fpucci
07-06-2004, 15:38
Originariamente inviato da cionci
[...]ma bisogna stare attenti su qualsiasi funzioen di input che non permette di specificare il numero di byte o strutture da leggere...

Per l'appunto!
In generale, come già detto prima, meglio privilegiare quelle funzioni che consentano di specificare a priori la dimensione dei buffer

ilsensine
07-06-2004, 15:39
Originariamente inviato da cionci
Certo questo risolve per scanf...ma in quanti la usano così ;)

IO! IO!

...e c'è chi fa MOLTO peggio :D
http://marc.theaimsgroup.com/?l=linux-kernel&m=108529071114282&w=2

VegetaSSJ5
07-06-2004, 15:43
Originariamente inviato da ilsensine
IO! IO!

...e c'è chi fa MOLTO peggio :D
http://marc.theaimsgroup.com/?l=linux-kernel&m=108529071114282&w=2
questo merita di essere inserito:fscanf(in, "%*[^\n]\n%*[^\n]"); /* skip two lines */
while (fscanf(in, " %16[^:]:%*[^\n]", name) == 1):eekk:

maxithron
07-06-2004, 23:32
Originariamente inviato da fpucci
Programmo in C da 15 anni ed ormai ritengo che non esiston funzioni pericolose.
Il pericolo viene determinato, secondo me, da chi le usa, ossia il programmatore che "non sa quello che fa".

Per cvi capita il buffer overflow, la colpa non è della funzione in sé ma di chi ha sottodimensionato il buffer oppure ha non saputo gestire il particolare evento.

E' chiaro che nel momento in cui utilizzo una primitiva devo fare attenzione a tutti le implicazioni...

In effetti, è più a questo modo di pensare che ho aperto il 3d che non alla mera 'liquidazione' delle primitive. :) Mi rendo conto di averla espressa male.

Ciò comunque vale perchè come già evidenziato dalla maggior parte di voi, è un utilizzo 'inconsapevole' della funzione a provocare problemi che non la funzione stessa.

fpucci
08-06-2004, 10:13
Originariamente inviato da maxithron
[...] è un utilizzo 'inconsapevole' della funzione a provocare problemi che non la funzione stessa.

Infatti.
Però mi sono accorto di una cosa.
Che il programmatore smaliziato (o esperto, fate voi), capisce al volo quali potrebbero essere i possibili problemi, mentre il neofita rischia di cadere nella trappola.

A volte il "man" (sotto unix/linux) o l'help sotto windows o comunque una buona guida sul C, dovrebbero porre in evidenza questi problemi.

Nel caso tanto discusso della gets(), ad esempio, il man() del compilatore C per Unix-Solaris mette in guardia l'utente proprio su questo aspetto, e cioè che un utilizzo improprio del buffer potrebbe portare a risultati impredicibili... e pertanto consigliano l'uso della fgets() ;)

Poi sta al buon uso di chi programma scegliere quella che fa al caso suo...

maxithron
08-06-2004, 11:10
Inoltre, se già compili con gcc anche senza l'opzione -Wall ed hai una gets, ti esce lo stesso il warning che indica la possibile problematica.