2010-07-24 21 views
20

Estoy tratando de deshacerme de algunas advertencias del compilador que dicen que strcpy, sprintf, etc. no son seguros. Entiendo por qué no son seguros, pero no puedo pensar en una buena manera de corregir el código, en un estilo C++.Cómo deshacerse de advertencias/errores "inseguros" en Visual Studio (strcpy, sprintf, strdup)

Aquí está un extracto del código:

extList->names[i]=(char *)malloc(length*sizeof(char)); 
strcpy(extList->names[i],extName);      // unsafe 
// strncpy(extList->names[i],extName,length);   // also unsafe 

Aquí está el mensaje:

C4996: 'strcpy': Esta función o variable pueden ser inseguro. Considera usar strcpy_s en su lugar. Para desactivar la desactivación, use _CRT_SECURE_NO_WARNINGS. Consulte la ayuda en línea para obtener detalles.

No puedo pensar en una forma segura de copiar los datos en C++ sin saber la longitud de las cosas para copiar. Sé que hay strlen(), pero eso también es inseguro ya que supone (tal vez incorrectamente) que los datos están terminados en nulo.

También:

// used to concatenate: 
sprintf(extStr,"%s%s",platExtStr,glExtStr); 

C4996: 'sprintf': Esta función o variable pueden ser inseguros. Considere usando sprintf_s en su lugar. Para desactivar la desactivación, use _CRT_SECURE_NO_WARNINGS. Consulte la ayuda en línea para obtener detalles.

Usar std :: string para concatenar es bastante fácil, pero luego necesito obtener los datos en extStr de alguna manera (y no usando strcpy, lol). La función string :: c_str() devuelve un puntero a datos no modificables, por lo que no puedo simplemente establecer extStr igual a él. (Y ni siquiera estoy seguro de si el puntero c_str() necesita eliminar invocó más tarde? ¿Se asigna espacio usando "nuevo"?)

¿Algún consejo sobre esto? Esto es parte de un archivo de 10,000 líneas que no es mío ... así que no estoy exactamente interesado en volver a escribirlo en C++.

+4

Probablemente deba mencionar qué sistema operativo, entorno de programación y compilador está utilizando. –

+1

Y si es un estudio visual/win32, las advertencias del compilador incluso le dicen cómo apagarlas. – nos

+1

¿10,000 líneas de código en un archivo? Sugeriría una refactorización y luego me preocuparía limpiar las advertencias. –

Respuesta

4

¡Sabes cuánto copiar - asignó espacio para ello!

Seguramente no estaría dispuesto a copiar más que el espacio que asignó?

Preferiría utilizar un método que evite explícitamente los desbordamientos del búfer al limitar el número de elementos copiados. Cuando era un programador C utilizamos

dest = malloc(len);   // note: where did we get len? 
if (dest is null) panic! // note: malloc can fail 
strncpy(dest, src, len); 
dest[len-1] =0; 

Esto es ligeramente desordenado, y ha sido señalado está utilizando strncpy() un método que realmente fue diseñado originalmente para los campos de ancho fijo en lugar de cadenas. Sin embargo, lo hace ach

Existen métodos como strdup() y strlcpy() que pueden ayudar.

Mis recomendaciones:

1). Su objetivo no debe ser suprimir las advertencias, sino hacer que el código sea sólido.

2).Cuando copie cadenas, debe asegurarse de lo siguiente:

  • Protéjase contra la entrada incorrecta, por ejemplo, una cuerda no terminada o excesivamente larga.
  • protegerse de los fallos malloc,
  • fuertemente prefieren copias de números contados de caracteres a la copia hasta que veamos un nulo
  • Si usted demanda para construir una cadena, a continuación, hacer abolsutely Seguro que NULL terminarlo

Si strlcpy() está disponible en su entorno, entonces podría usarlo, de lo contrario, ¿por qué no escribir su propia pequeña función de utilidad? Entonces, si hay advertencias solo en esa función que has localizado, entonces hay un problema.

+3

'strncpy' no es [para uso con cadenas C] (http://stackoverflow.com/questions/2884874/when-to-use-strncpy-or-memmove/2884974#2884974). 'strlcpy' o' memcpy' se pueden usar, dependiendo de las circunstancias. –

+0

Sí, strncpy tampoco es seguro. ¿Es strlcpy independiente de la plataforma? Sé que Microsoft tiene sprintf_s que no funcionarán con otros compiladores. – Andre

1

Creo que debe reemplazar todas las llamadas a la función si es posible para llamar a una implementación propia. Un buen ejemplo aquí sería una función para reemplazar strcpy y llamar a la versión específica del compilador de strcpy dentro de él. Su implementación puede modificarse fácilmente para adaptarse a cualquier compilador de su elección, específicamente si va a agregar o cambiar plataformas/compiladores.

Ejemplo:


char* StringCopy(char* Destination, const char* Source, size_t DestinationSize) 
{ 
#ifdef _MSC_VER 
    return strcpy_s(Destination, Source, DestinationSize); 
#else 
    if(!(strlen(Source) >= DestinationSize)) 
    return strcpy(Destination, Source); 
    else 
    return 0x0; 
#endif 
} 
+0

Disculpa la! (Strlen (Fuente)> = Tamaño de destino). No pude hacer funcionar el "<". – Simon

+3

-1. La implementación estándar no tiene errores desconocidos, pero es probable que su nueva implementación los tenga. Estarás reinventando la rueda. – SigTerm

+0

-1 reinventar la rueda es un olor de código –

28

Usted realmente no necesita pragmas para desactivarlas.

para Win32/msvc, en ProjectProperties -> Propiedades de configuración -> C/C++ -> preprocesador -> preprocesador Definiciones, añadir siguientes macros:

_CRT_SECURE_NO_DEPRECATE 
_CRT_NONSTDC_NO_DEPRECATE 

O puede pasar Thos en los parámetros de línea de comandos (- D_CRT_SECURE_NO_DEPRECATE). Probablemente pueda #definirlos al comienzo de ciertos archivos * .cpp. Además, probablemente haya más de ellos (ver crtdefs.h - parece que hay muchos de ellos ...). Ese tipo de advertencias normalmente te dicen con qué macros puedes desactivarlas, solo lee el resultado del compilador.

+0

Esto es exactamente lo que necesita. El primero normalmente eliminará todas las sugerencias de función * _s. – rubenvb

3

En su primer ejemplo, ya conoce la longitud. Como no está asignando length+1 bytes, supongo que length INCLUYE el terminador nulo. En ese caso, simplemente std::copy la cadena: std::copy(extName, extName + length, expList->names[i]);

En el segundo ejemplo asumiendo las cuerdas de origen se termine con un nulo se podría calcular la longitud de la cadena de destino y utilizar std::copy de nuevo para concatenar manualmente, o se puede utilizar std::string y la std::copy de la resultados de c_str en su destino (Suponiendo nuevamente que haya asignado suficiente espacio para ello).

c_str() no asigna memoria que requeriría eliminación externa.

Finalmente, tenga en cuenta que sizeof(char) siempre será uno y, por lo tanto, es redundante en su malloc, aunque el número de bits en ese carácter puede no ser 8 (consulte CHAR_BIT).

+1

Usar std :: copy también me advierte que no es seguro porque requiere que el usuario compruebe el tamaño :( – Andre

1

Si la portabilidad no es una preocupación, puede usar 'strcpy_s'.

5

Si deshacerse de las advertencias solo es su objetivo ... simplemente defina este _CRT_SECURE_NO_WARNINGS y suprimirá todas las advertencias de desaprobación. Pero esto no solucionará los problemas subyacentes con las funciones CRT inseguras.

Si está en la versión de Visual Studio> = 2005 y desea corregir estas advertencias de forma adecuada ... el método más fácil es #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 y #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 en su proyecto.

sin más cambios de código se puede observar que la mayoría de las advertencias se corrigen automáticamente. Al definir esta ventana, automáticamente se llamará a las funciones de sobrecarga segura para la mayoría de las funciones CRT inseguras. Los tamaños de búfer para matrices estáticas se calculan automáticamente.

Aunque los búferes asignados dinámicamente no se arreglan de esta forma y debemos repararlos manualmente. Consulte this link para obtener más información.

A continuación se muestra una forma de corregir el ejemplo programáticamente

strcpy_s(extList->names[i], length, extName); 
6

Aquí es otra respuesta a esta pregunta.

#ifdef _MSC_VER 
#pragma warning(push) 
#pragma warning(disable : 4996) 
#endif 

     strcpy(destination, source); 

#ifdef _MSC_VER 
#pragma warning(pop) 
#endif 
+0

+1 Esto funciona para mí. La respuesta de VM Rakesh no funcionó. No sé por qué. – Diversity

+0

Probablemente no funcione si está utilizando encabezados precompilados, ya que el encabezado ya puede haber sido incluido sin el conjunto de macros. –

+0

Siempre puede colocarlo, como una de las primeras líneas, en stdafx.h antes de incluir cualquier otro Sin embargo, una palabra de advertencia: compruebe todas las líneas de advertencia C4996 que el compilador le da antes de desactivarlo por completo. Esta advertencia no se proporciona en vano. – PapaAtHome

0

Si este código solo se compila para la plataforma de Windows, entonces es mejor utilizar la versión segura de estas funciones. Sin embargo, si este código se compila en varias plataformas (Linux, Aix, etc.), entonces puede desactivar la advertencia en su archivo de configuración de proyecto de Windows (por ejemplo, .vcxproj) utilizando _CRT_SECURE_NO_WARNINGS o, puede usar un fragmento de código como este en los lugares donde esas funciones han sido llamadas en el archivo .cpp.

#if _OS_ == _OS__WINDOWS 
//secure function call 
#else 
//already written code 
#endif