¿Qué tan peligroso es acceder a una matriz fuera de los límites?

11 minutos de lectura

avatar de usuario
CrisD

¿Qué tan peligroso es acceder a una matriz fuera de sus límites (en C)? A veces puede suceder que leo desde fuera de la matriz (ahora entiendo que luego accedo a la memoria utilizada por otras partes de mi programa o incluso más allá) o estoy tratando de establecer un valor en un índice fuera de la matriz. El programa a veces falla, pero a veces simplemente se ejecuta, dando solo resultados inesperados.

Ahora lo que me gustaría saber es, ¿qué tan peligroso es esto realmente? Si daña mi programa, no es tan malo. Si, por otro lado, rompe algo fuera de mi programa, porque de alguna manera logré acceder a una memoria totalmente ajena, entonces es muy malo, me imagino. Leí mucho ‘cualquier cosa puede pasar’, ‘la segmentación podría ser el problema menos grave’, ‘su disco duro podría volverse rosa y los unicornios podrían estar cantando debajo de su ventana’, lo cual está muy bien, pero ¿cuál es realmente el peligro?

Mis preguntas:

  1. ¿Puede la lectura de valores desde fuera de la matriz dañar algo además de mi programa? Me imagino que solo mirar las cosas no cambia nada, o ¿cambiaría, por ejemplo, el atributo ‘última vez que se abrió’ de un archivo al que accedí?
  2. ¿La configuración de valores fuera de la matriz puede dañar algo además de mi programa? De esta pregunta de desbordamiento de pila, deduzco que es posible acceder a cualquier ubicación de memoria, que no hay garantía de seguridad.
  3. Ahora ejecuto mis pequeños programas desde XCode. ¿Proporciona eso alguna protección adicional alrededor de mi programa donde no puede llegar fuera de su propia memoria? ¿Puede dañar XCode?
  4. ¿Alguna recomendación sobre cómo ejecutar mi código intrínsecamente defectuoso de forma segura?

Uso OSX 10.7, Xcode 4.6.

  • En general, el sistema operativo se protegerá a sí mismo y a otros procesos de su malversación. Sin embargo, no es algo en lo que necesariamente quieras confiar en gran medida.

    – Lame caliente

    26 de marzo de 2013 a las 20:48

  • Además, nunca “llegará a alcanzar” un archivo en su disco duro cuando acceda a un índice de matriz fuera de los límites (en su RAM).

    – Baterista B

    26 de marzo de 2013 a las 20:49


  • Creo que estás preguntando sobre la matriz C, ¿verdad? así que eso no tiene nada que ver con ObjC y realmente no se relaciona con ningún IDE.

    –Bryan Chen

    26/03/2013 a las 20:51

  • Aquí está mi ejemplo favorito de resultados extraños (se trata de la pila, pero me pareció muy esclarecedor…).

    – phipsgabler

    26 de marzo de 2013 a las 22:34

  • xkcd.com/371

    – Dan está jugando a la luz del fuego

    27 de marzo de 2013 a las 0:36

avatar de usuario
udo klein

Usted escribe:

Leí mucho de ‘cualquier cosa puede pasar’, ‘la segmentación podría ser el problema menos grave’, ‘su disco duro podría volverse rosa y los unicornios podrían estar cantando debajo de su ventana’, todo lo cual está bien, pero ¿cuál es realmente el peligro?

Pongámoslo de esa manera: carga un arma. Apúntalo fuera de la ventana sin ningún objetivo en particular y dispara. ¿Cuál es el peligro?

El tema es que no lo sabes. Si su código sobrescribe algo que bloquea su programa, está bien porque lo detendrá en un estado definido. Sin embargo, si no falla, los problemas comienzan a surgir. ¿Qué recursos están bajo el control de su programa y qué podría hacerles? Conozco al menos un problema importante que fue causado por tal desbordamiento. El problema estaba en una función de estadísticas aparentemente sin sentido que estropeó una tabla de conversión no relacionada para una base de datos de producción. El resultado fue algo muy limpieza costosa después. En realidad, hubiera sido mucho más barato y más fácil de manejar si este problema hubiera formateado los discos duros … en otras palabras: los unicornios rosas podrían ser su menor problema.

La idea de que tu sistema operativo te protegerá es optimista. Si es posible, trate de evitar escribir fuera de los límites.

  • ok, esto era exactamente lo que temía. Voy a ‘tratar de evitar escribir fuera de los límites’ pero, viendo lo que he estado haciendo en los últimos meses, seguramente lo seguiré haciendo mucho. ¿Cómo se volvieron tan buenos programando sin una forma segura de practicar?

    – ChrisD

    26/03/2013 a las 21:05


  • Quién dijo que todo era seguro 😉

    –Udo Klein

    27 de marzo de 2013 a las 6:39

  • Las prácticas de codificación seguras y protegidas deben siempre ser empleado.

    – Nik Bougalis

    26/03/2013 a las 21:05

  • Sugeriría NO usar try/catch para el código con errores a menos que detecte excepciones muy específicas y sepa cómo recuperarse de ellas. Catch (…) es lo peor que puede agregar a un código con errores.

    – Eugenio

    26/03/2013 a las 21:05


  • @NikBougalis: estoy completamente de acuerdo, pero es AÚN MÁS IMPORTANTE si el sistema operativo no incluye protección de memoria/espacios de direcciones virtuales, o falta el sistema operativo 🙂

    – toques de trompeta

    26 de marzo de 2013 a las 21:07

  • @Eugene: nunca he notado que eso sea un problema para mí, pero estoy de acuerdo contigo, ¿lo he editado? 🙂

    – toques de trompeta

    26 de marzo de 2013 a las 21:09

  • 1) ¿Quieres decir daño porque estaría revelando algo que debería haber permanecido en secreto? 2) No estoy seguro de entender lo que quiere decir, pero supongo que solo estoy accediendo a la RAM tratando de acceder a ubicaciones fuera de los límites de la matriz.

    – ChrisD

    26 de marzo de 2013 a las 21:13


No verificar los límites puede provocar efectos secundarios desagradables, incluidos agujeros de seguridad. Uno de los feos es ejecución de código arbitrario. En un ejemplo clásico: si tiene una matriz de tamaño fijo y usa strcpy() para colocar una cadena proporcionada por el usuario allí, el usuario puede proporcionarle una cadena que desborda el búfer y sobrescribe otras ubicaciones de memoria, incluida la dirección del código donde la CPU debe regresar cuando finaliza su función.

Lo que significa que su usuario puede enviarle una cadena que hará que su programa esencialmente llame exec("/bin/sh")que lo convertirá en shell, ejecutando todo lo que quiera en su sistema, incluida la recopilación de todos sus datos y convirtiendo su máquina en un nodo de botnet.

Ver Rompiendo la pila por diversión y ganancias para obtener detalles sobre cómo se puede hacer esto.

  • Sé que no debería acceder a los elementos de la matriz más allá de los límites, gracias por reforzar ese punto. Pero la pregunta es, además de hacer todo tipo de daño a mi programa, ¿puedo ir más allá de la memoria de mi programa sin darme cuenta? Y me refiero a OSX.

    – ChrisD

    27 de marzo de 2013 a las 22:47

  • @ChrisD: OS X es un sistema operativo moderno, por lo que le brindará protección de memoria completa. Por ejemplo, no debe limitarse a lo que su programa puede hacer. Esto no debería incluir meterse con otros procesos (a menos que esté ejecutando con privilegios de root).

    – Che

    28 de marzo de 2013 a las 10:53


  • Prefiero decir bajo privilegios de anillo 0, no de raíz.

    – Ruslán

    10 de julio de 2015 a las 9:20

  • Más interesante es que los compiladores hipermodernos pueden decidir que si el código intenta leer foo[0] a través de foo[len-1] después de haber utilizado previamente un cheque de len contra la longitud de la matriz para ejecutar u omitir un fragmento de código, el compilador debe sentirse libre de ejecutar ese otro código incondicionalmente incluso si la aplicación posee el almacenamiento más allá de la matriz y los efectos de leerlo habrían sido benignos, pero el efecto de invocar el otro código no lo sería.

    – Super gato

    23 de junio de 2016 a las 16:38

avatar de usuario
ricardo marrón

NSArrayA los s en Objective-C se les asigna un bloque específico de memoria. Exceder los límites de la matriz significa que estaría accediendo a una memoria que no está asignada a la matriz. Esto significa:

  1. Esta memoria puede tener cualquier valor. No hay forma de saber si los datos son válidos según su tipo de datos.
  2. Esta memoria puede contener información confidencial, como claves privadas u otras credenciales de usuario.
  3. La dirección de memoria puede no ser válida o estar protegida.
  4. La memoria puede tener un valor cambiante porque otro programa o subproceso está accediendo a ella.
  5. Otras cosas utilizan el espacio de direcciones de la memoria, como los puertos asignados a la memoria.
  6. Escribir datos en una dirección de memoria desconocida puede bloquear su programa, sobrescribir el espacio de memoria del sistema operativo y, en general, hacer que el sol implosione.

Desde el aspecto de su programa, siempre desea saber cuándo su código excede los límites de una matriz. Esto puede provocar que se devuelvan valores desconocidos, lo que provocaría que su aplicación se bloqueara o proporcionara datos no válidos.

  • Sé que no debería acceder a los elementos de la matriz más allá de los límites, gracias por reforzar ese punto. Pero la pregunta es, además de hacer todo tipo de daño a mi programa, ¿puedo ir más allá de la memoria de mi programa sin darme cuenta? Y me refiero a OSX.

    – ChrisD

    27 de marzo de 2013 a las 22:47

  • @ChrisD: OS X es un sistema operativo moderno, por lo que le brindará protección de memoria completa. Por ejemplo, no debe limitarse a lo que su programa puede hacer. Esto no debería incluir meterse con otros procesos (a menos que esté ejecutando con privilegios de root).

    – Che

    28 de marzo de 2013 a las 10:53


  • Prefiero decir bajo privilegios de anillo 0, no de raíz.

    – Ruslán

    10 de julio de 2015 a las 9:20

  • Más interesante es que los compiladores hipermodernos pueden decidir que si el código intenta leer foo[0] a través de foo[len-1] después de haber utilizado previamente un cheque de len contra la longitud de la matriz para ejecutar u omitir un fragmento de código, el compilador debe sentirse libre de ejecutar ese otro código incondicionalmente incluso si la aplicación posee el almacenamiento más allá de la matriz y los efectos de leerlo habrían sido benignos, pero el efecto de invocar el otro código no lo sería.

    – Super gato

    23 de junio de 2016 a las 16:38

avatar de usuario
Dan Haynes

Si alguna vez realiza programación a nivel de sistemas o programación de sistemas integrados, pueden suceder cosas muy malas si escribe en ubicaciones de memoria aleatorias. Los sistemas más antiguos y muchos microcontroladores usan E/S mapeada en memoria, por lo que escribir en una ubicación de memoria que se asigna a un registro periférico puede causar estragos, especialmente si se hace de forma asíncrona.

Un ejemplo es la programación de memoria flash. El modo de programación en los chips de memoria se habilita escribiendo una secuencia específica de valores en ubicaciones específicas dentro del rango de direcciones del chip. Si otro proceso escribiera en cualquier otra ubicación en el chip mientras eso sucede, causaría que el ciclo de programación fallara.

En algunos casos, el hardware ajustará las direcciones (los bits/bytes más significativos de la dirección se ignoran), por lo que escribir en una dirección más allá del final del espacio de direcciones físicas dará como resultado que los datos se escriban justo en el medio.

Y finalmente, las CPU más antiguas como la MC68000 pueden bloquearse hasta el punto de que solo un reinicio de hardware puede hacer que vuelvan a funcionar. No he trabajado en ellos durante un par de décadas, pero creo que cuando se encontró con un error de bus (memoria inexistente) al intentar manejar una excepción, simplemente se detuvo hasta que se afirmó el reinicio del hardware.

Mi mayor recomendación es un complemento descarado para un producto, pero no tengo ningún interés personal en él y no estoy afiliado a ellos de ninguna manera, pero basado en un par de décadas de programación C y sistemas integrados donde la confiabilidad era crítica, la PC de Gimpel Lint no solo detectará ese tipo de errores, sino que lo convertirá en un mejor programador de C/C++ al constantemente insistiéndote en los malos hábitos.

También recomendaría leer el estándar de codificación MISRA C, si puede obtener una copia de alguien. No he visto ninguno reciente, pero en los viejos tiempos daban una buena explicación de por qué deberías/no deberías hacer las cosas que cubren.

No sé tú, pero aproximadamente la segunda o tercera vez que recibo un volcado de memoria o un bloqueo de cualquier aplicación, mi opinión sobre la compañía que la produjo se reduce a la mitad. La 4ª o 5ª vez y lo que sea que sea el paquete se convierte en estantería y conduzco una estaca de madera a través del centro del paquete/disco en el que vino solo para asegurarme de que nunca vuelva a atormentarme.

  • Según el sistema, fuera de rango lee también pueden desencadenar un comportamiento impredecible, o pueden ser benignos, aunque el comportamiento benigno del hardware en cargas fuera de rango no implica un comportamiento benigno del compilador.

    – Super gato

    23 de junio de 2016 a las 16:28

¿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