A função gets, da biblioteca padrão do C (stdio) pode gerar um grande problema para o programador que a usa: como essa função não limita o número de caracteres a serem lidos da entrada padrão (stdin), pode haver vazamento de memória, ou até pior, injeção de código malicioso no progreama.
A solução é usar fgets, que limita o buffer de leitura.
Como a própria manpage da função gets informa, é preferível o uso de fgets. Leia o trecho presente na manpage de gets:
BUGS Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.
Vejamos um simples exemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <stdio.h> #define STRSIZE 10 int main() { char str[ STRSIZE ]; gets( str ); printf( "%s\n", str ); return 0; } |
A própria compilação com o GCC já alerta sobre o problema de gets:
$ gcc teste.c /tmp/ccCUw08x.o: In function `main': teste.c:(.text+0x1f): warning: the `gets' function is dangerous and should not be used.
Dependendo da posição da memória em que o programa for executado, pode ocorrer o seguinte problema durante sua execução:
$ ./a.out oi eu sou o beraldo oi eu sou o beraldo *** stack smashing detected ***: ./a.out terminated ======= Backtrace: ========= /lib/libc.so.6(__fortify_fail+0x37)[0x7f8b96f57537] /lib/libc.so.6(__fortify_fail+0x0)[0x7f8b96f57500] ./a.out[0x4005fc] /lib/libc.so.6(__libc_start_main+0xfe)[0x7f8b96e76d8e] ./a.out[0x4004f9] ======= Memory map: ======== 00400000-00401000 r-xp 00000000 08:03 403972 /tmp/a.out 00600000-00601000 r--p 00000000 08:03 403972 /tmp/a.out 00601000-00602000 rw-p 00001000 08:03 403972 /tmp/a.out 00ca3000-00cc4000 rw-p 00000000 00:00 0 [heap] 7f8b96c42000-7f8b96c57000 r-xp 00000000 08:03 524368 /lib/libgcc_s.so.1 7f8b96c57000-7f8b96e56000 ---p 00015000 08:03 524368 /lib/libgcc_s.so.1 7f8b96e56000-7f8b96e57000 r--p 00014000 08:03 524368 /lib/libgcc_s.so.1 7f8b96e57000-7f8b96e58000 rw-p 00015000 08:03 524368 /lib/libgcc_s.so.1 7f8b96e58000-7f8b96fd2000 r-xp 00000000 08:03 546662 /lib/libc-2.12.1.so 7f8b96fd2000-7f8b971d1000 ---p 0017a000 08:03 546662 /lib/libc-2.12.1.so 7f8b971d1000-7f8b971d5000 r--p 00179000 08:03 546662 /lib/libc-2.12.1.so 7f8b971d5000-7f8b971d6000 rw-p 0017d000 08:03 546662 /lib/libc-2.12.1.so 7f8b971d6000-7f8b971db000 rw-p 00000000 00:00 0 7f8b971db000-7f8b971fb000 r-xp 00000000 08:03 526899 /lib/ld-2.12.1.so 7f8b973d4000-7f8b973d7000 rw-p 00000000 00:00 0 7f8b973f7000-7f8b973fb000 rw-p 00000000 00:00 0 7f8b973fb000-7f8b973fc000 r--p 00020000 08:03 526899 /lib/ld-2.12.1.so 7f8b973fc000-7f8b973fd000 rw-p 00021000 08:03 526899 /lib/ld-2.12.1.so 7f8b973fd000-7f8b973fe000 rw-p 00000000 00:00 0 7fff0445e000-7fff0447f000 rw-p 00000000 00:00 0 [stack] 7fff0454c000-7fff0454d000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Aborted
Isso nem sempre ocorre. Depende dos limites de memória alocados para a execução do programa.
Teoricamente, na string só deveria conter “oi eu sou “, que são os dez primeiros caracteres da string lida. Assim, os demais caracteres ficam além dessa última posição de memória, que pode estar em uso por outra aplicação, gerando o erro. Pior que isso, se for injetado um código malicioso, a outra aplicação poderá executá-lo. Essa é uma forma de “vírus”.
A solução é usar fgets, lendo de stdin, que é o arquivo que representa a entrada padrão:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <stdio.h> #define STRSIZE 10 int main() { char str[ STRSIZE ]; fgets( str, STRSIZE, stdin ); printf( "%s\n", str ); return 0; } |
Compilação e execução:
$ gcc teste.c $ ./a.out oi eu sou o beraldo oi eu sou
O resultado foi o esperado.
Portanto, excluam gets de suas vidas. =)
Dicas de Livros
- C – a Linguagem de Programacao Padrao Ansi – Kernighan, Brian / Ritchie, Dennis M, o livro escrito pelos criadores da linguagem C
- C – Completo e Total – Schildt, Herbert
- C Como Programar 6 Edicao – Paul; Deitel Harvey Deitel
- Linguagem C – Luís Damas
Roberto Beraldo
Latest posts by Roberto Beraldo (see all)
- Não Tenha Preguiça de Ler! - 25/04/2016
- Como Atualizar Scripts PHP de MySQL Para MySQLi - 29/10/2015
- Como usar PDO com banco de dados MySQL - 10/09/2015