[c] 버스 오류는 무엇입니까?

“버스 오류”메시지는 무엇을 의미하며 segfault와 어떻게 다릅니 까?



답변

버스 오류는 오늘날 x86에서 드물며 프로세서가 요청한 메모리 액세스를 시도 할 수 없을 때 발생합니다.

  • 정렬 요구 사항을 충족하지 않는 주소로 프로세서 명령어 사용

세그먼트 결함은 프로세스에 속하지 않은 메모리에 액세스 할 때 발생하며 매우 일반적이며 다음과 같은 결과입니다.

  • 할당 해제 된 무언가에 대한 포인터 사용.
  • 초기화되지 않은 가짜 포인터를 사용합니다.
  • 널 포인터 사용.
  • 버퍼 넘침.

추신 : 더 정확하게 말하면 문제를 일으킬 포인터 자체를 조작하는 것이 아니라 가리키는 메모리에 액세스하는 것입니다 (역 참조).


답변

segfault가 액세스가 허용되지 않은 메모리에 액세스하고 있습니다. 읽기 전용이며 권한이 없습니다.

버스 오류가있을 수없는 메모리에 액세스하려고합니다. 시스템에 무의미한 주소를 사용했거나 해당 작업에 잘못된 종류의 주소를 사용했습니다.


답변

mmap 최소 POSIX 7 예

커널 SIGBUS이 프로세스로 전송할 때 “버스 오류”가 발생 합니다.

ftruncate잊혀져 서 생성하는 최소한의 예 :

#include <fcntl.h> /* O_ constants */
#include <unistd.h> /* ftruncate */
#include <sys/mman.h> /* mmap */

int main() {
    int fd;
    int *map;
    int size = sizeof(int);
    char *name = "/a";

    shm_unlink(name);
    fd = shm_open(name, O_RDWR | O_CREAT, (mode_t)0600);
    /* THIS is the cause of the problem. */
    /*ftruncate(fd, size);*/
    map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    /* This is what generates the SIGBUS. */
    *map = 0;
}

로 실행 :

gcc -std=c99 main.c -lrt
./a.out

우분투 14.04에서 테스트되었습니다.

POSIX 는 다음 SIGBUS같이 설명 합니다.

메모리 객체의 정의되지 않은 부분에 액세스

의 mmap 사양은 말한다 :

pa에서 시작하여 객체의 끝 이후에 전체 페이지에 대해 len 바이트 동안 계속되는 주소 범위 내의 참조는 SIGBUS 신호를 전달해야합니다.

그리고 크기가 0 인 객체를 생성 shm_open 한다고 말합니다 .

공유 메모리 객체의 크기는 0입니다.

따라서 *map = 0할당 된 객체의 끝을지나갑니다.

ARMv8 aarch64에서 정렬되지 않은 스택 메모리 액세스

: 이것은에서 언급 한 버스 오류가 무엇입니까? SPARC의 경우보다 재현 가능한 예를 제공합니다.

필요한 것은 독립형 aarch64 프로그램입니다.

.global _start
_start:
asm_main_after_prologue:
    /* misalign the stack out of 16-bit boundary */
    add sp, sp, #-4
    /* access the stack */
    ldr w0, [sp]

    /* exit syscall in case SIGBUS does not happen */
    mov x0, 0
    mov x8, 93
    svc 0

그런 다음이 프로그램은 Ubuntu 18.04 aarch64, ThunderX2 서버 시스템의 Linux 커널 4.15.0에서 SIGBUS를 발생 시킵니다 .

불행히도, QEMU v4.0.0 사용자 모드에서는 재현 할 수 없습니다. 이유가 확실하지 않습니다.

장애는에 의해 선택 및 제어 것으로 보인다 SCTLR_ELx.SASCTLR_EL1.SA0, 내가 관련 문서를 요약 한 분야 추가 여기에 약간 .


답변

응용 프로그램이 데이터 버스에서 데이터 정렬이 잘못되면 커널이 SIGBUS를 발생시킵니다. 대부분의 프로세서를위한 대부분의 현대 컴파일러가 프로그래머를위한 데이터를 패딩 / 정렬하기 때문에 요어의 정렬 문제가 (적어도) 완화되어 요즘 SIGBUS가 너무 자주 보이지 않는다고 생각합니다 (AFAIK).

부터 : 여기


답변

어떤 이유로 코드 페이지를 페이징 할 수없는 경우 SIGBUS를 얻을 수도 있습니다.


답변

OS X에서 C를 프로그래밍하는 동안 방금 발생한 버스 오류의 특정 예 :

#include <string.h>
#include <stdio.h>

int main(void)
{
    char buffer[120];
    fgets(buffer, sizeof buffer, stdin);
    strcat("foo", buffer);
    return 0;
}

문서가 기억 나지 않는 경우 strcat첫 번째 인수를 변경하여 두 번째 인수를 첫 번째 인수에 추가합니다 (인수를 넘기면 제대로 작동합니다). 리눅스에서는 예상대로 세그먼테이션 오류가 발생하지만 OS X에서는 버스 오류가 발생합니다. 왜? 나는 정말로 모른다.


답변

버스 오류의 한 가지 전형적인 인스턴스는 SPARC (적어도 일부 SPARC , 아마도 변경되었을 수 있음) 와 같은 특정 아키텍처에서 잘못 정렬 된 액세스를 수행하는 경우입니다. 예를 들어 :

unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;

이 코드 조각은 32 비트 정수 값 0xdeadf00d을 적절하게 정렬되지 않은 주소 에 쓰려고 시도 하며 이와 관련하여 “피킹”된 아키텍처에서 버스 오류를 생성합니다. 인텔은 x86 그런데,입니다 하지 이러한 아키텍처는 (더 천천히 실행이기는하지만)에 대한 액세스를 허용합니다.