세그먼테이션 결함이란 무엇입니까?


598

세그먼테이션 결함이란 무엇입니까? C와 C ++에서 다른가요? 분할 오류와 매달려 포인터는 어떻게 관련되어 있습니까?


93
분할 오류로 인해 컴파일러가 기분이 나빠 집니다.
Benjamin Crouzier

22
이 경우 컴파일러가 아무 불평도하지 않은 이유는 무엇입니까?하지만 런타임에 시스템에서 세그먼테이션 오류 (코어 덤프)가 발생합니까? T_T
Jim Raynor

3
무언가 잘못되었을 때 메모리 덤프!
resultsway

7
@ pinouchon : 웃긴 일이지만 컴파일러는 언제 세그 폴트와 관련이 있습니까? 더 많은 런타임 환경이 아닙니까?
dhein

1
일반적으로 널 포인터의 역 참조를 시도하여 호출되므로 세그먼트 결함은 종종 Java와 유사합니다 NullPointerException.
Raedwald

답변:


673

세그먼트 오류는 "귀하가 아닌"메모리에 액세스하여 발생하는 특정 종류의 오류입니다. 메모리를 손상시키고 디버그하기 어려운 메모리 버그를 방지하는 도우미 메커니즘입니다. segfault를 얻을 때마다 메모리에 문제가 있음을 알 수 있습니다. 이미 해제 된 변수에 액세스하고 메모리의 읽기 전용 부분에 쓰는 것 등 메모리 관리에서 C와 C ++의 segfault 사이에는 기본 차이가 없습니다.

적어도 C (++)와 같은 저수준 언어에서 segfault를 얻는 방법에는 여러 가지가 있습니다. segfault를 얻는 일반적인 방법은 null 포인터를 역 참조하는 것입니다.

int *p = NULL;
*p = 1;

읽기 전용으로 표시된 메모리 부분에 쓰려고 할 때 또 다른 segfault가 발생합니다.

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

매달려있는 포인터는 다음과 같이 더 이상 존재하지 않는 것을 가리 킵니다.

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

포인터 가 블록이 끝난 후에 존재하지 않는 p문자 변수 c를 가리 키기 때문에 매달려 있습니다. 그리고 매달려있는 포인터 (와 같은 *p='A') 를 역 참조하려고 하면 segfault가 생길 것입니다.


154
마지막 예제는 빌드 할 때 특히 불쾌합니다. int main () {char * p = 0; {char c = 'x'; p = & c; } printf ( "% c \ n", * p); 리턴 0; } gcc 또는 다른 여러 컴파일러를 사용하면 작동하는 것으로 나타납니다. 컴파일시 경고가 없습니다. segfault가 없습니다. 범위를 벗어난 '}'은 (는) 실제로 데이터를 삭제하지 않고 다시 사용할 수있는 것으로 표시하기 때문입니다. 코드는 몇 년 동안 프로덕션 시스템에서 잘 실행될 수 있습니다. 코드의 다른 부분을 변경하고, 컴파일러 또는 다른 것을 변경하고 BOOOOOM!
Chris Huang-Leaver

36
죄송합니다 범프하지만, 단지 보조 노트에 대한 ... 당신의 예제 중 누구도 반드시 그냥 정의되지 않은 동작이 ;-)의 사실, 세그먼트 폴트를 일으키지
oldrinb

18
@oldrinb : 반드시 segfault를 일으키는 코드를 작성하는 것은 불가능합니다 . 적어도 메모리 보호없이 작동하는 시스템이 있기 때문에 메모리 조각이 실제로 "귀하의 것"인지 여부를 알 수 없으므로 segfaults를 모르고 정의되지 않은 동작 만 ... (예 : 클래식 AmigaOS)
DevSolar

7
@ ChrisHuang-Leaver, 당신 c은 그것이 로컬 이라는 것을 이해해야합니다 . 그것은 그것이 스택 후에 밀려오고 나서 {팝 아웃 되었음을 의미합니다 }. 매달려있는 포인터는 이제 스택에서 벗어난 오프셋에 대한 참조 일뿐입니다. 그래서 간단한 프로그램으로 수정해도 segfault가 발생하지 않습니다. 반면에 더 복잡한 사용 사례에서는 다른 함수 호출로 스택이 커지고 매달려있는 포인터가 가리키는 데이터가 포함될 수있는 segfault가 발생할 수 있습니다. 해당 데이터 (로컬 변수)에 쓰면 정의되지 않은 동작 (segfault & Co)이 발생합니다.
Ayman Khamouma

3
@ ChrisHuang-Leaver, 일반적으로 범위를 벗어날 때 컴파일러는 사용하지 않는 스택 공간을 확보하기 위해 일부 스택 공간을 복구해야하지만 gcc가이 컴파일러 중 하나 인 경우는 항상 발생하지 않습니다. 또한 할당 된 스택 공간은 일반적으로 다시 재사용되므로 사용하지 않는 스택 페이지를 시스템으로 반환하는 운영 체제가 없다고 들었습니다.이 공간을 대상으로 SIGSEGV하므로 스택과의 맹 글링과 같은 신호가 예상되지 않습니다.
루이스 콜로라도

111

그것은 단순히 불가능하기 때문에 다른 프로세스 메모리에 직접 액세스하여 세그먼트 화 결함이 발생하지 않는다는 점에 주목할 가치가 있습니다. 가상 메모리를 사용하면 모든 프로세스에 고유 한 가상 주소 공간이 있으며 포인터 값을 사용하여 다른 프로세스에 액세스 할 수 없습니다. 예외는 다른 가상 주소에 매핑 된 동일한 물리적 주소 공간과 모든 프로세스에서 동일한 방식으로 매핑 된 커널 메모리 인 공유 라이브러리 일 수 있습니다 (syscall에서 TLB 플러시를 피하기 위해 생각합니다). 그리고 shmat;)와 같은 것들-이것이 '간접적 인'접근으로 계산됩니다. 그러나 프로세스 코드에서 먼 거리에 있고 일반적으로 액세스 할 수 있는지 확인할 수 있습니다.

그럼에도 불구하고 (프로세스) 메모리에 부적절한 방식으로 액세스하는 경우 (예 : 쓰기 불가능한 공간에 쓰려고하는 경우) 세그먼테이션 오류가 발생할 수 있습니다. 그러나 가장 일반적인 이유는 실제 주소 공간에 전혀 맵핑되지 않은 가상 주소 공간의 일부에 대한 액세스 입니다.

그리고 가상 메모리 시스템과 관련하여이 모든 것이 가능합니다.


공유 메모리 / 메모리 매핑 파일을 사용하면 다른 사람이 메모리를 엉망으로 만들 수 있습니다. WIN32에는 'WriteProcessMemory'와 같은 불쾌한 API도 있습니다!
paulm

1
@ paulm : 예, 알고 있습니다. 이것이 바로 "그리고 shmat과 같은 것들"에서 염두에 두었던 것입니다. 이것들은 '간접적 인'접근으로 계산됩니다. "
konrad.kruczynski

가상 메모리 운영 체제에는 다른 프로세스 가상 메모리에 액세스하는 프로세스가 없습니다 (일반적으로 운영 체제 구현자가 제발 화를 내지 마십시오). 어떤 종류의 메모리 연결 시스템 호출이 아니므로 접속하다. 가상 메모리 주소는 일반적으로 고려중인 프로세스에 따라 다른 것을 의미합니다.
루이스 콜로라도

38

세그먼테이션 결함은 프로세스가 디스크립터 테이블에 나열되지 않은 페이지 요청 또는 프로세스가 나열한 페이지에 대한 유효하지 않은 요청 (예 : 읽기 전용 페이지의 쓰기 요청)으로 인해 발생합니다.

매달려있는 포인터는 유효한 페이지를 가리 키거나 가리지 않지만 "예기치 않은"메모리 세그먼트를 가리키는 포인터입니다.


10
이것은 사실이지만 세그먼테이션 오류가 무엇인지 이미 모르는 경우 실제로 도움이됩니까?
zoul

29

솔직히 말하면, 다른 포스터에서 언급했듯이 Wikipedia에는 ​​이것에 대한 훌륭한 기사 가 있으므로 살펴보십시오. 이 유형의 오류는 매우 흔하며 종종 액세스 위반 또는 일반 보호 오류와 같은 다른 것입니다.

C, C ++ 또는 포인터를 허용하는 다른 언어에서는 다르지 않습니다. 이러한 종류의 오류는 일반적으로 다음과 같은 포인터로 인해 발생합니다.

  1. 제대로 초기화되기 전에 사용
  2. 그들이 가리키는 메모리가 재 할당되거나 삭제 된 후에 사용됩니다.
  3. 인덱스가 배열 범위를 벗어난 인덱스 배열에 사용됩니다. 이것은 일반적으로 STL / Boost 기반 컬렉션 (C ++)이 아닌 기존 배열 또는 c 문자열에서 포인터 수학을 수행 할 때만 발생합니다.

16

Wikipedia에 따르면 :

프로그램이 액세스 할 수없는 메모리 위치에 액세스하려고 시도하거나 허용되지 않는 방식으로 메모리 위치에 액세스하려고하면 (예 : 읽기 전용 위치에 쓰려고 시도하거나) 운영 체제의 일부를 덮어 씁니다.


13

분할 오류 는 하드웨어 오류 (이 경우 RAM 메모리)로 인해 발생합니다. 이것은 덜 일반적인 원인이지만 코드에서 오류를 찾지 못하면 memtest가 도움이 될 수 있습니다.

이 경우 솔루션은 RAM을 변경하십시오.

편집하다:

여기에 참조가 있습니다 : 하드웨어에 의한 분할 오류


3
고장난 RAM에 대한 빠르고 더러운 테스트는 충돌 프로그램을 반복해서 반복해서 실행하는 것입니다. 프로그램에 내부 비결정론이없는 경우 (즉, 동일한 입력에 대해 항상 동일한 출력을 생성하거나, 적어도 예상해야하는 경우) , 특정 입력에 대해 항상 충돌 하지는 않지만 항상 충돌 하지는 않습니다. 나쁜 RAM에 대해 걱정하기 시작하십시오.
zwol

8

프로세스 (프로그램 인스턴스 실행)가 다른 프로세스에서 사용중인 읽기 전용 메모리 주소 또는 메모리 범위에 액세스하거나 존재하지 않는 (유효하지 않은) 메모리 주소에 액세스하려고 할 때 세그먼테이션 결함이 발생합니다. 댕글 링 참조 (포인터) 문제 는 내용이 메모리에서 이미 삭제 된 객체 또는 변수에 액세스하려고 시도하는 것을 의미합니다.

int *arr = new int[20];
delete arr;
cout<<arr[1];  //dangling problem occurs here

4
배열을 삭제하는 올바른 방법은 delete [] arr;
Damian

8

Wikipedia의 Segmentation_fault 페이지에는 그 원인과 이유를 지적하는 매우 좋은 설명이 있습니다. 자세한 설명은 위키를 살펴보십시오.

컴퓨팅에서 세그먼테이션 오류 (종종 segfault로 단축 됨) 또는 액세스 위반은 메모리 보호 기능이있는 하드웨어에서 발생하는 결함으로, 운영 체제 (OS)에 메모리 액세스 위반을 알립니다.

다음은 세그먼테이션 오류의 일반적인 원인입니다.

  • NULL 포인터 역 참조 – 메모리 관리 하드웨어에서 특수한 경우
  • 존재하지 않는 메모리 주소 액세스 시도 (외부 프로세스의 주소 공간)
  • 메모리에 액세스하려고하면 프로그램에 대한 권한이 없습니다 (예 : 프로세스 컨텍스트의 커널 구조).
  • 읽기 전용 메모리 (예 : 코드 세그먼트)를 쓰려고 시도

이는 종종 잘못된 메모리 액세스를 초래하는 프로그래밍 오류로 인해 발생합니다.

  • 초기화되지 않은 포인터 (임의의 메모리 주소를 가리키는 와일드 포인터)에 대한 참조 또는 할당

  • 해제 된 포인터 (해제 / 할당 해제 / 삭제 된 메모리를 가리키는 매달려 포인터)에 대한 참조 해제 또는 할당

  • 버퍼 오버 플로우.

  • 스택 오버플로

  • 올바르게 컴파일되지 않은 프로그램을 실행하려고합니다. (컴파일 타임 오류가 존재하더라도 일부 컴파일러는 실행 파일을 출력합니다.)


6

간단히 말해 : 세그먼테이션 오류는 운영 체제가 프로그램에 잘못된 메모리 액세스를 감지했으며 메모리가 손상되지 않도록 프로그램을 조기 종료한다는 신호를 프로그램에 보내는 것입니다.


3

"세그먼트 결함"은 액세스 할 수없는 메모리에 액세스하려고 시도했음을 의미합니다.

첫 번째 문제는 main의 주장에 관한 것입니다. 주요 기능은이어야하며 int main(int argc, char *argv[])argv [1]에 액세스하기 전에 argc가 2 이상인지 확인해야합니다.

또한 float를 printf로 전달하므로 printf로 전달할 때 double로 변환되므로 % f 형식 지정자를 사용해야합니다. % s 형식 지정자는 문자열 용입니다 ( '\ 0'- 종료 문자 배열).


2

프로그램이 존재하지 않는 메모리 위치에 액세스하려고 시도하거나 허용되지 않는 방식으로 메모리 위치에 액세스하려고하면 세그먼트 화 결함 또는 액세스 위반이 발생합니다.

 /* "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;

세그먼트 폴트가 발생되도록 여기에 [1000]이 존재하지.

세그먼테이션 결함의 원인 :

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).

2
우선, 세그 폴트는 주소와 관련이 있거나 존재하지 않습니다. 액세스가 허용되지 않은 곳에 액세스하는 것입니다. 그리고 당신의 특별한 예에서, 그 위치가 존재한다는 것이 표준에 의해 보장됩니다. 표준에 따르면 배열의 경우 범위 내에서 잘 정렬 된 배열의 포인터 포인트에 유효한 주소가 있고 뒤에 1 이 있어야합니다 .
dhein

주소가 없으면 주소와 관련이 있으며이 주소에 액세스하려고하면 세그가 있습니다. 결점. 그리고 나의 예에서, 그것은 단지 관점을 이해하기위한 것입니다.
Mohit Rohilla

2

사이의 관계에 참여하는 "핵심 덤프"여기서 답변에서 "분할 오류"여러 좋은의 설명이 있습니다 만, 세그먼트 오류와 이후 종종 메모리 내용의 덤프있어, 내가 공유하기를 원해요 분할 오류 (코어 덤프) 및 메모리는 다음과 같습니다.

약 1955 년부터 1975 년까지-반도체 메모리 이전-컴퓨터 메모리의 지배적 인 기술은 구리선에 작은 자성 도넛을 사용했습니다. 도넛은 "페라이트 코어"로 알려져 있으며 메인 메모리는 "코어 메모리"또는 "코어"로 알려져 있습니다.

여기 에서 찍은 .


2

세그먼트 오류의 충분한 정의가있다, 나는 어리석은 실수를 보일 수 있지만 많은 시간을 낭비 프로그래밍시, 건너 온 몇 가지 예를 인용하고 싶습니다.

  1. printf에서 argumet 유형이 일치하지 않으면 아래의 경우 세그먼테이션 오류가 발생할 수 있습니다.

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

출력 : Segmentation Fault (SIGSEGV)

  1. 포인터에 메모리를 할당하는 것을 잊었지만 사용하려고 할 때.

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

출력 : Segmentation Fault (SIGSEGV)


1

단순한 의미 Segmentation fault는 귀하가 소유하지 않은 일부 메모리에 액세스하려고한다는 것입니다. Segmentation fault읽기 전용 메모리 위치에서 작업을 읽거나 쓰려고 시도하거나 메모리를 비우려고 할 때 발생합니다. 다시 말해, 이것을 일종의 메모리 손상으로 설명 할 수 있습니다.

아래에서는 프로그래머가 저지른 일반적인 실수에 대해 언급합니다 Segmentation fault.

  • scanf()잘못된 방법으로 사용하십시오 (넣는 것을 잊었습니다 &).
int num;
scanf("%d", num);// must use &num instead of num
  • 잘못된 방법으로 포인터를 사용하십시오.
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.
  • 문자열 리터럴 수정 (포인터는 읽기 전용 메모리를 쓰거나 수정하려고 시도합니다.)
char *str;  

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

//Problem:  trying to modify read only memory
*(str+1) = 'n';
  • 이미 해제 된 주소를 통해 연락하십시오.
// 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; 
  • 스택 오버플로-: 스택의 메모리 부족
  • 범위를 벗어난 배열에 액세스
  • printf()scanf()'을 사용할 때 잘못된 형식 지정자를 사용하십시오.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.