code

버스 오류 대 세그먼트화 오류

starcafe 2023. 6. 22. 22:05
반응형

버스 오류 대 세그먼트화 오류

버스 오류와 분할 오류의 차이점은 무엇입니까?프로그램이 세그먼트 오류를 발생시키고 처음으로 정지하고 두 번째로 버스 오류를 발생시키고 종료할 수 있는 경우가 있습니까?

제가 사용한 대부분의 아키텍처의 차이점은 다음과 같습니다.

  • SEGV는 사용자가 의도하지 않은 메모리(예: 주소 공간 외부)에 액세스할 때 발생합니다.
  • SIGBUS는 CPU와의 정렬 문제로 인해 발생합니다(예: 4의 배수가 아닌 주소에서 길게 읽으려고 시도).

SIGBUS또한 파일을 사용하여 파일 끝을 지나 매핑된 버퍼의 일부에 액세스하려고 할 경우와 공간 부족과 같은 오류 조건이 발생합니다.를 사용하여 신호 처리기를 등록하고 다음을 설정하는 경우SA_SIGINFO프로그램에서 결함이 있는 메모리 주소를 검사하고 메모리 매핑 파일 오류만 처리하도록 할 수 있습니다.

예를 들어 프로그램이 하드웨어 버스가 지원하지 않는 작업을 수행하려고 할 때 버스 오류가 발생할 수 있습니다.예를 들어 SPARC에서는 홀수 주소에서 멀티바이트 값(int, 32비트 등)을 읽으려고 하면 버스 오류가 발생했습니다.

예를 들어, 세그먼트화 규칙을 위반하는 액세스를 수행하는 경우, 즉 소유하지 않은 메모리를 읽거나 쓰려고 할 때 세그먼트화 오류가 발생합니다.

질문을 "간헐적으로 SIGSEGV 또는 SIGBUS를 받고 있는데 왜 일관성이 없습니까?"라는 의미로 해석하는 것은 C 또는 C++ 표준에 의해 세그먼트 결함이 발생하도록 보장되지 않는다는 것에 주목할 필요가 있습니다. 단지 "정의되지 않은 행동"일 뿐입니다.교수로서 제가 말한 것은 그것이 대신 악어가 바닥판에서 나와 당신을 잡아먹게 할 수도 있다는 것을 의미합니다.

따라서 두 가지 버그가 있을 수 있습니다. 첫 번째 버그는 때때로 SIGSEGV를 유발하고 두 번째 버그는 SIGBUS를 유발합니다. (세그폴트가 발생하지 않고 프로그램이 아직 실행 중인 경우).

디버거를 사용하고 악어를 조심하는 것을 추천합니다.

당신이 말하고 있는 것 같습니다.SIGSEGV그리고.SIGBUSPosix에 의해 정의된 신호.

SIGSEGV프로그램이 잘못된 주소를 참조할 때 발생합니다. SIGBUS는 구현 정의 하드웨어 결함입니다.이 두 신호의 기본 동작은 프로그램을 종료하는 것입니다.

그 프로그램은 이러한 신호를 잡을 수 있고 심지어 무시할 수도 있습니다.

프로그램이 세그먼트 오류를 발생시키고 처음으로 정지하며 두 번째로 버스 오류를 발생시키고 종료할 수 있습니까?

버그인 경우에도 마찬가지입니다. 예: 밖의 에 의해 분할 SIGSEGV 오류(SIGBUS)를 모두할 수 한 예입니다.다음은 결정론적인 방법으로 어레이의 경계 밖에 있는 인덱스에 의해 분할 오류(SIGSEGV)와 버스 오류(SIGBUS) 모두를 생성할 수 있는 macOS의 심각하지만 단순한 예입니다.되지 않은 않습니다. (이디버거 .)lldb나의 경우!)

bus_svv.c:

#include <stdlib.h>

char array[10];

int main(int argc, char *argv[]) {
    return array[atol(argv[1])];
}

예제에서는 배열의 인덱스 역할을 하는 명령줄에서 정수를 가져옵니다.에는 신호를 발생시키지 않는 일부 인덱스 값(배열 외부에서도)이 있습니다. (모든 값은 표준 세그먼트/섹션 크기에 따라 달라집니다.)clang-902.0.39.1을 사용하여 2.60GHz의 High Sierra macOS 10.13.5, i5-4288U CPU에서 바이너리를 생성했습니다.)

77791보다 높고 -4128보다 낮으면 분할 결함(SIGSEGV)이 발생합니다.24544는 버스 오류(SIGBUS)를 발생시킵니다.전체 지도는 다음과 같습니다.

$ ./bus_segv -4129
Segmentation fault: 11
$ ./bus_segv -4128
...
$ ./bus_segv 24543
$ ./bus_segv 24544
Bus error: 10
...
$ ./bus_segv 28639
Bus error: 10
$ ./bus_segv 28640
...
$ ./bus_segv 45023
$ ./bus_segv 45024
Bus error: 10
...
$ ./bus_segv 53215
Bus error: 10
$ ./bus_segv 53216
...
$ ./bus_segv 69599
$ ./bus_segv 69600
Bus error: 10
...
$ ./bus_segv 73695
Bus error: 10
$ ./bus_segv 73696
...
$ ./bus_segv 77791
$ ./bus_segv 77792
Segmentation fault: 11

분해된 코드를 보면 버스 오류가 있는 범위의 경계가 인덱스가 표시하는 것만큼 홀수가 아니라는 것을 알 수 있습니다.

otool -tv버스_tvv

bus_segv:
(__TEXT,__text) section
_main:
0000000100000f60    pushq   %rbp
0000000100000f61    movq    %rsp, %rbp
0000000100000f64    subq    $0x10, %rsp
0000000100000f68    movl    $0x0, -0x4(%rbp)
0000000100000f6f    movl    %edi, -0x8(%rbp)
0000000100000f72    movq    %rsi, -0x10(%rbp)
0000000100000f76    movq    -0x10(%rbp), %rsi
0000000100000f7a    movq    0x8(%rsi), %rdi
0000000100000f7e    callq   0x100000f94 ## symbol stub for: _atol
0000000100000f83    leaq    0x96(%rip), %rsi
0000000100000f8a    movsbl  (%rsi,%rax), %eax
0000000100000f8e    addq    $0x10, %rsp
0000000100000f92    popq    %rbp    
0000000100000f93    retq    

타고leaq 0x96(%rip), %rsi어레이의 주소rsi 어레시주소의작주의 (PC 상로결정된됩다니가)의으로 결정된).

rsi = 0x100000f8a + 0x96 = 0x100001020
rsi - 4128 = 0x100000000 (below segmentation fault)
rsi + 24544 = 0x100007000 (here and above bus error)
rsi + 28640 = 0x100008000 (below bus error)
rsi + 45024 = 0x10000c000 (here and above bus error)
rsi + 53216 = 0x10000e000 (below bus error)
rsi + 69600 = 0x100012000 (here and above bus error)
rsi + 73696 = 0x100013000 (below bus error)
rsi + 77792 = 0x100014000 (here and above segmentation fault)

lldb페이지 제한이 다른 프로세스를 설정할 수 있습니다.디버그 세션에서 버스 오류를 재현할 수 없습니다.따라서 디버거는 버스 오류 스핏 바이너리에 대한 해결 방법일 수 있습니다.

안드레아스

이것은 버스 오류가 무엇입니까? 만약 그것이 없었다면.

프로그램이 세그먼트 오류를 발생시키고 처음으로 정지하고 두 번째로 버스 오류를 발생시키고 종료할 수 있는 경우가 있습니까?

문제의 일부여기에 있는 정보를 사용하여 직접 답변할 수 있습니다.


광기: 같은 일을 반복하고 다른 결과를 기대하는 것.
알베르트 아인슈타인


물론, 질문을 문자 그대로 받아들이는 것은...

#include <signal.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int main() {
    srand(time(NULL));
    if (rand() % 2)
        kill(getpid(), SIGBUS);
    else
        kill(getpid(), SIGSEGV);
    return 0;
}

Tada, 한 번 실행 시 분할 오류로 종료하고 다른 실행 시 버스 오류로 종료할 수 있는 프로그램입니다.

언급URL : https://stackoverflow.com/questions/838540/bus-error-vs-segmentation-fault

반응형