¿Qué sucede si bash acceder a la memoria más allá de una región malloc () ‘d?

He asignado una tirada de memoria con char* memoryChunk = malloc ( 80* sizeof(char) + 1); ¿Qué me impide escribir en la ubicación de la memoria más allá de 81 unidades? ¿Qué puedo hacer para prevenir eso?

 void testStage2(void) { char c_str1[20] = "hello"; char* ut_str1; char* ut_str2; printf("Starting stage 2 tests\n"); strcat(c_str1, " world"); printf("%s\n", c_str1); // nothing exciting, prints "hello world" ut_str1 = utstrdup("hello "); ut_str1 = utstrrealloc(ut_str1, 20); utstrcat(ut_str1, c_str1); printf("%s\n", ut_str1); // slightly more exciting, prints "hello hello world" utstrcat(ut_str1, " world"); printf("%s\n", ut_str1); // exciting, should print "hello hello world wo", 'cause there's not enough room for the second world } char* utstrcat(char* s, char* suffix){ int i = strlen(s),j; int capacity = *(s - sizeof(unsigned) - sizeof(int)); for ( j =0; suffix[j] != '\0'; j++){ if ((i+j-1) == 20) return s; s[i+j] = suffix[j]; } //strcpy(s, suffix); s[i + j] = '\0'; return s; }// append the suffix to s 

¿Qué me impide escribir en la ubicación de la memoria más allá de 81 unidades?

Nada. Sin embargo, hacer esto da como resultado un comportamiento indefinido . Esto significa que cualquier cosa puede suceder, y no deberías depender de que haga lo mismo dos veces. 99.999% de las veces esto es un error.

¿Qué puedo hacer para prevenir eso?

Siempre verifique que sus punteros estén dentro de los límites antes de acceder (leerlos o escribirlos). Siempre asegúrese de que las cadenas terminen con \0 al pasar a las funciones de cadena.

Puede usar herramientas de depuración como valgrind para ayudarlo a encontrar errores relacionados con el puntero fuera de límites y el acceso a la matriz.

enfoque de stdlib

Para su código, puede tener utstrncat que actúa como utstrcat pero toma un tamaño máximo (es decir, el tamaño del búfer).

El enfoque de stdc ++

También puede crear una matriz struct / class o usar std::string en C ++. Por ejemplo:

 typedef struct UtString { size_t buffer_size; char *buffer; } UtString; 

Luego haz que tus funciones operen en eso. Incluso puede tener una reasignación dinámica usando esta técnica (pero eso no parece ser lo que quiere).

Enfoque de marcador de final de buffer

Otro enfoque es tener un marcador de final de buffer , similar al final del marcador de cadena . Cuando encuentre el marcador, no escriba en ese lugar ni en otro antes (para el final del marcador de cadena) (o puede reasignar el búfer para que haya más espacio).

Por ejemplo, si tiene "hello world\0xxxxxx\1" como una cadena (donde \0 es el final del marcador de cadena, \1 es el final del marcador de memoria intermedia, y las x son datos aleatorios). Agregar " this is fun" se vería así:

 hello world\0xxxxxx\1 hello world \0xxxxx\1 hello world t\0xxxx\1 hello world th\0xxx\1 hello world thi\0xx\1 hello world this\0x\1 hello world this \0\1 *STOP WRITING* (next bytes are end of string then end of buffer) 

Tu problema

El problema con tu código está aquí:

  if ((i+j-1) == 20) return s; 

Aunque se está deteniendo antes de sobrepasar el búfer, no está marcando el final de la cadena.

En lugar de regresar, puede usar break para terminar el bucle for prematuramente. Esto causará que el código se ejecute después del bucle for . Esto establece el final del marcador de cadena y devuelve la cadena, que es lo que desea.

Además, me temo que puede haber un error en su asignación. Tienes + 1 para asignar el tamaño antes de la cadena, ¿correcto? Hay un problema: unsigned generalmente no tiene 1 caracter; necesitarás + sizeof(unsigned) para eso. También escribiría utget_buffer_size y utset_buffer_size para que pueda realizar cambios más fácilmente.

Nada te impide hacer eso. Si lo hace, podría pasar cualquier cosa: el progtwig podría continuar de forma feliz como si nada hubiera sucedido, podría colapsar ahora, podría colapsar más tarde, incluso podría borrar su disco duro. Este es el reino del comportamiento indefinido .

Hay una serie de herramientas que intentan detectar o mitigar este tipo de problemas, pero nada es infalible. Una de esas herramientas es valgrind . Valgrind observa el patrón de accesos de memoria de su progtwig y le notifica problemas como este. Hace esto ejecutando su progtwig en una especie de máquina virtual, por lo que perjudica significativamente el rendimiento de su progtwig, pero puede ayudarlo a detectar muchos errores cuando se usa correctamente.

Nada le impide escribir más allá de ese límite, y lo que sucede depende de lo que está más allá de ese límite. Truco de hacker estándar (desbordamiento de búfer) para piratear progtwigs que no verifican y asegurarse de que no sobrescriban los límites del búfer.

Como lo mencionan otros carteles, solo tiene que progtwigr cuidadosamente. No use llamadas como strlen, strcpy – use los versoins de longitud limitada como strncpy, etc.

Carl sugiere strncpy () , que es un comienzo en la dirección correcta. La idea principal es desarrollar el hábito de evitar los desbordamientos del búfer adoptando prácticas específicas. Una biblioteca más deliberada para esto está cubierta en strlcpy y strlcat: consistente, segura, copia de cadenas y concatenación .

Qué sucede: nada, o su progtwig obtendrá SIGSEGV arrojado sobre él. Lo que debe hacer: escriba su progtwig cuidadosamente. Use herramientas como valgrind.