Abortar en lugar de segfault con clara violación de memoria

Me encontré con este comportamiento extraño cuando se trata de cadenas en C. Este es un ejercicio del libro de K&R donde se suponía que escribiera una función que agrega una cadena al final de otra. Esto obviamente requiere que la cadena de destino tenga suficiente memoria asignada para que la cadena de origen se ajuste. Aquí está el código:

/* strcat: Copies contents of source at the end of dest */ char *strcat(char *dest, const char* source) { char *d = dest; // Move to the end of dest while (*dest != '\0') { dest++; } // *dest is now '\0' while (*source != '\0') { *dest++ = *source++; } *dest = '\0'; return d; } 

Durante las pruebas escribí lo siguiente, esperando que ocurriera un error de seguridad mientras el progtwig se está ejecutando:

 int main() { char s1[] = "hello"; char s2[] = "eheheheheheh"; printf("%s\n", strcat(s1, s2)); } 

Según tengo entendido, s1 tiene una matriz de 6 chars asignados y s2 una matriz de 13 chars . Pensé que cuando strcat intenta escribir en s1 en índices superiores a 6, el progtwig falla. En su lugar, todo funciona bien, pero el progtwig no se cierra limpiamente, sino que funciona:

 helloeheheheheheh zsh: abort ./a.out 

y sale con el código 134, que creo que simplemente significa abortar.

¿Por qué no obtengo una falla de seguridad (o sobrescribo s2 si las cadenas están asignadas en la stack)? ¿Dónde están estas cadenas en la memoria (la stack o el montón)?

Gracias por tu ayuda.

Pensé que cuando Strcat intenta escribir en s1 en índices superiores a 6 el progtwig falla.

Escribir fuera de los límites de la memoria que ha asignado en la stack es un comportamiento indefinido . Invocar este comportamiento indefinido usualmente (pero no siempre) resulta en un segfault. Sin embargo, no puede estar seguro de que ocurrirá una falla de seguridad.

El enlace de wikipedia lo explica muy bien:

Cuando se produce una instancia de comportamiento indefinido, en lo que concierne a la especificación del lenguaje, cualquier cosa podría suceder, tal vez nada.

Por lo tanto, en este caso, podría obtener una falla de seguridad, el progtwig podría abortar o, a veces, podría funcionar bien. O algo. No hay forma de garantizar el resultado.

¿Dónde están estas cadenas en la memoria (la stack o el montón)?

Ya que los ha declarado como char [] en main() , son matrices que tienen almacenamiento automático , lo que por razones prácticas significa que están en la stack.

Edición 1:

Voy a intentar explicarte cómo podrías descubrir la respuesta por ti mismo. No estoy seguro de lo que realmente sucede, ya que esto no es un comportamiento definido (como han dicho otros), pero puede hacer una depuración simple para averiguar qué está haciendo realmente su comstackdor.

Respuesta original

Mi conjetura sería que ambos están en la stack. Puedes verificar esto modificando tu código con:

 int main() { char c1 = 'X'; char s1[] = "hello"; char s2[] = "eheheheheheh"; char c2 = '3'; printf("%s\n", strcat(s1, s2)); } 

c1 y c2 van a estar en la stack. Sabiendo que puede comprobar si s1 y s2 son.

Si la dirección de c1 es menor que s1 y la dirección de s1 es menor que c2 entonces está en la stack. De lo contrario, es probable que esté en su sección .bss (lo que sería lo más inteligente que se podría hacer pero rompería la recursión).

La razón por la que estoy apostando a que las cadenas estén en la stack es que si las está modificando en la función, y esa función se llama a sí misma, entonces la segunda llamada no tendría su propia copia de las cadenas y, por lo tanto, no sería válida. .. Sin embargo, el comstackdor todavía sabe que esta función no es recursiva y puede poner las cadenas en el .bss por lo que podría estar equivocado.

Suponiendo que supongo que está en la stack es correcto, en su código

 int main() { char s1[] = "hello"; char s2[] = "eheheheheheh"; printf("%s\n", strcat(s1, s2)); } 

"hello" (con el terminador nulo) se coloca en la stack, seguido de "eheheheheheh" (con el terminador nulo).

Ambos están ubicados uno tras otro (gracias a la simple suerte del orden en el que los escribió) formando un único bloque de memoria en el que puede escribir (¡pero no debería!) … Es por eso que no hay una falla de Seg, Puedes ver esto rompiendo antes de printf y mirando las direcciones.

s2 == (uintptr_t)s1 + (strlen(s1) + 1) debe ser verdadero si tengo razón.

Modificar tu código con

 int main() { char s1[] = "hello"; char c = '3'; char s2[] = "eheheheheheh"; printf("%s\n", strcat(s1, s2)); } 

Debería ver c sobrescrito si tengo razón …

Sin embargo, si estoy equivocado y está en la sección .bss , entonces podrían estar adyacentes y se los sobrescribiría sin una falla de seguridad.

Si realmente quieres saberlo, desmóntalo:

Desafortunadamente solo sé cómo hacerlo en Linux. Intente usar el comando nm > .txt u objdump -t > .sym comando de objdump -t > .sym para volcar todos los símbolos de su progtwig. Los comandos también deben proporcionarle la sección en la que reside cada símbolo.

Busque los símbolos s1 y s2 el archivo; si no los encuentra, significa que están en la stack, pero lo comprobaremos en el siguiente paso.

Use el comando objdump -S your_binary > text_file.S (asegúrese de construir su binario con símbolos de depuración) y luego abra el archivo .S en un editor de texto.

Busque de nuevo los símbolos s1 y s2 (espero que no haya otros, sospecho que no, pero no estoy seguro).

Si encuentra sus definiciones seguidas de un comando push o sub %esp , entonces están en la stack. Si no está seguro de lo que significan sus definiciones, publíquelo nuevamente aquí y déjenos echarle un vistazo.

No hay ninguna falla de seguridad o incluso una sobrescritura porque puede usar la memoria de la segunda cadena y seguir funcionando. Incluso dar la respuesta correcta. El aborto es una señal de que el progtwig se dio cuenta de que algo estaba mal. Intente invertir el orden en el que declara las cadenas e intente nuevamente. Probablemente no será tan agradable.

 int main() { char s1[] = "hello"; char s2[] = "eheheheheheh"; printf("%s\n", strcat(s1, s2)); } 

en su lugar utiliza:

  int main() { char s1[20] = "hello"; char s2[] = "eheheheheheh"; printf("%s\n", strcat(s1, s2)); } 

Esta es la razón por la que su progtwig no se bloqueó:

Sus cadenas se declaran como matriz (s1 [] y s2 []). Así que están en la stack. Y sucede que la memoria para s2 [] está justo después de s1 []. Entonces, cuando se llama a strcat (), todo lo que hace es mover cada carácter en s2 [] un byte hacia adelante. La stack como stack es legible y se puede escribir. Así que no hay restricción a lo que estás haciendo.

Pero creo que el comstackdor es libre de ubicar s1 [] y s2 [] donde se ajuste, así que esto es solo un feliz accidente.

Ahora hacer que tu progtwig se bloquee es relativamente fácil

  1. Intercambie s1 y s2 en su llamada: en lugar de strcat (s1, s2), haga strcat (s2, s1). Esto debería causar la excepción de aplastamiento de stack.
  2. Cambie s1 [] y s2 [] a * s1 y * s2. Esto debería causar un error de seguridad cuando se escribe en un segmento de solo lectura.

hmm … las cadenas están bien astackdas ya que heap se usa solo para la asignación dinámica de memoria y demás …

segfault es para el acceso a la memoria no válida, pero con esta matriz solo está escribiendo cosas que están fuera del límite (fuera del límite) para la matriz, así que al escribir no creo que tenga un problema … Ya que en C es su De hecho, se deja al progtwigdor para asegurarse de que las cosas se mantengan dentro de los arreglos.

Además, al leer, si usas punteros, no creo que haya ningún problema, ya que puedes seguir leyendo hasta donde quieras y usando la sum de las longitudes anteriores. Pero si usa las funciones que se mencionan en string.h, retransmiten la presencia del carácter nulo “\ 0” para decidir dónde detener la operación; por lo tanto, creo que su función funcionó.

pero la terminación también podría indicar que cualquier otra variable / algo que pudiera haber estado presente al lado de la ubicación de las cadenas podría haberse sobreescrito con un valor char … ¡El acceso a esas podría haber causado la salida del progtwig!

Espero que esto ayude …. buena pregunta por cierto!