¿Qué es una falla de segmentación?

599

¿Qué es una falla de segmentación? ¿Es diferente en C y C ++? ¿Cómo se relacionan las fallas de segmentación y los punteros colgantes?

Rajendra Uppal
fuente
95
La falla de segmentación hace que el compilador se sienta mal .
Benjamin Crouzier
22
Si ese es el caso, ¿por qué en mi caso el compilador no se quejó de nada, todo salió bien, pero en el tiempo de ejecución el sistema arroja una falla de segmentación (volcado del núcleo)? T_T
Jim Raynor
3
¡Solo un volcado de memoria cuando algo sale mal!
resultados
77
@pinouchon: Divertido, pero ¿cuándo tiene algo que ver un compilador con fallas seg? ¿No es más el entorno de tiempo de ejecución?
dhein
1
Normalmente se llama al intentar desreferenciar un puntero nulo, por lo que un error de segmentación suele ser análogo a un Java NullPointerException.
Raedwald

Respuestas:

674

La falla de segmentación es un tipo específico de error causado por el acceso a la memoria que "no le pertenece". Es un mecanismo auxiliar que evita que corrompa la memoria e introduzca errores de memoria difíciles de depurar. Cada vez que obtienes un segfault, sabes que estás haciendo algo mal con la memoria: acceder a una variable que ya se ha liberado, escribir en una parte de solo lectura de la memoria, etc. La falla de segmentación es esencialmente la misma en la mayoría de los idiomas que te permiten jugar En la gestión de memoria, no existe una diferencia de principio entre los valores predeterminados en C y C ++.

Hay muchas formas de obtener una segfault, al menos en los lenguajes de nivel inferior como C (++). Una forma común de obtener un segfault es desreferenciar un puntero nulo:

int *p = NULL;
*p = 1;

Otro segfault ocurre cuando intenta escribir en una parte de la memoria que se marcó como de solo lectura:

char *str = "Foo"; // Compiler marks the constant string as read-only
*str = 'b'; // Which means this is illegal and results in a segfault

El puntero colgante señala una cosa que ya no existe, como aquí:

char *p = NULL;
{
    char c;
    p = &c;
}
// Now p is dangling

El puntero pcuelga porque apunta a la variable de carácter cque dejó de existir después de que finalizó el bloque. Y cuando intente desreferenciar el puntero colgante (como *p='A'), probablemente obtendrá un segfault.

zoul
fuente
154
El último ejemplo es particularmente desagradable, cuando construyo: int main () {char * p = 0; {char c = 'x'; p = & c; } printf ("% c \ n", * p); devuelve 0; } Con gcc o varios otros compiladores, "parece" que funciona. No hay advertencias en la compilación. Sin segfault. Esto se debe a que el '}' fuera del alcance, en realidad no elimina los datos, solo los marca como libres para ser utilizados nuevamente. El código puede funcionar bien en un sistema de producción durante años, altera otra parte del código, cambia el compilador u otra cosa y ¡BOOOOOM!
Chris Huang-Leaver
36
Perdón por el golpe, pero solo una nota al margen ... ninguno de sus ejemplos necesariamente causa una falla predeterminada, de hecho, es solo un comportamiento indefinido ;-)
oldrinb
18
@oldrinb: Es imposible escribir código que necesariamente cause una falla por defecto. No menos importante porque hay sistemas que funcionan sin protección de memoria, por lo tanto, no se puede saber si una pieza de memoria realmente "te pertenece" y, por lo tanto , no se conocen segfaults, solo un comportamiento indefinido ... (AmigaOS clásico, por ejemplo)
DevSolar
77
@ ChrisHuang-Leaver, debe comprender que ces local, significa que se ha insertado en la pila después {y ha salido de ella después }. el puntero colgante es solo una referencia a un desplazamiento que ahora está fuera de la pila. Es por eso que modificarlo en un programa simple nunca desencadenará ningún defecto de seguridad. por otro lado, puede conducir a una falla predeterminada en un caso de uso más complejo, donde otras llamadas a funciones pueden hacer que la pila crezca y contenga los datos apuntados por el puntero colgante. escribir en esos datos (variables locales) conduciría a un comportamiento indefinido (segfault & Co)
Ayman Khamouma
3
@ ChrisHuang-Leaver, normalmente cuando se sale del alcance, el compilador tiene que recuperar algo de espacio de pila para liberar el espacio de pila no utilizado, pero esto no sucede siempre (con gcc como uno de estos compiladores). Además, el espacio de pila asignado normalmente se reutiliza nuevamente, por lo que no he oído hablar de ningún sistema operativo que devuelva páginas de pila no utilizadas al sistema, lo que hace que ese espacio SIGSEGVesté sujeto a una , por lo que no esperaré que tal señal se estropee con la pila.
Luis Colorado
111

Vale la pena señalar que la falla de segmentación no es causada por acceder directamente a otra memoria de proceso (esto es lo que escucho a veces), ya que simplemente no es posible. Con la memoria virtual, cada proceso tiene su propio espacio de dirección virtual y no hay forma de acceder a otro utilizando ningún valor de puntero. La excepción a esto puede ser bibliotecas compartidas que son el mismo espacio de direcciones físicas mapeado a (posiblemente) diferentes direcciones virtuales y memoria del núcleo, que incluso se mapea de la misma manera en cada proceso (para evitar que TLB se vacíe en syscall, creo). Y cosas como shmat;): esto es lo que cuento como acceso 'indirecto'. Sin embargo, se puede verificar que generalmente están ubicados lejos del código de proceso y que generalmente podemos acceder a ellos (es por eso que están allí,

Aún así, puede producirse un fallo de segmentación en caso de acceder a nuestra propia memoria (de proceso) de manera incorrecta (por ejemplo, al intentar escribir en un espacio no grabable). Pero la razón más común para esto es el acceso a la parte del espacio de direcciones virtual que no está asignada a la física.

Y todo esto con respecto a los sistemas de memoria virtual.

konrad.kruczynski
fuente
Con la memoria compartida / archivos mapeados de memoria es posible que otra persona se meta con su memoria. ¡En WIN32 también hay API desagradables como 'WriteProcessMemory'!
Paul
1
@paulm: Sí, lo sé. Esto es lo que tenía en mente en "Y cosas como shmat;): esto es lo que cuento como acceso 'indirecto'".
konrad.kruczynski
En un sistema operativo de memoria virtual no hay forma (normalmente, así que, por favor, los implementadores del sistema operativo, no me critiquen por esto) para que un proceso acceda a otra memoria virtual de proceso, no siendo algún tipo de llamada al sistema de conexión de memoria que le permita acceso. Las direcciones de memoria virtual normalmente significan cosas diferentes según el proceso que se esté considerando.
Luis Colorado
38

Una falla de segmentación es causada por una solicitud de una página que el proceso no ha incluido en su tabla de descriptores, o una solicitud no válida para una página que sí ha incluido (por ejemplo, una solicitud de escritura en una página de solo lectura).

Un puntero colgante es un puntero que puede o no apuntar a una página válida, pero apunta a un segmento de memoria "inesperado".

Ignacio Vazquez-Abrams
fuente
10
Esto es cierto, pero ¿realmente te ayudaría si no supieras qué es una falla de segmentación?
zoul
29

Para ser honesto, como han mencionado otros carteles, Wikipedia tiene un muy buen artículo sobre esto, así que eche un vistazo allí. Este tipo de error es muy común y a menudo se denomina otras cosas como infracción de acceso o falla de protección general.

No son diferentes en C, C ++ o cualquier otro lenguaje que permita punteros. Este tipo de errores generalmente son causados ​​por punteros que son

  1. Utilizado antes de inicializarse correctamente
  2. Se usa después de que la memoria a la que apuntan ha sido reasignada o eliminada.
  3. Se utiliza en una matriz indexada donde el índice está fuera de los límites de la matriz. En general, esto es solo cuando estás haciendo cálculos de puntero en matrices tradicionales o cadenas en C, no en colecciones basadas en STL / Boost (en C ++).
Componente 10
fuente
16

De acuerdo con wikipedia:

Se produce un error de segmentación cuando un programa intenta acceder a una ubicación de memoria a la que no está permitido acceder, o intenta acceder a una ubicación de memoria de una manera que no está permitida (por ejemplo, al intentar escribir en una ubicación de solo lectura, o para sobrescribir parte del sistema operativo).

Orhan Cinar
fuente
13

La falla de segmentación también es causada por fallas de hardware, en este caso las memorias RAM. Esta es la causa menos común, pero si no encuentra un error en su código, tal vez un memtest podría ayudarlo.

La solución en este caso, cambiar la RAM.

editar:

Aquí hay una referencia: fallo de segmentación por hardware

Alejo Bernardin
fuente
3
Una prueba rápida y sucia de RAM defectuosa es ejecutar su programa de bloqueo una y otra vez en un bucle. Si el programa no tiene un no determinismo interno, es decir, siempre produce la misma salida para la misma entrada, o al menos se supone que debe hacerlo, pero, para alguna entrada en particular, se bloquea a veces , no siempre pero no nunca: entonces debe Comience a preocuparse por la mala RAM.
zwol
8

La falla de segmentación ocurre cuando un proceso (instancia en ejecución de un programa) intenta acceder a la dirección de memoria de solo lectura o al rango de memoria que está utilizando otro proceso o accede a la dirección de memoria inexistente (no válida). El problema de la referencia colgante (puntero) significa que intentar acceder a un objeto o variable cuyo contenido ya se ha eliminado de la memoria, por ejemplo:

int *arr = new int[20];
delete arr;
cout<<arr[1];  //dangling problem occurs here
Sohail xIN3N
fuente
44
La forma correcta de eliminar una matriz es delete [] arr;
Damian
8

La página Segmentation_fault de Wikipedia tiene una muy buena descripción al respecto, solo señala las causas y razones. Echa un vistazo a la wiki para obtener una descripción detallada.

En informática, un fallo de segmentación (a menudo acortado a segfault) o una infracción de acceso es un fallo provocado por el hardware con protección de memoria, que notifica a un sistema operativo (SO) sobre una infracción de acceso a la memoria.

Las siguientes son algunas causas típicas de una falla de segmentación:

  • Anulación de la referencia a punteros NULL: esto está especialmente revestido por hardware de administración de memoria
  • Intentar acceder a una dirección de memoria inexistente (fuera del espacio de direcciones del proceso)
  • Al intentar acceder a la memoria, el programa no tiene derechos (como las estructuras del núcleo en el contexto del proceso)
  • Intentar escribir memoria de solo lectura (como segmento de código)

Estos a su vez a menudo son causados ​​por errores de programación que resultan en un acceso no válido a la memoria:

  • Desreferenciar o asignar a un puntero no inicializado (puntero comodín, que apunta a una dirección de memoria aleatoria)

  • Desreferenciar o asignar a un puntero liberado (puntero colgante, que apunta a la memoria que se ha liberado / desasignado / eliminado)

  • Un desbordamiento de búfer.

  • Un desbordamiento de pila.

  • Intentando ejecutar un programa que no se compila correctamente. (Algunos compiladores generarán un archivo ejecutable a pesar de la presencia de errores en tiempo de compilación).

Roy
fuente
6

En palabras simples: falla de segmentación es el sistema operativo que envía una señal al programa diciendo que ha detectado un acceso ilegal a la memoria y está terminando prematuramente el programa para evitar que la memoria se corrompa.

FilipeCanatto
fuente
3

"Falla de segmentación" significa que intentó acceder a la memoria a la que no tiene acceso.

El primer problema es con sus argumentos de main. La función principal debe ser int main(int argc, char *argv[]), y debe comprobar que argc es al menos 2 antes de acceder a argv [1].

Además, dado que está pasando un flotante a printf (que, por cierto, se convierte en un doble al pasar a printf), debe usar el especificador de formato% f. El especificador de formato% s es para cadenas (matrices de caracteres con terminación '\ 0').

Gusano PHP ...
fuente
2

Se produce un error de segmentación o una infracción de acceso cuando un programa intenta acceder a una ubicación de memoria que no existe, o intenta acceder a una ubicación de memoria de una manera que no está permitida.

 /* "Array out of bounds" error 
   valid indices for array foo
   are 0, 1, ... 999 */
   int foo[1000];
   for (int i = 0; i <= 1000 ; i++) 
   foo[i] = i;

Aquí i [1000] no existe, por lo que se produce una falla predeterminada.

Causas de la falla de segmentación:

it arise primarily due to errors in use of pointers for virtual memory addressing, particularly illegal access.

De-referencing NULL pointers  this is special-cased by memory management hardware.

Attempting to access a nonexistent memory address (outside processs address space).

Attempting to access memory the program does not have rights to (such as kernel structures in process context).

Attempting to write read-only memory (such as code segment).
Mohit Rohilla
fuente
2
En primer lugar, la falla seg no tiene nada que ver con que la dirección exista o no. Se trata de que está accediendo a él donde no se le permite hacerlo. Y en su ejemplo especial, incluso se garantiza por norma que esa ubicación existe. Como el estándar dice en caso de matriz, debe darse que hay una dirección válida para un puntero apuntando a una matriz bien alineada dentro de sus límites Y 1 detrás .
dhein
también se libera con la dirección, si no tiene la dirección y si intenta acceder a esta dirección, también hay seg. culpa. Y en mi ejemplo, es solo para entender el punto de vista.
Mohit Rohilla
2

Hay varias buenas explicaciones de "Fallo de segmentación" en las respuestas, pero dado que con el fallo de segmentación a menudo hay un volcado del contenido de la memoria, quería compartir dónde está la relación entre la parte "volcado de núcleo" en Fallo de segmentación (núcleo volcado) y la memoria proviene de:

Desde aproximadamente 1955 hasta 1975, antes de la memoria de semiconductores, la tecnología dominante en la memoria de la computadora utilizaba pequeñas donas magnéticas colgadas de cables de cobre. Las rosquillas se conocían como "núcleos de ferrita" y la memoria principal, así conocida como "memoria central" o "núcleo".

Tomado de aquí .

Viktor Nonov
fuente
2

Hay suficientes definiciones de falla de segmentación, me gustaría citar algunos ejemplos que encontré durante la programación, que pueden parecer errores tontos, pero perderán mucho tiempo.

  1. puede obtener una falla de segmentación en el siguiente caso, mientras que el tipo de argumento no coincide en printf

    #include<stdio.h> int main(){
    int a = 5; printf("%s",a); return 0; }

salida: Segmentation Fault (SIGSEGV)

  1. cuando olvidaste asignar memoria a un puntero, pero intentaste usarlo.

     #include<stdio.h> 
     typedef struct{
       int a;
     }myStruct;   
    int main(){
      myStruct *s;
      /* few lines of code */
      s->a = 5;
      return 0;
    }

salida: Segmentation Fault (SIGSEGV)

NPE
fuente
1

El significado simple de Segmentation faultes que está intentando acceder a alguna memoria que no le pertenece. Segmentation faultocurre cuando intentamos leer y / o escribir tareas en una ubicación de memoria de solo lectura o intentamos liberar memoria. En otras palabras, podemos explicar esto como algún tipo de corrupción de memoria.

A continuación menciono los errores comunes cometidos por los programadores que conducen a Segmentation fault.

  • Usar scanf()de manera incorrecta (olvidé poner &).
int num;
scanf("%d", num);// must use &num instead of num
  • Use punteros de manera incorrecta.
int *num; 
printf("%d",*num); //*num should be correct as num only
//Unless You can use *num but you have to point this pointer to valid memory address before accessing it.
  • Modificación de un literal de cadena (el puntero intenta escribir o modificar una memoria de solo lectura).
char *str;  

//Stored in read only part of data segment
str = "GfG";      

//Problem:  trying to modify read only memory
*(str+1) = 'n';
  • Intente llegar a través de una dirección que ya está liberada.
// allocating memory to num 
int* num = malloc(8); 
*num = 100; 

// de-allocated the space allocated to num 
free(num); 

// num is already freed there for it cause segmentation fault
*num = 110; 
  • Desbordamiento de pila: se está quedando sin memoria en la pila
  • Acceder a una matriz fuera de los límites '
  • Use especificadores de formato incorrectos cuando use printf()y scanf()'
Kalana
fuente