El código siguiente genera un error y mata a mi solicitud. Esto tiene sentido, dado que el búfer está a sólo 10 bytes, y el texto es de 22 bytes de longitud (desbordamiento de búfer).

char buffer[10];    
int length = sprintf_s( buffer, 10, "1234567890.1234567890." ); 

¿Cómo puedo detectar este error, por lo que puedo informar que en lugar de estrellarse contra mi aplicación?

Edición:

Después de leer los comentarios de abajo me fui con _snprintf_s. Si devuelve un valor -1, a continuación, el buffer no se actualizó.

length = _snprintf_s( buffer, 10, 9, "123456789" );
printf( "1) Length=%d\n", length ); //Length == 9

length = _snprintf_s( buffer, 10, 9, "1234567890.1234567890." );
printf( "2) Length=%d\n", length ); //Length == -1

length = _snprintf_s( buffer, 10, 10, "1234567890.1234567890." );
printf( "3) Length=%d\n", length ); //Crash, it needs room for the NULL char 
Pasando el tamaño de búfer y el tamaño de búfer de menos uno es obtuso y propenso a error. Se debe preferir la variante describo a continuación: longitud = _snprintf_s(buffer, _TRUNCATE, «1234567890.1234567890.» ); Desde el primer parámetro de tamaño se omite el compilador utiliza la plantilla de la sobrecarga de la cual se deduce el tamaño. _TRUNCATE es un valor especial que hace lo que dice. No hay números de magia, y ahora el código es seguro, fácil de mantener, y un buen ejemplo. Si te gusta este comentario y _snprintf_s entonces usted debe seleccionar mi respuesta, en lugar de la peligrosa snprintf/_snprintf respuesta.

OriginalEl autor Steven smethurst | 2009-10-01

6 Comentarios

  1. 5

    Lugar de sprintf_s, usted podría utilizar snprintf (un.k.un _snprintf en windows).

    #ifdef WIN32
    #define snprintf _snprintf
    #endif
    
    char buffer[10];    
    int length = snprintf( buffer, 10, "1234567890.1234567890." );
    //unix snprintf returns length output would actually require;
    //windows _snprintf returns actual output length if output fits, else negative
    if (length >= sizeof(buffer) || length<0) 
    {
        /* error handling */
    }
    También hay un snprintf_s.
    Nota: como una cuestión de seguridad, si no hay suficiente espacio, el contenido del búfer podría no ser terminada en null.
    si MS reclamado de conformidad a C99 – que no – esa afirmación sería falsa; el estándar C99 requiere snprintf() a null terminar la cadena, a menos que la longitud de la cadena es 0. Sección 7.19.6.5: Si n es cero, no hay nada escrito… de lo Contrario, la salida de los personajes más allá de la n-1 de son descartadas en vez de estar escrito a la matriz, y un carácter null se escribe al final de los caracteres escritos en la matriz. Si la copia se lleva a cabo entre los objetos que se solapan, el comportamiento es indefinido.
    Leffler: fresco, no sabía que.
    Por favor, edita tu respuesta para eliminar la sugerencia de utilizar _snprintf. Esta es una increíblemente peligroso sugerencia.

    OriginalEl autor Managu

  2. 16

    Es por diseño. Todo el punto de sprintf_s, y otras funciones de la *_s de la familia, es para la captura de errores de saturación de búfer y tratarlos como condición previa violaciones. Esto significa que no están destinados a ser recuperables. Esto está diseñado para la captura de los errores de sólo – no tienes que llamar nunca sprintf_s si usted sabe que la cadena puede ser demasiado grande para un búfer de destino. En ese caso, utilice strlen primero para revisar y decidir si es necesario recortar.

    No estoy de acuerdo. Es totalmente razonable para llamar sprintf_s con un búfer de destino que es demasiado pequeño, mientras que el uso de la _TRUNCATE bandera para indicar que. Bueno, técnicamente _TRUNCATE requiere el uso de snprintf_s en lugar de sprintf_s, pero mi punto es que la mayoría de stands. El uso de la función strlen es a menudo inadecuado o inconveniente, pero el uso de _TRUNCATE es a menudo trivial y apropiado.
    Yo creo que el uso de snprintf_s es la diferencia crucial, y en realidad no es un mero tecnicismo.
    Es una diferencia crucial, sin duda. Pero creo que su respuesta hace que parezca que el _s familia de funciones no se puede truncar, que podría ser engañosa.
    Sí, usted nunca debe hacer cualquier tipo de codificación del error, y entonces no habría necesidad de excepciones. No es obvio, pero usted necesita para reemplazar el valor predeterminado de error de controlador para el tiempo de ejecución de c funciones, entonces usted puede manejar como usted por favor, incluyendo lanzar su propia excepción. Ver _set_invalid_parameter_handler enlace y Jonathon Leffler respuesta.

    OriginalEl autor Pavel Minaev

  3. 5

    Esto funciona con VC++ y es incluso más seguro que usar snprintf (y sin duda más seguro que _snprintf):

    void TestString(const char* pEvil)
    {
      char buffer[100];
      _snprintf_s(buffer, _TRUNCATE, "Some data: %s\n", pEvil);
    }

    La _TRUNCATE bandera indica que la cadena debe ser truncado. En esta forma el tamaño del búfer no está realmente pasa, que (paradójicamente!) es lo que lo hace tan seguro. El compilador utiliza la plantilla de la magia para inferir el tamaño de búfer que significa que no pueden ser especificados de forma errónea (un sorprendentemente común de error). Esta técnica puede ser aplicada para crear otros seguro de la cadena de contenedores, como se describe en mi blog aquí:
    https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/

    buscando en la documentación de MSDN de _snprintf_s, parece que se han olvidado de un argumento en la llamada a _snprintf_s. Este argumento debe aparecer entre el buffer y _TRUNCATE y se llama sizeOfBuffer
    No me he olvidado de un argumento – que el código se compila y es perfectamente seguro. Usted necesita volver a leer la documentación. Estoy haciendo uso de una plantilla de reemplazar a _snprintf_s que le dice al compilador para inferir el tamaño del búfer. He visto cientos de lugares donde los programadores han pase explícitamente en un tamaño de búfer y han pasado en el mal tamaño. Sólo por tener el compilador inferir el tamaño de búfer puede este grave error evitarse. Me he referido a esta técnica en el artículo que he enlazado en mi solución. Muy recomendable.

    OriginalEl autor Bruce Dawson

  4. 0

    De MSDN:

    La principal diferencia entre sprintf_s y sprintf es que sprintf_s toma un parámetro de longitud de especificar el tamaño del buffer de salida en los personajes. Si el búfer es demasiado pequeño para el texto que se imprime luego de que el búfer se establece una cadena vacía y el parámetro no válido controlador se invoca. A diferencia de snprintf, sprintf_s garantiza que el buffer será terminada en null (a menos que el tamaño del búfer es cero).

    Así que lo ideal de lo que has escrito debería funcionar correctamente.

    El valor predeterminado «parámetro no válido controlador», termina el proceso.
    cierto, pero es fácil de instalar uno que no, que se traduce en sprintf_s devolver -1 si el búfer es demasiado pequeño

    OriginalEl autor Ashwin

  5. 0

    Parece que está escrito en MSVC de algún tipo?

    Creo que el MSDN docs para sprintf_s dice que afirman muere, así que no estoy demasiado seguro de si mediante programación puede coger.

    Como LBushkin sugerido, es mucho mejor usar las clases que manejan las cuerdas.

    OriginalEl autor Calyth

  6. 0

    Véase la sección 6.6.1 de TR24731 que es el ISO C Comité versión de la funcionalidad implementada por Microsoft. Proporciona funciones set_constraint_handler(), abort_constraint_handler() y ignore_constraint_handler() funciones.

    Hay comentarios de Pavel Minaev lo que sugiere que la implementación de Microsoft no se adhiere a la TR24731 propuesta (que es un ‘Tipo 2 Tech Report’), entonces usted no puede ser capaz de intervenir, o puede que tenga que hacer algo diferente de lo que el TR indica que debe hacerse. Para esto, examine MSDN.

    Por desgracia, MSVC no implementar TR24731 totalmente en particular, no se implementa específicamente las funciones que se referencia (también, sus nombres acabar también con _s – es decir,set_constraint_handler_s).
    Pero de acuerdo a la msdn.microsoft.com/en-us/library/ksazx244%28VS.80%29.aspx hay es una función _set_invalid_parameter_handler() función que se puede utilizar para cambiar el comportamiento predeterminado de abortar el programa.

    OriginalEl autor Jonathan Leffler

Dejar respuesta

Please enter your comment!
Please enter your name here