Índice de matriz fuera de límite en C

¿Por qué C diferencia en caso de índice de matriz fuera de límite

 #include  int main() { int a[10]; a[3]=4; a[11]=3;//does not give segmentation fault a[25]=4;//does not give segmentation fault a[20000]=3; //gives segmentation fault return 0; } 

Entiendo que está intentando acceder a la memoria asignada para procesar o enhebrar en caso de a[11] o a[25] y se saldrá de los límites de la stack en caso de a[20000] .

¿Por qué el comstackdor o el enlazador no dan un error? ¿No conocen el tamaño de la matriz? Si no, ¿cómo funciona sizeof(a) correctamente?

El problema es que C / C ++ en realidad no hace ninguna comprobación de límites con respecto a las matrices. Depende del sistema operativo para asegurarse de que está accediendo a la memoria válida.

En este caso particular, está declarando una matriz basada en stack. Dependiendo de la implementación particular, el acceso fuera de los límites de la matriz simplemente accederá a otra parte del espacio de stack ya asignado (la mayoría de los SO e hilos reservan una cierta porción de memoria para la stack). Siempre y cuando solo juegue en el espacio de stack preasignado, todo no se bloqueará (tenga en cuenta que no dije trabajo).

Lo que está sucediendo en la última línea es que ahora ha accedido más allá de la parte de memoria asignada para la stack. Como resultado, usted está indexando en una parte de la memoria que no está asignada a su proceso o está asignada de manera solo lectura. El sistema operativo ve esto y envía una falla seg al proceso.

Esta es una de las razones por las que C / C ++ es tan peligroso cuando se trata de la verificación de límites.

El segfault no es una acción prevista de su progtwig C que le diga que un índice está fuera de límites. Más bien, es una consecuencia involuntaria de un comportamiento indefinido.

En C y C ++, si declaras una matriz como

 type name[size]; 

Solo se le permite acceder a elementos con índices desde 0 hasta size-1 . Cualquier cosa fuera de ese rango causa un comportamiento indefinido. Si el índice estaba cerca del rango, lo más probable es que lea la memoria de su propio progtwig. Si el índice estuvo fuera de rango, lo más probable es que su progtwig sea destruido por el sistema operativo. Pero no puedes saber, cualquier cosa puede suceder.

¿Por qué C permite eso? Bueno, la esencia básica de C y C ++ es no proporcionar características si cuestan rendimiento. C y C ++ se han utilizado durante siglos para sistemas críticos de alto rendimiento. C se ha utilizado como lenguaje de implementación para núcleos y progtwigs donde el acceso fuera de los límites de la matriz puede ser útil para obtener un acceso rápido a los objetos que se encuentran adyacentes en la memoria. Tener el comstackdor prohibir esto sería en vano.

¿Por qué no advierte sobre eso? Bueno, puedes poner niveles de advertencia altos y esperar la misericordia del comstackdor. Esto se llama calidad de implementación (QoI). Si algún comstackdor utiliza un comportamiento abierto (como comportamiento indefinido) para hacer algo bueno, tiene una buena calidad de implementación en ese sentido.

 [js@HOST2 cpp]$ gcc -Wall -O2 main.c main.c: In function 'main': main.c:3: warning: array subscript is above array bounds [js@HOST2 cpp]$ 

Si, en cambio, formateara su disco duro al ver la matriz a la que se accede fuera de los límites, lo que sería legal, la calidad de la implementación sería bastante mala. Disfruté leer sobre eso en el documento ANSI C Rationale .

Por lo general, solo obtiene un error de segmentación si intenta acceder a la memoria que su proceso no posee.

Lo que está viendo en el caso de a[11] (y a[10] por cierto) es la memoria que posee su proceso , pero que no pertenece a la matriz a a[] . a[25000] está tan lejos de a[] , probablemente esté fuera de tu memoria por completo.

Cambiar a[11] es mucho más insidioso, ya que afecta silenciosamente a una variable diferente (o el marco de stack que puede causar un error de segmentación diferente cuando la función vuelve).

C no está haciendo esto. El subsistema de memeory virtual del sistema operativo es.

En el caso en que solo está un poco fuera de límite, se está dirigiendo a memeory que está asignado para su progtwig (en la stack de llamadas de stack en este caso). En el caso de que esté lejos de los límites, se dirige a la memoria que no se le entregó a su progtwig y el sistema operativo genera un error de segmentación.

En algunos sistemas, también existe un concepto de memoria “grabable” forzada por el sistema operativo, y es posible que intente escribir en memeory que sea suyo, pero que esté marcado como “no grabable”.

Solo para agregar lo que dicen otras personas, no puede confiar en que el progtwig simplemente falle en estos casos, no hay garantía de lo que sucederá si intenta acceder a una ubicación de memoria más allá de los “límites de la matriz”. Es lo mismo que si hicieras algo como:

 int *p; p = 135; *p = 14; 

Eso es solo al azar; esto podría funcionar Puede que no. No lo hagas Código para evitar este tipo de problemas.

Esa no es una cuestión de C es un problema del sistema operativo. Tu progtwig tiene cierto espacio de memoria y todo lo que hagas dentro de eso está bien. La falla de segmentación solo ocurre cuando accede a la memoria fuera de su espacio de proceso.

No todos los sistemas operativos tienen espacios de direcciones separados para cada proceso, en cuyo caso puede dañar el estado de otro proceso o del sistema operativo sin previo aviso.

Como se mencionó anteriormente, algunos comstackdores pueden detectar algunos accesos de matriz fuera de límites en tiempo de comstackción. Pero la comprobación de límites en tiempo de comstackción no atrapará todo:

 int a[10]; int i = some_complicated_function(); printf("%d\n", a[i]); 

Para detectar esto, se deberían usar verificaciones de tiempo de ejecución, y se evitan en C debido a su impacto en el rendimiento. Incluso con el conocimiento del tamaño de la matriz de a en tiempo de comstackción, es decir, sizeof (a), no puede proteger contra eso sin insertar una verificación de tiempo de ejecución.

Según entiendo la pregunta y los comentarios, entiendes por qué pueden pasar cosas malas cuando accedes a la memoria fuera de los límites, pero te preguntas por qué tu comstackdor en particular no te advirtió.

Los comstackdores pueden advertirle, y muchos lo hacen en los niveles de advertencia más altos. Sin embargo, el estándar está escrito para permitir que las personas ejecuten comstackdores para todo tipo de dispositivos y comstackdores con todo tipo de características, por lo que el estándar requiere lo mínimo y garantiza que las personas puedan realizar un trabajo útil.

Hay algunas veces que el estándar requiere que un cierto estilo de encoding genere un diagnóstico. Hay muchas otras ocasiones en las que el estándar no requiere un diagnóstico. Incluso cuando se requiere un diagnóstico, no conozco ningún lugar donde el estándar indique cuál debería ser la redacción exacta.

Pero no estás completamente fuera de peligro aquí. Si su comstackdor no lo advierte, Lint puede. Además, hay una serie de herramientas para detectar dichos problemas (en tiempo de ejecución) para matrices en el montón, una de las más famosas es Cerca eléctrica (o DUMA ). Pero incluso Electric Fence no garantiza que atrape todos los errores de desbordamiento.

C filosofía es siempre confiar en el progtwigdor. Y tampoco el control de límites permite que un progtwig en C se ejecute más rápido.