Sin error fuera de los límites

4 minutos de lectura

avatar de usuario
Cemre Mengü

Tengo este código en C que toma un montón de chars

#include<stdio.h> 
# define NEWLINE '\n'
int main()
{

char c;
char str[6];
int i = 0;
while( ((c = getchar()) != NEWLINE))
{
        str[i] = c;
        ++i;
        printf("%d\n", i);
}

return 0;
}

La entrada es: testtesttest

Salida: 1 2 3 4 5 6 7 8 117 118 119 120

Mis preguntas son:

  1. ¿Por qué no obtengo una excepción fuera de los límites (falla de segmentación) aunque excedo claramente la capacidad de la matriz?

  2. ¿Por qué los números en la salida saltan repentinamente a números muy grandes?

Intenté esto en C++ y obtuve el mismo comportamiento. ¿Alguien podría explicar cuál es la razón de esto?

  • Posible duplicado de Acceder a una matriz fuera de los límites no da error, ¿por qué?, ¿Qué tan peligroso es acceder a una matriz fuera de los límites?, etc.

    – jww

    4 de octubre de 2019 a las 11:53

avatar de usuario
jackman

Tienes que compilar así:

gcc -fsanitize=address -ggdb -o test test.c

Hay más información aquí.

  • -fsanitize=undefined es en realidad un diagnóstico mucho más fuerte. address solo se activará cuando el código falla en el tiempo de ejecución. A diferencia de, undefined desencadena un error de tiempo de ejecución para todos los comportamientos indefinidos, ya sea que haya un error de segmento en el tiempo de ejecución o no. Otro fsanitize también existen argumentos, documentados en man gcc.

    – 6equj5

    2 de febrero de 2021 a las 5:03


Escribir fuera de los límites de la matriz (en realidad, incluso simplemente realizar la aritmética del puntero/subíndice de la matriz, incluso si no usa el resultado para leer o escribir nada) da como resultado comportamiento indefinido. El comportamiento indefinido no es un error notificado o notificable; significa que su programa podría hacer cualquier cosa. Es muy peligroso y usted es completamente responsable de evitarlo. C no es Java/Python/etc.

avatar de usuario
Max E.

La asignación de memoria es más complicada de lo que parece. La variable “str”, en este caso, está en la pila, junto a otras variables, por lo que no la sigue la memoria no asignada. La memoria también suele estar alineada con palabras (una “palabra” tiene entre cuatro y ocho bytes). Posiblemente estaba jugando con el valor de otra variable, o con algún “relleno” (espacio vacío agregado para mantener la alineación de palabras) o algo completamente diferente. .

Como dijo R.., es un comportamiento indefinido. Las condiciones fuera de los límites podrían causar un error de segmento… o podrían causar una corrupción silenciosa de la memoria. Si está modificando la memoria que ya se ha asignado, el sistema operativo no lo detectará. Es por eso que los errores fuera de los límites son tan insidiosos en C.

Cuando accede a un índice de matriz, C y C ++ no realizan una verificación de límites. Las fallas de segmentación solo ocurren cuando intenta leer o escribir en una página que no estaba asignada (o intenta hacer algo en una página que no está permitida, por ejemplo, intenta escribir en una página de solo lectura), pero dado que las páginas generalmente son bastante grande (múltiplos de unos pocos kilobytes; en Mac OS, múltiplos de 4 KB), a menudo deja mucho espacio para desbordarse.

Si su matriz está en la pila (como la suya), puede ser aún peor ya que la pila suele ser bastante grande (hasta varios megabytes). Esta es también la causa de los problemas de seguridad: escribir más allá de los límites de una matriz en la pila puede sobrescribir la dirección de retorno de la función y provocar la ejecución de código arbitrario (las famosas infracciones de seguridad de “desbordamiento de búfer”).

Los valores que obtienes cuando lees son simplemente lo que existe en este lugar en particular. Ellos son completamente indefinido.

Si usa C++ (y tiene la suerte de trabajar con C++11), el estándar define el std::array<T, N> type, que es una matriz que conoce sus límites. Él at arrojará si intenta leer más allá del final.

  • Cuando un programa falla, siempre es el hardware el primero que reconoce que algo anda mal, no el sistema operativo. El sistema operativo es invocado por el hardware para manejar la falla de segmento, que luego puede cargar algunos datos del disco, proporcionar una página cero o enviar una señal al proceso infractor. Independientemente de lo que haga el sistema operativo, está limitado a la granularidad del tamaño de página del hardware. Y ese tamaño de página de hardware resulta ser 4kiB en X86.

    – cmaster – reincorporar a monica

    5 sep 2015 a las 20:18

¿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