¿Por qué la función gets es tan peligrosa que no debería usarse?

8 minutos de lectura

avatar de usuario
Vinit Dhatrak

Cuando trato de compilar código C que usa el gets() función con GCC, recibo esta advertencia:

(.text+0x34): advertencia: la función `gets’ es peligrosa y no debe usarse.

Recuerdo que esto tiene algo que ver con la protección y la seguridad de la pila, pero no estoy seguro exactamente por qué.

¿Cómo puedo eliminar esta advertencia y por qué existe tal advertencia sobre el uso gets()?

Si gets() es tan peligroso entonces ¿por qué no podemos eliminarlo?

avatar de usuario
Tomas Owens

Para usar gets con seguridad, debe saber exactamente cuántos caracteres leerá, de modo que pueda hacer que su búfer sea lo suficientemente grande. Solo lo sabrá si sabe exactamente qué datos leerá.

En lugar de usar getsquieres usar fgetsque tiene la firma

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

(fgetssi lee una línea completa, dejará el '\n' en la cadena; tendrás que lidiar con eso).

gets siguió siendo una parte oficial del idioma hasta el estándar ISO C de 1999, pero se eliminó oficialmente en el 2011 estándar. La mayoría de las implementaciones de C aún lo admiten, pero al menos gcc emite una advertencia para cualquier código que lo use.

  • En realidad no es gcc la que advierte, es la glibc la que contiene un pragma o atributo en gets() eso hace que el compilador emita una advertencia cuando se usa.

    – fuz

    5 de enero de 2015 a las 11:47

  • @fuz en realidad, ni siquiera es solo el compilador el que advierte: ¡el enlazador imprimió la advertencia citada en el OP!

    – Ruslán

    21 de abril de 2020 a las 14:53

Porque gets no realiza ningún tipo de comprobación al obtener bytes de Entrada estándar y ponerlos en algún lugar. Un ejemplo sencillo:

char array1[] = "12345";
char array2[] = "67890";

gets(array1);

Ahora, antes que nada, puede ingresar cuántos caracteres desea, gets no le importará. En segundo lugar, los bytes sobre el tamaño de la matriz en la que los coloca (en este caso array1) sobrescribirá todo lo que encuentre en la memoria porque gets los escribirá. En el ejemplo anterior, esto significa que si ingresa "abcdefghijklmnopqrts" tal vez, impredeciblemente, también se sobrescribirá array2 o lo que sea.

La función no es segura porque asume una entrada consistente. ¡NUNCA LO USE!

  • que hace gets totalmente inutilizable es que no tiene un parámetro de longitud/recuento de matriz que toma; si hubiera estado allí, sería simplemente otra función estándar ordinaria de C.

    – leyendas2k

    30 de septiembre de 2013 a las 3:59


  • @legends2k: tengo curiosidad por saber cuál es el uso previsto gets fue, y ¿por qué no se hizo una variante fgets estándar tan conveniente para los casos de uso donde la nueva línea no se desea como parte de la entrada?

    – Super gato

    28 de marzo de 2015 a las 18:04

  • @Super gato gets fue, como sugiere el nombre, diseñado para obtener una cadena de stdinsin embargo, la justificación para no tener un Talla el parámetro puede haber sido de el espiritu de c: Confía en el programador. Esta función fue eliminada en C11 y el reemplazo dado gets_s toma el tamaño del búfer de entrada. no tengo ni idea de la fgets parte sin embargo.

    – leyendas2k

    29 de marzo de 2015 a las 1:29


  • @legends2k: El único contexto que puedo ver en el que gets podría ser excusable sería si uno estuviera usando un sistema de E/S con búfer de línea de hardware que fuera físicamente incapaz de enviar una línea de cierta longitud, y la vida útil prevista del programa fuera más corta que la vida útil del hardware. En ese caso, si el hardware es incapaz de enviar líneas de más de 127 bytes, podría justificarse gets en un búfer de 128 bytes, aunque creo que las ventajas de poder especificar un búfer más corto cuando se espera una entrada más pequeña justificarían con creces el costo.

    – Super gato

    29 de marzo de 2015 a las 16:57

  • @legends2k: en realidad, lo que podría haber sido ideal habría sido tener un “puntero de cadena” que identificara un byte que seleccionaría entre algunos formatos diferentes de cadena/búfer/búfer-info, con un valor de byte de prefijo que indica una estructura que contenía el byte de prefijo [plus padding], además del tamaño del búfer, el tamaño utilizado y la dirección del texto real. Tal patrón haría posible que el código pase una subcadena arbitraria (no solo la cola) de otra cadena sin tener que copiar nada, y permitiría métodos como gets y strcat para aceptar con seguridad todo lo que quepa.

    – Super gato

    29 de marzo de 2015 a las 17:02


avatar de usuario
pmg

Leí recientemente, en un Publicación de USENET en comp.lang.cese gets() se está eliminando del Estándar. WOOHOO

Te alegrará saber que el comité acaba de votar (por unanimidad, según parece) para eliminar gets() del borrador también.

  • que hace gets totalmente inutilizable es que no tiene un parámetro de longitud/recuento de matriz que toma; si hubiera estado allí, sería simplemente otra función estándar ordinaria de C.

    – leyendas2k

    30 de septiembre de 2013 a las 3:59


  • @legends2k: tengo curiosidad por saber cuál es el uso previsto gets fue, y ¿por qué no se hizo una variante fgets estándar tan conveniente para los casos de uso donde la nueva línea no se desea como parte de la entrada?

    – Super gato

    28 de marzo de 2015 a las 18:04

  • @Super gato gets fue, como sugiere el nombre, diseñado para obtener una cadena de stdinsin embargo, la justificación para no tener un Talla el parámetro puede haber sido de el espiritu de c: Confía en el programador. Esta función fue eliminada en C11 y el reemplazo dado gets_s toma el tamaño del búfer de entrada. no tengo ni idea de la fgets parte sin embargo.

    – leyendas2k

    29 de marzo de 2015 a las 1:29


  • @legends2k: El único contexto que puedo ver en el que gets podría ser excusable sería si uno estuviera usando un sistema de E/S con búfer de línea de hardware que fuera físicamente incapaz de enviar una línea de cierta longitud, y la vida útil prevista del programa fuera más corta que la vida útil del hardware. En ese caso, si el hardware es incapaz de enviar líneas de más de 127 bytes, podría justificarse gets en un búfer de 128 bytes, aunque creo que las ventajas de poder especificar un búfer más corto cuando se espera una entrada más pequeña justificarían con creces el costo.

    – Super gato

    29 de marzo de 2015 a las 16:57

  • @legends2k: en realidad, lo que podría haber sido ideal habría sido tener un “puntero de cadena” que identificara un byte que seleccionaría entre algunos formatos diferentes de cadena/búfer/búfer-info, con un valor de byte de prefijo que indica una estructura que contenía el byte de prefijo [plus padding], además del tamaño del búfer, el tamaño utilizado y la dirección del texto real. Tal patrón haría posible que el código pase una subcadena arbitraria (no solo la cola) de otra cadena sin tener que copiar nada, y permitiría métodos como gets y strcat para aceptar con seguridad todo lo que quepa.

    – Super gato

    29 de marzo de 2015 a las 17:02


avatar de usuario
yuhao

En C11 (ISO/CEI 9899:201x), gets() ha sido removido. (Está en desuso en ISO/IEC 9899:1999/Cor.3:2007(E))

Además de fgets()C11 presenta una nueva alternativa segura gets_s():

C11 K.3.5.4.1 El gets_s función

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
char *gets_s(char *s, rsize_t n);

Sin embargo, en el Práctica recomendada sección, fgets() todavía se prefiere.

Él fgets La función permite que los programas escritos correctamente procesen de forma segura las líneas de entrada demasiado largas para almacenarlas en la matriz de resultados. En general, esto requiere que los llamantes de fgets preste atención a la presencia o ausencia de un carácter de nueva línea en la matriz de resultados. Considere usar fgets (junto con cualquier procesamiento necesario basado en caracteres de nueva línea) en lugar de
gets_s.

  • Si eliminan fgets(), siempre hay opciones como scanf(“%s”, arr) o getline(&arr, 100500, stdin). Esto es una molestia, por supuesto, porque cuando quieres escribir un código de mierda, generalmente también quieres hacerlo lo más rápido posible y con un uso mínimo de la capacidad intelectual. Espero que las implementaciones se detengan solo en las advertencias.

    – Sr. Kirushko

    13 mayo 2021 a las 18:12


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad