2009-06-01 21 views
5

cuando trato de hacer cosas como esta:¿Por qué MSVC++ considera que "std :: strcat" es "inseguro"? (C++)

char* prefix = "Sector_Data\\sector"; 
char* s_num = "0"; 
std::strcat(prefix, s_num); 
std::strcat(prefix, "\\"); 

y así sucesivamente y así sucesivamente, recibo una advertencia

warning C4996: 'strcat': This function or variable may be unsafe. Consider using strcat_s instead. 

¿Por qué es strcat considera inseguro, y hay una manera para deshacerse de esta advertencia sin usar strcat_s?

Además, si la única manera de deshacerse de la advertencia es usar strcat_s, ¿cómo funciona? (Sintaxis: aparentemente no toma dos argumentos).

+13

debe saber que su ejemplo es terriblemente incorrecto. Las constantes de cadena (como: char * s = "hello";) NO son grabables. Si tiene suerte, se bloqueará, si tiene mala suerte hará que la aplicación funcione incorrectamente de alguna manera sutil. la forma correcta de hacer lo que quería es así: prefijo de pila [SIZE] = "Sector_Datos \\ sector"; donde TAMAÑO es lo suficientemente grande como para contener el prefijo Y lo que sea que desee agregar a él. –

+3

Tal como está escrito, su ejemplo contiene un desbordamiento de búfer. No solo un posible desbordamiento del búfer, sino cierto. –

Respuesta

26

Porque el búfer, prefijo, podría tener menos espacio del que está copiando en él, provocando un desbordamiento del búfer. Por lo tanto, un pirata informático podría pasar una cadena especialmente diseñada que sobrescriba la dirección de retorno u otra memoria crítica y comience a ejecutar el código en el contexto de su programa.

strcat_s resuelve esto forzándolo a pasar la longitud del búfer en el que está copiando la cadena; truncará la cadena si es necesario para asegurarse de que no se sobrepase el búfer.

google strcat_s para ver exactamente cómo usarlo.

+1

strcat_s es una de las funciones de la biblioteca de liberación como parte de las Mejoras de seguridad en el CRT - http://msdn.microsoft.com/en-us/library/8ef0s5kh(VS.80).aspx – Sean

+3

La verdad es dicha, esto es simplemente un miedo a Microsoft en nombre de Microsoft para asegurarse de que el código que usted escribe no se pueda compilar en ningún otro lugar que no sea Windows.'strcat_s' no es más que un' strncat' propietario (que ha existido durante 40 años). Además, 'strcat' no es inseguro como tal en primer lugar, ni llama' strcat_s' con la longitud proporcionada por 'strlen' más segura. Lo que no es seguro es aceptar ciegamente la entrada de usuario arbitraria (y de longitud arbitraria), pero usar una función no estándar no resuelve ese problema, solo se bloqueará en una función diferente ('strlen'). – Damon

+1

@DeadMG: Es cierto que usar 'strcat_s' significa que no necesita restar la longitud inicial del tamaño total, pero aparte de eso, es exactamente el mismo, excepto que no es estándar ni portátil. Pero mi punto en general es que usar funciones "seguras" no hace que nada sea más seguro en absoluto. Usted sabe que puede confiar en algunos datos (como literales de cadenas en su programa) o sabe que no puede confiar en ellos (datos ingresados ​​por el usuario) y, en cualquier caso, debe conocer los tamaños de búfer de destino. Si ese no es el caso, todo se pierde, independientemente de las funciones "seguras" que uno use. Lo mismo vale para strncat también, ... – Damon

3

Porque no tiene medios para verificar si la cadena de destino (prefijo) en su caso se escribirá más allá de sus límites. strcat esencialmente funciona mediante bucle, copiando byte por byte la cadena de origen en el destino. Se detiene cuando ve un valor "0" (anotado por '\ 0') llamado terminal nulo. Como C no tiene una verificación de límites incorporada, y el dest str es solo un lugar en la memoria, strcat continuará yendo ad-infinidium incluso si pasa la fuente str o el dest. str no tiene un terminal nulo.

Las soluciones anteriores son específicas de la plataforma para su entorno de Windows. Si quieres algo independiente de plataforma, tiene que bregar con strncat:

strncat(char* dest, const char* src, size_t count) 

Esta es otra opción cuando se utiliza de forma inteligente. Puede usar conteo para especificar el número máximo de caracteres para copiar. Para hacer esto, debes averiguar cuánto espacio hay disponible en dest (cuánto asignaste - strlen (dest)) y pasarlo como count.

+1

Incluso strncat no es seguro. Desde MSDN: strncat no comprueba suficiente espacio en strDest; por lo tanto, es una causa potencial de los desbordamientos del búfer. Tenga en cuenta que el conteo limita el número de caracteres agregados; no es un límite en el tamaño de strDest. Vea el ejemplo a continuación. Para obtener más información, vea Evitar saturaciones de búfer. –

+0

La comprobación del espacio suficiente en el almacenamiento intermedio de destino está fuera del alcance del idioma y requiere instalaciones adicionales por parte del sistema operativo/compilador. –

+2

MSDN no tiene sentido acerca de strncat(). Obliga al programador a ingresar un tamaño, y dos tamaños se pueden equivocar con la misma facilidad que uno. El problema con strncat(), como strncpy(), es que no hace lo mismo que un strcat de longitud limitada() (o strcpy()). –

4

Esa es una de las funciones de manipulación de cadenas en C/C++ que puede provocar errores de desbordamiento del búfer.

El problema es que la función no sabe cuál es el tamaño de los búferes. A partir de la documentación de MSDN:

El primer argumento, strDestination, debe ser lo suficientemente grande para contener el strDestination actual y strSource combinado y una de cierre '\ 0'; de lo contrario, puede producirse un desbordamiento del búfer.

strcat_s toma un argumento extra diciéndole el tamaño del búfer. Esto le permite validar los tamaños antes de hacer el concat, y evitará los excesos. Ver http://msdn.microsoft.com/en-us/library/d45bbxx4.aspx

+0

+1 Para proporcionar el enlace a la documentación real. – Eclipse

+0

Ahora, si el compilador también verificó si el argumento 'strcat_s' era correcto o si el comportamiento de' strcat_s' era confiable en caso de error ... Desafortunadamente, tampoco es el caso, por lo que es un ejercicio inútil. – Deduplicator

28

Si está utilizando C++, ¿por qué no evitar todo el lío y utilizar std::string.El mismo ejemplo sin ningún error se vería así:

std::string prefix = "Sector_Data\\sector"; 
prefix += "0"; 
prefix += "\\" 

sin necesidad de preocuparse por los tamaños del búfer y todo eso. Y si tiene una API que toma un const char *, puede simplemente usar el miembro .c_str();

some_c_api(prefix.c_str()); 
+4

Es bueno ver una buena respuesta al problema subyacente. Yo hubiera votado más de una vez si pudiera. –

4

Usted puede deshacerse de ellos mediante la adición de advertencia:

_CRT_SECURE_NO_WARNINGS 

y

_SCL_SECURE_NO_WARNINGS 

a las definiciones del preprocesador de su proyecto.

+0

Sí, suprimir el mensaje de advertencia utilizando la marca de arriba es la mejor opción si quiere escribir código portátil. El uso de strcat_s puede generar código no portátil, ya que es específico del compilador de Microsoft. –

0

Hay dos problemas con strcat. En primer lugar, usted tiene que hacer todo su validación fuera de la función, hacer un trabajo que es casi lo mismo que la función:

if(pDest+strlen(pDest)+strlen(pScr) < destSize) 

Tienes que caminar por toda la longitud de ambas cadenas sólo para asegurarse de que se ajuste, antes de recorrer toda su longitud OTRA VEZ para hacer la copia. Debido a esto, muchos programadores simplemente asumirán que encajará y se saltearán la prueba. Peor aún, puede ser que cuando se escribe el código por primera vez, se GARANTIZE que se ajuste, pero cuando alguien agrega otro strcat, o cambia un tamaño de búfer o constante en algún otro lugar del programa, ahora tiene problemas.

El otro problema es si pSrc y pDst se superponen. Dependiendo de su compilador, strcat puede ser un bucle simple que comprueba un carácter a la vez para un 0 en pSrc. Si pDst sobrescribe ese 0, entonces entrarás en un bucle que se ejecutará hasta que tu programa falle.

4

Para desactivar la advertencia, puede hacerlo.

#pragma warning(disable:4996) 

btw, le recomiendo encarecidamente que utilice strcat_s().

Cuestiones relacionadas