strncat funciona como c strncpy

funciona - strncpy arduino



¿Por qué strncpy no null termina? (11)

strncpy() supuestamente protege de desbordamientos de búfer. Pero si evita un desbordamiento sin terminación nula, con toda probabilidad una operación de cadena subsiguiente se desbordará. Entonces, para protegerme de esto, me encuentro haciendo lo siguiente:

strncpy( dest, src, LEN ); dest[LEN - 1] = ''/0'';

man strncpy da:

La función strncpy () es similar, excepto que no se copian más de n bytes de src. Por lo tanto, si no hay un byte nulo entre los primeros n bytes de src, el resultado no terminará en nulo.

Sin nulo terminando algo aparentemente inocente como:

printf( "FOO: %s/n", dest );

... podría colapsar.

¿Hay alternativas mejores y más seguras a strncpy() ?


Algunas nuevas alternativas se especifican en ISO / IEC TR 24731 (Consulte https://buildsecurityin.us-cert.gov/daisy/bsi/articles/knowledge/coding/317-BSI.html para obtener información). La mayoría de estas funciones toman un parámetro adicional que especifica la longitud máxima de la variable objetivo, aseguran que todas las cadenas terminen en nulo, y tienen nombres que terminan en _s (para "seguro"?) Para diferenciarlos de su anterior "inseguro" versiones. 1

Desafortunadamente, todavía están ganando soporte y pueden no estar disponibles con su conjunto de herramientas en particular. Las versiones posteriores de Visual Studio arrojarán advertencias si usa las antiguas funciones inseguras.

Si sus herramientas no son compatibles con las nuevas funciones, debería ser bastante fácil crear sus propias envolturas para las funciones anteriores. Aquí hay un ejemplo:

errCode_t strncpy_safe(char *sDst, size_t lenDst, const char *sSrc, size_t count) { // No NULLs allowed. if (sDst == NULL || sSrc == NULL) return ERR_INVALID_ARGUMENT; // Validate buffer space. if (count >= lenDst) return ERR_BUFFER_OVERFLOW; // Copy and always null-terminate memcpy(sDst, sSrc, count); *(sDst + count) = ''/0''; return OK; }

Puede cambiar la función para adaptarla a sus necesidades, por ejemplo, para copiar siempre la mayor cantidad de cadena posible sin desbordamiento. De hecho, la implementación de VC ++ puede hacer esto si pasa _TRUNCATE como el count .



1 Por supuesto, todavía necesita ser preciso sobre el tamaño del búfer de destino: si proporciona un búfer de 3 caracteres pero le dice a strcpy_s() que tiene espacio para 25 caracteres, todavía tiene problemas.

En lugar de strncpy() , podrías usar

snprintf(buffer, BUFFER_SIZE, "%s", src);

Aquí hay un trazador de líneas que copia como máximo caracteres de size-1 no nulo de src a dest y agrega un terminador nulo:

static inline void cpystr(char *dest, const char *src, size_t size) { if(size) while((*dest++ = --size ? *src++ : 0)); }


Estas funciones han evolucionado más que estar diseñadas, por lo que realmente no existe un "por qué". Solo tienes que aprender "cómo". Desafortunadamente, las páginas de manual de Linux al menos no tienen ejemplos de casos de uso común para estas funciones, y he notado un gran uso incorrecto en el código que he revisado. He tomado algunas notas aquí: http://www.pixelbeat.org/programming/gcc/string_buffers.html


Originalmente, el sistema de archivos UNIX de 7ma edición (ver DIR (5)) tenía entradas de directorio que limitaban los nombres de archivo a 14 bytes; cada entrada en un directorio constaba de 2 bytes para el número de inodo más 14 bytes para el nombre, nulo acolchado para 14 caracteres, pero no necesariamente terminado en nulo. Es mi creencia que strncpy() fue diseñado para trabajar con esas estructuras de directorio o, al menos, funciona perfectamente para esa estructura.

Considerar:

  • Un nombre de archivo de 14 caracteres no fue terminado nulo.
  • Si el nombre era más corto que 14 bytes, era nulo rellenado a longitud completa (14 bytes).

Esto es exactamente lo que se lograría mediante:

strncpy(inode->d_name, filename, 14);

Por lo tanto, strncpy() se adaptó idealmente a su aplicación de nicho original. Fue solo por casualidad sobre la prevención de desbordamientos de cadenas terminadas en nulo.

(Tenga en cuenta que el relleno nulo hasta la longitud 14 no es una sobrecarga grave; si la longitud del búfer es de 4 KB y todo lo que desea es copiar 20 caracteres de manera segura, los 4075 nulos adicionales son exagerados graves, y pueden ser fácilmente llevar a un comportamiento cuadrático si agrega material repetidamente a un buffer largo).


Siempre he preferido:

memset(dest, 0, LEN); strncpy(dest, src, LEN - 1);

para arreglarlo después se acerca, pero eso es solo una cuestión de preferencia.


Sin depender de extensiones más nuevas, he hecho algo como esto en el pasado:

/* copy N "visible" chars, adding a null in the position just beyond them */ #define MSTRNCPY( dst, src, len) ( strncpy( (dst), (src), (len)), (dst)[ (len) ] = ''/0'')

y quizás incluso:

/* pull up to size - 1 "visible" characters into a fixed size buffer of known size */ #define MFBCPY( dst, src) MSTRNCPY( (dst), (src), sizeof( dst) - 1)

¿Por qué las macros en lugar de funciones "incorporadas" (?) Más nuevas? Debido a que solía haber un buen número de unidades diferentes, así como otros entornos que no son de Unix (que no son Windows) que tuve que volver a puerto cuando estaba haciendo C a diario.


Strncpy es más seguro contra los ataques de desbordamiento de pila por parte del usuario de su programa, no lo protege contra los errores que el programador realiza, como la impresión de una cadena no terminada en nulo, de la manera que ha descrito.

Puede evitar el problema que ha descrito al limitar el número de caracteres impresos por printf:

char my_string[10]; //other code here printf("%.9s",my_string); //limit the number of chars to be printed to 9


Use strlcpy() , especificado aquí:

Si tu libc no tiene una implementación, prueba esta:

size_t strlcpy(char* dst, const char* src, size_t bufsize) { size_t srclen =strlen(src); size_t result =srclen; /* Result is always the length of the src string */ if(bufsize>0) { if(srclen>=bufsize) srclen=bufsize-1; if(srclen>0) memcpy(dst,src,srclen); dst[srclen]=''/0''; } return result; }

(Escrito por mí en 2004 - dedicado al dominio público).



strncpy funciona directamente con los búferes de cadena disponibles, si está trabajando directamente con su memoria, DEBE ahora almacenar en búfer los tamaños y puede configurar el ''/ 0'' manualmente.

Creo que no hay una mejor alternativa en el campo C, pero no es realmente tan malo si eres tan cuidadoso como deberías cuando juegas con memoria en bruto.


strncpy no está destinado a ser utilizado como un strcpy más seguro, se supone que se utiliza para insertar una cadena en el medio de otro.

Todas esas funciones de manejo de cadenas "seguras" como snprintf y vsnprintf son correcciones que se han agregado en estándares posteriores para mitigar los exploits de desbordamiento de búfer, etc.

Wikipedia menciona a strncat como una alternativa a la escritura de su propio strncpy seguro:

*dst = ''/0''; strncat(dst, src, LEN);

EDITAR

Eché de menos que strncat excede los caracteres LEN cuando nulo termina la cadena si es más larga o igual a LEN char''s.

De todos modos, el objetivo de utilizar strncat en lugar de cualquier solución interna como memcpy (..., strlen (...)) / lo que sea es que la implementación de strncat podría ser optimizada para el objetivo / plataforma en la biblioteca.

Por supuesto, debe verificar que dst contiene al menos el nullchar, por lo que el uso correcto de strncat sería algo así como:

if(LEN) { *dst = ''/0''; strncat(dst, src, LEN-1); }

También admito que strncpy no es muy útil para copiar una subcadena en otra cadena, si el src es más corto que n char, la cadena de destino se truncará.