2009-05-26 26 views
5

tengo el siguiente fragmento de código C y tienen que identificar el error y sugerir una forma de escribir que sea más segura:¿Cómo podría escribirse este fragmento C de forma más segura?

char somestring[] = "Send money!\n"; 
char *copy; 

copy = (char *) malloc(strlen(somestring)); 

strcpy(copy, somestring); 
printf(copy); 

Así que el error es que strlen ignora el arrastre '\0' de una cadena y por lo tanto no es va a asignar suficiente memoria para la copia, pero no estoy seguro de lo que están obteniendo al escribir con más seguridad?

Podría simplemente usar malloc(strlen(somestring)+1)) Supongo, pero estoy pensando que debe haber una manera mejor que eso?


EDIT: OK, he aceptado una respuesta, sospecho que no se esperaría que la solución strdup de nosotros ya que no es parte de la norma ANSI C. Parece ser una pregunta bastante subjetiva, así que No estoy seguro de si lo que he aceptado es realmente lo mejor. Gracias de todos modos por todas las respuestas.

Respuesta

4
char somestring[] = "Send money!\n"; 
char *copy; 
size_t copysize; 

copysize = strlen(somestring)+1; 
copy = (char *) malloc(copysize); 
if (copy == NULL) 
    bail("Oh noes!\n"); 

strncpy(copy, somestring, copysize); 
printf("%s", copy); 

diferencias se señaló anteriormente:

  • Resultado de malloc() se debe comprobar!
  • Calcular y tienda el tamaño de la memoria!
  • Use strncpy() porque strcpy() es malo. En este ejemplo artificial, no duele, pero no adquieras el hábito de usarlo.

EDIT:

Para aquellos que piensan que debería usar strdup() ... eso sólo funciona si se toma el punto de vista muy estrecha de la cuestión. Eso no sólo es tonto, que es con vistas a una respuesta aún mejor:

char somestring[] = "Send money!\n"; 
char *copy = somestring; 
printf(copy); 

Si vas a ser obtuso, al menos, ser bueno en eso.

+3

+1 para el uso de strncpy. Esa es la fuente de tantos agujeros de seguridad, no es gracioso. –

+8

El uso de strncpy() mal es peor que usar strcpy() mal. Si usa strncpy(), tiene * NO * garantía de salida terminada nula (este ejemplo es correcto, pero no en general). Además, si usa búferes de gran tamaño y sizeof (búfer) para el tercer parámetro de strncpy(), tiene un mini desastre de rendimiento en sus manos; strncpy() celosamente pone a cero los datos copiados a longitud completa. * SÍ * para conocer la longitud de las cadenas fuente y de destino; Si lo hace correctamente, utilizar strcpy() es seguro y más seguro que el uso ciego de strncpy(). (Si es de alguna ayuda, strncat() es mucho, mucho peor que strncpy(); ¡nunca lo use!) –

+1

Jonathan, strlcpy() es mucho más sensato. Lo uso cuando está disponible, y en algún momento traigo una versión cuando no está disponible. Lástima que Drepper sea un idiota. – dwc

6
char somestring[] = "Send money!\n"; 
char *copy = strdup(something); 

if (copy == NULL) { 
    // error 
} 

o simplemente poner esta lógica en una función separada xstrdup:

char * xstrdup(const char *src) 
{ 
    char *copy = strdup(src); 

    if (copy == NULL) { 
     abort(); 
    } 

    return copy; 
} 
+5

Cabe señalar que strdup() es no es parte de ANSI C. –

+1

debe ser: if (copy == NULL) { – hiena

+2

Si strdup() no existe para su biblioteca C, entonces debe escribirlo. Eso significa que tiene un único punto donde puede ocurrir un error en lugar de cientos. –

-2

La manera más segura sería utilizar strncpy en lugar de strcpy. Esa función toma un tercer argumento: la longitud de la cadena para copiar. Esta solución no se extiende más allá de ANSI C, por lo que funcionará en todos los entornos (mientras que otros métodos solo pueden funcionar en sistemas que cumplen con POSIX).

char somestring[] = "Send money!\n"; 
char *copy; 

copy = (char *) malloc(strlen(somestring)); 

strncpy(copy, somestring, strlen(somestring)); 
printf(copy); 
+0

+1 para strncpy; más que cualquier otra cosa, eso hace que este código sea más seguro. Al menos en el caso de falla de malloc, segfault; strcpy() permite agujeros de seguridad insanos que son DIFÍCILES de encontrar. –

+1

-1 por error único y corrupción de memoria –

+0

@McWafflestix: no, en este caso, el uso de strncpy() es incorrecto y el resultado es un desastre. Como señala Aaron Digulla, la llamada a strncpy() necesita la longitud 'strlen (somestring) +1'; tal como está escrito, se garantiza que la copia no tendrá terminación nula. El printf() es peligroso en general, utilizando una cadena aleatoria ya que el formato para printf() es malo (puts() es probablemente la opción más cercana a la sana aquí). (Imagine "Enviar 20% de dinero extra" en su lugar!) –

3
  1. strlen + 1, para el \ 0 terminador
  2. malloc puede fallar; comprobar siempre el valor de retorno de malloc
0

La mejor manera de escribirlo con más seguridad, si uno estuviera realmente interesado en tal cosa, sería escribirlo en Ada.

somestring : constant string := "Send money!"; 
declare 
    copy : constant string := somestring; 
begin 
    put_line (somestring); 
end; 

Mismo resultado, ¿cuáles son las diferencias?

  • Todo se hace en la pila (sin punteros). La desasignación es automática y segura.
  • Todo está automaticamente gama- fin de poder comprobar que no hay posibilidad de desbordamiento de memoria hazañas
  • Ambas cadenas son constantes, por lo que no hay posibilidad de cometer errores y su modificación.
  • Probablemente sea la forma más rápida que que la C, no solo por la falta de asignación dinámica, sino porque no hay ese escaneo adicional a través de la cadena requerida por strlen().

Tenga en cuenta que en Ada "cadena" no es una construcción dinámica especial. Es la matriz integrada de caracteres. Sin embargo, las matrices de Ada se pueden clasificar en la declaración por la matriz que se les asigna.

3

Ick ... use strdup() como todos los demás han dicho y escríbalo usted mismo si es necesario. Ya que tiene tiempo para pensar en esto ahora ... revise el 25 Most Dangerous Programming Errors at Mitre, luego considere por qué la frase printf(copy) debe nunca aparecen en el código. Es decir a la altura de malloc(strlen(str)) en términos de la maldad absoluta por no mencionar el dolor de cabeza de rastrear por lo que hace que una gran cantidad de dolor cuando la copia es algo así como "%s%n" ...

7

que no puedo comentar sobre las respuestas anteriores, pero además de comprobar el código de retorno y usando strncpy, nunca se debe hacer:

printf(string) 

Pero usar:

printf("%s", string); 

ref: http://en.wikipedia.org/wiki/Format_string_attack

+2

+1 por agujero de seguridad inesperado en el código más común –

1

Me gustaría comentar las soluciones anteriores, pero no tengo suficientes representantes. Usar strncpy aquí es tan incorrecto como usar strcpy (ya que no existe ningún riesgo de desbordamiento). Hay una función llamada memcpy en < string.h> y está pensada exactamente para esto. No sólo es significativamente más rápido, sino también la función correcta de usar para copiar cadenas de longitud conocida en la norma C.

De la respuesta aceptada:

char somestring[] = "Send money!\n"; 
char *copy; 
size_t copysize; 

copysize = strlen(somestring)+1; 
copy = (char *) malloc(copysize); 
if (copy == NULL) 
    bail("Oh noes!\n"); 

memcpy(copy, somestring, copysize); /* You don't use str* functions for this! */ 
printf("%s", copy); 
+0

-1 por usar malloc() en una copia de cadena cuando tienes strdup(). No reinvente la rueda cuando tenga una función de biblioteca. –

+0

@ Aaron Como se mencionó anteriormente, strdup() no es ANSI, no existirá en todos los sistemas. El punto de esta respuesta se puede aplicar cuando escribe su propia versión de strdup(). – Trent

1

maneras de hacer el código más seguro (y más correcta)

  1. No haga una copia innecesaria. En el ejemplo, no hay un requisito aparente de que realmente necesite copiar somestring. Puede sacarlo directamente.
  2. Si tiene que hacer una copia de una cadena, escriba una función para hacerlo (o use strdup si la tiene). Entonces solo tienes que hacerlo bien en un solo lugar.
  3. Siempre que sea posible, inicialice el puntero a la copia inmediatamente cuando la declare.
  4. Recuerde asignar espacio para el terminador nulo.
  5. Recuerde verificar el valor de retorno desde malloc.
  6. Recuerde liberar la memoria malloc 'ed.
  7. No llame al printf con una cadena de formato no confiable. Use printf("%s", copy) o puts(copy).
  8. Utilice un lenguaje orientado a objetos con una clase de cadena o cualquier lenguaje con soporte de cadena incorporado para evitar la mayoría de estos problemas.
1

para añadir más a los caminos de Adrian McCarthy para hacer el código más seguro,

utilizar un analizador de código estático, que son muy buenos para encontrar este tipo de errores

Cuestiones relacionadas