Es sprintf(búfer, “%s […]”, buffer, […]) ¿a salvo?

4 minutos de lectura

avatar de usuario
pablo pescador

Vi el uso de este patrón para concatenar en una cadena en un código en el que estaba trabajando:

sprintf(buffer, "%s <input type="file" name="%s" />\r\n", buffer, id);
sprintf(buffer, "%s</td>", buffer);

y estoy bastante seguro de que no es seguro C. Notarás que buffer es tanto la salida como la primera entrada.

Aparte de la posibilidad obvia de un desbordamiento de búfer, creo que no hay garantía de que el búfer no cambie entre el inicio y el final de la función (es decir, no hay garantía de cuál será el estado del búfer durante la ejecución de la función). La firma de sprintf especifica además que la cadena de destino es restrictedición

También recuerdo un informe de un escritura especulativa en memcpy, y no veo ninguna razón por la que alguna biblioteca de C pueda hacer lo mismo en un sprintf. En este caso, por supuesto, estaría escribiendo a su fuente. Entonces ¿Es este comportamiento seguro?

FYI, propuse:

char *bufEnd = buffer + strlen(buffer);
/* sprintf returns the number of f'd and print'd into the s */
bufEnd += sprintf(bufEnd, " <input type="file" name="%s" />\r\n", id);

para reemplazar esto.

  • Incluso si es a salvo (no se bloqueará, etc.) Puedo imaginarlo generando un resultado diferente al esperado.

    – nadie

    16 de agosto de 2009 a las 3:08

  • @AndrewMedico ¿Cómo es eso?

    – gato

    27/09/2016 a las 21:49

avatar de usuario
Karl Voigtland

Desde el documentación de glibc sprintf():

El comportamiento de esta función no está definido si la copia tiene lugar entre objetos que se superponen; por ejemplo, si s también se proporciona como argumento para imprimir bajo el control de la conversión ‘%s’.

Puede ser seguro en una implementación particular; pero no podías contar con que fuera portátil.

Tampoco estoy seguro de que su propuesta sea segura en todos los casos. Todavía podría estar superponiendo búferes. Es tarde y mi esposa me está molestando, pero creo que aún podría tener el caso en el que desea usar la cadena original nuevamente en la cadena concatenada y está sobrescribiendo el carácter nulo y, por lo tanto, es posible que la implementación de sprintf no sepa dónde se reutilizó. extremos de cuerda.

Es posible que desee seguir con un snprint() en un búfer temporal, luego strncat() en el búfer original.

  • De acuerdo, solo quería un control de cordura. POSIX dice lo mismo: > Si la copia tiene lugar entre objetos que se superponen como resultado de una llamada a sprintf() o snprintf(), los resultados no están definidos.

    –Paul Fisher

    16 de agosto de 2009 a las 3:00

  • En realidad, no estoy superponiendo búferes en mi segundo, es un búfer estrictamente diferente. No uso el original.

    –Paul Fisher

    16 de agosto de 2009 a las 3:14

  • A menos que estés viendo algo que yo no veo, lo cual es totalmente posible.

    –Paul Fisher

    16 de agosto de 2009 a las 3:15

  • ok si lo veo; Supongo que el único caso arriesgado es si desea reutilizar la cadena original en algún punto de la cadena concatenada.

    -Karl Voigtland

    16 de agosto de 2009 a las 3:16

En este caso específico, va a funcionar porque la cadena en buffer será lo primero que va a entrar buffer (de nuevo, inútil), así que deberías usar strcat() en cambio para obtener el [almost] mismo efecto.

Pero, si está tratando de combinar strcat() con las posibilidades formativas de sprintf()puedes intentar esto:

sprintf(&buffer[strlen(buffer)], " <input type="file" name="%s" />\r\n", id);

Si desea concatenar texto formateado al final de un búfer usando printf(), le recomiendo que use un número entero para realizar un seguimiento de la posición final.

int i = strlen(buffer);
i += sprintf(&buffer[i], " <input type="file" name="%s" />\r\n", id);
i += sprintf(&buffer[i], "</td>");

o:

int i = strlen(buffer);
i += sprintf(&buffer[i], " <input type="file" name="%s" />\r\n", id);
strcat(&buffer[i], "</td>");

Y antes de que la gente se vuelva loca al votar negativamente (“¡Esto no es seguro! ¡Puedes desbordar el búfer!”), Solo estoy abordando una forma razonable de construir una cadena formateada en C/C++.

  • Creo que su sugerencia es funcionalmente igual a mi reemplazo propuesto, pero usa una notación ligeramente diferente. Sin embargo, puedo ver por qué algunos prefieren verlo escrito de esta manera.

    –Paul Fisher

    16 de agosto de 2009 a las 3:47

¿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