"버스 오류"메시지는 무엇을 의미하며 segfault와 어떻게 다릅니 까?
"버스 오류"메시지는 무엇을 의미하며 segfault와 어떻게 다릅니 까?
답변:
버스 오류는 오늘날 x86에서 드물며 프로세서가 요청한 메모리 액세스를 시도 할 수 없을 때 발생합니다.
세그먼트 결함은 프로세스에 속하지 않은 메모리에 액세스 할 때 발생하며 매우 일반적이며 다음과 같은 결과입니다.
추신 : 더 정확하게 말하면 문제를 일으킬 포인터 자체를 조작하는 것이 아니라 가리키는 메모리에 액세스하는 것입니다 (역 참조).
/var/cache
단순히 가득했습니다 askubuntu.com/a/915520/493379
static_cast
에드 void *
객체에 해당 점포 콜백 (객체 속성 한 점에있어서 다른) 파라미터. 그런 다음 콜백이 호출됩니다. 그러나 전달 된 내용은 void *
완전히 다른 것으로서 메소드 호출로 인해 버스 오류가 발생했습니다.
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.SA
와 SCTLR_EL1.SA0
, 내가 관련 문서를 요약 한 분야 추가 여기에 약간 .
응용 프로그램이 데이터 버스에서 데이터 정렬이 잘못되면 커널이 SIGBUS를 발생시킵니다. 대부분의 프로세서를위한 대부분의 현대 컴파일러가 프로그래머를위한 데이터를 패딩 / 정렬하기 때문에 요어의 정렬 문제가 (적어도) 완화되어 요즘 SIGBUS가 너무 자주 보이지 않는다고 생각합니다 (AFAIK).
부터 : 여기
어떤 이유로 코드 페이지를 페이징 할 수없는 경우 SIGBUS를 얻을 수도 있습니다.
mmap
보다 큰 파일 을 시도하면/dev/shm
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에서는 버스 오류가 발생합니다. 왜? 나는 정말로 모른다.
"foo"
읽기 전용 메모리 세그먼트에 저장되므로 쓰기가 불가능합니다. 스택 오버플로 방지가 아니라 메모리 쓰기 보호 (프로그램 자체를 다시 작성할 수있는 경우 보안 허점)입니다.
버스 오류의 한 가지 전형적인 인스턴스는 SPARC (적어도 일부 SPARC , 아마도 변경되었을 수 있음) 와 같은 특정 아키텍처에서 잘못 정렬 된 액세스를 수행하는 경우입니다. 예를 들어 :
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
이 코드 조각은 32 비트 정수 값 0xdeadf00d
을 적절하게 정렬되지 않은 주소 에 쓰려고 시도 하며 이와 관련하여 "피킹"된 아키텍처에서 버스 오류를 생성합니다. 인텔은 x86 그런데,입니다 하지 이러한 아키텍처는 (더 천천히 실행이기는하지만)에 대한 액세스를 허용합니다.
일반적으로 정렬되지 않은 액세스를 의미합니다.
물리적으로 존재하지 않는 메모리에 액세스하려고하면 버스 오류가 발생하지만 MMU가없는 프로세서와 버그가없는 OS를 사용하는 경우이 오류가 표시되지 않습니다. 프로세스의 주소 공간에 매핑 된 기존 메모리
scanf
). 그것은 OS X Mavericks가 버그가 있다는 것을 의미합니까? 버그가없는 OS의 동작은 무엇입니까?
Mac OS X에서 버스 오류가 발생한 이유는 스택에 약 1MB를 할당하려고했기 때문입니다. 이것은 하나의 스레드에서 잘 작동했지만, Mac OS X에는 비 주요 스레드의 스택 크기 가 매우 제한되어 있기 때문에 openMP를 사용할 때 버스 오류가 발생 합니다 .
위의 모든 답변에 동의합니다. BUS 오류와 관련된 2 센트는 다음과 같습니다.
프로그램 코드 내의 명령어에서 BUS 오류가 발생하지 않아도됩니다. 바이너리를 실행할 때와 실행 중에 바이너리가 수정됩니다 (빌드로 덮어 쓰기 또는 삭제 등).
이것이 맞는지 확인 :
이것이 원인인지 확인하는 간단한 방법은 동일한 바이너리의 실행중인 인스턴스를 시작하고 빌드를 실행하는 것입니다. SIGBUS
빌드가 완료되고 바이너리 (두 인스턴스가 현재 실행중인 인스턴스)를 교체 한 직후에 실행중인 두 인스턴스가 모두 오류와 함께 충돌 합니다.
기본 이유 : OS가 메모리 페이지를 스왑하고 일부 경우 바이너리가 메모리에 완전히로드되지 않을 수 있으며 OS가 동일한 바이너리에서 다음 페이지를 가져 오려고 할 때 이러한 충돌이 발생하지만 바이너리는 마지막 이후 변경되었습니다. 읽어.
blxtd가 위에서 응답 한 것을 더하기 위해, 프로세스 가 특정 'variable'의 메모리에 액세스하려고 시도 할 수없는 경우에도 버스 오류가 발생합니다 .
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
첫 번째 'for 루프' 에서 변수 'i' 의 ' 부주의 한 '사용법을 주목하십시오 . 이것이이 경우 버스 오류의 원인입니다.
방금 ARMv7 프로세서에서 최적화되지 않은 경우 세그먼테이션 오류를 발생시키는 코드를 작성할 수 있지만 -O2 (더 최적화)로 컴파일하면 버스 오류가 발생하는 어려운 방법을 발견했습니다.
우분투 64 비트에서 GCC ARM gnueabihf 크로스 컴파일러를 사용하고 있습니다.
버스 오류가 발생하는 일반적인 버퍼 오버 플로우는 다음과 같습니다.
{
char buf[255];
sprintf(buf,"%s:%s\n", ifname, message);
}
큰 따옴표 ( "")로 묶인 문자열의 크기가 buf 크기보다 크면 버스 오류가 발생합니다.