programing

버스 오류란 무엇입니까?세그멘테이션 장애와 다른가요?

goodcopy 2022. 7. 5. 23:09
반응형

버스 오류란 무엇입니까?세그멘테이션 장애와 다른가요?

"버스 오류" 메시지는 무엇을 의미하며 분할 장애와 어떻게 다릅니까?

버스 오류는 현재 x86에서 거의 발생하지 않고 프로세서가 요청된 메모리 액세스를 시도할 수 없을 때 발생합니다.일반적으로 다음과 같습니다.

  • 프로세서 명령과 그 얼라인먼트 요건을 충족하지 않는 주소를 사용합니다.

분할 장애는 프로세스에 속하지 않는 메모리에 액세스할 때 발생합니다.이러한 현상은 매우 일반적이며 일반적으로 다음과 같은 결과로 발생합니다.

  • 포인터를 사용하여 할당 해제된 무언가로 이동합니다.
  • 초기화되지 않은 가짜 포인터를 사용합니다.
  • null 포인터를 사용합니다.
  • 버퍼 오버플로우

PS: 좀 더 정확하게 말하면, 문제의 원인이 되는 것은 포인터 자체를 조작하는 것이 아닙니다.가리키는 메모리(디레퍼런스)에 액세스 하고 있습니다.

segfault는 사용자가 액세스할 수 없는 메모리에 액세스하는 것입니다.읽기 전용이고 허가도 없고...

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

mmap 7 'POSIX 7'

error"는이 "Bus error"를 전송할 때 합니다.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

Ubuntu 14.04로 테스트 완료.

POSIX 설명 SIGBUS같이요.

메모리 개체의 정의되지 않은 부분에 대한 액세스입니다.

mmap 사양은 다음과 같습니다.

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

★★★★★★★★★★★★★★★★★.shm_open 는 사이즈가 0인 오브젝트를 생성한다고 합니다.

공유 메모리 개체의 크기가 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, Linux 커널 4.15.0에서 ThunderX2 서버 머신의 SIGBUS를 올립니다.

유감스럽게도 QEMU v4.0.0 사용자 모드에서는 재현할 수 없습니다.이유는 잘 모르겠습니다.

장애는 이며 이 장애에 의해 되는 것으로 .SCTLR_ELx.SA ★★★★★★★★★★★★★★★★★」SCTLR_EL1.SA0관련 문서를 여기에 조금 더 요약해 두었습니다.

위의 모든 답변에 동의합니다.다음은 BUS 오류에 대한 2센트입니다.

BUS 에러는, 프로그램 코드의 지시에 의해서 발생하는 것은 아닙니다.이 문제는 바이너리를 실행하고 실행 중에 바이너리가 수정(빌드에 의해 덮어쓰기 또는 삭제됨 등)될 때 발생할 수 있습니다.

이 경우 확인

간단한 방식으로 이 원인을 확인하고 후에 시작한 빌드를 같은 바이너리 양식의 인스턴스가build 출력 디렉터리의 커플을 시작하여 있다.이것이 원인인지 여부를 확인하는 간단한 방법은 빌드 출력 디렉토리에서 동일한 바이너리의 인스턴스를 몇 개 시작하고,실행하는 것입니다 빌드를시작한 후.둘 다 운동 인스턴스인스턴스가 크래시하여 둔 실행 중인으로 추락할 것이다.SIGBUS오류 후에 이 체격과 2진(는 인스턴스 both가 현재 실행 중인)를 끝냈다.빌드가 완료되고 바이너리(두 인스턴스가 현재 실행 중인 바이너리)가 교체된 직후에 오류가 발생했습니다.

근본적인 이유

이는 OS가 메모리 페이지를 스왑하고 경우에 따라서는 바이너리가 메모리에 완전히 로드되지 않을 수 있기 때문입니다.이러한 크래시는 OS가 같은 바이너리에서 다음 페이지를 가져오려고 할 때 발생합니다만, 바이너리가 마지막으로 읽힌 이후 변경되었습니다.

POSIX 시스템에서는 어떤 이유로 코드 페이지를 호출할 수 없는 경우에도 SIGBUS 신호를 수신할 수 있습니다.

루트 디렉토리가 100%일 때 버스 오류가 발생했습니다.

버스 에러의 전형적인 예는 SPARC(적어도 일부 SPARC가 변경되었을 가능성이 있다)와 같은 특정 아키텍처에서 잘못 정렬된 액세스를 하는 경우입니다.예:

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

이 무리 이 32비트 정수값을 쓰려고 합니다 스니펫은 32비트 정수 값 쓰려고 노력한다.0xdeadf00d(대부분의 경우) 올바르게 정렬되지 않은 주소로 전송되며, 이와 관련하여 "확실한" 아키텍처에서 버스 오류가 발생합니다.참고로 인텔 x86은 그런 아키텍처가 아닙니다.이것에 의해, 액세스가 허가됩니다(단, 실행은 더 느리지만).

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처음과 첫번째 argument(그리고 fine 일하는 주장 뒤집어 보겠습니다.)을 변경하여 두번째 인자 추가합니다.는 첫 번째 인수를 변경하여두 번째 인수를 첫 번째 인수에 추가합니다(인수가 변경되면 정상적으로 동작합니다).linux에 있지만, OSX에서 버스 오류가 발생한다. 왜 분할 fault(예상대로)을 줍니까?리눅스 에서는 세그멘테이션 폴트(예상대로)가 표시되지만 OSX에서는버스 에러가 표시됩니다.왜일까요?나는 정말 모른다.난 정말 몰라.

먼저 SIGBUS와 SIGSEGV는 특정 유형의 오류가 아니라 오류 그룹 또는 패밀리입니다.따라서 일반적으로 신호 번호(si_no)와 신호 코드(si_code)가 표시됩니다.

또, OS와 아키텍처에 의해서도, 원인이 되는 것이 무엇인지에 따라서도 다릅니다.

일반적으로 그렇게 말할 수 있다.SIGSEGV는 메모리 매핑(권한, 매핑 없음) 즉 mmu 오류와 관련되어 있습니다.

SIGBUS는 메모리 매핑이 성공하여 기본 메모리 시스템에서 문제가 발생한 경우(메모리 부족, 해당 위치에 메모리가 없음, 정렬, smu로 인해 액세스가 차단됨 등), 즉 버스 오류입니다.

SIGBUS는 시스템에서 파일이 사라졌을 때(리무버블 미디어에서 파일을 mmap하고 분리한 경우) mmap된 파일과 함께 있을 수도 있습니다.

siginfo.h 헤더는 플랫폼의 siginfo.h 헤더를 참조하는 것이 좋습니다.예를 들어 Linux의 경우 이 페이지에서는 개요를 설명합니다.https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/siginfo.h#L245

/*
 * SIGSEGV si_codes
 */
#define SEGV_MAPERR 1   /* address not mapped to object */
#define SEGV_ACCERR 2   /* invalid permissions for mapped object */
#define SEGV_BNDERR 3   /* failed address bound checks */
#ifdef __ia64__
# define __SEGV_PSTKOVF 4   /* paragraph stack overflow */
#else
# define SEGV_PKUERR    4   /* failed protection key checks */
#endif
#define SEGV_ACCADI 5   /* ADI not enabled for mapped object */
#define SEGV_ADIDERR    6   /* Disrupting MCD error */
#define SEGV_ADIPERR    7   /* Precise MCD exception */
#define SEGV_MTEAERR    8   /* Asynchronous ARM MTE error */
#define SEGV_MTESERR    9   /* Synchronous ARM MTE exception */
#define NSIGSEGV    9

/*
 * SIGBUS si_codes
 */
#define BUS_ADRALN  1   /* invalid address alignment */
#define BUS_ADRERR  2   /* non-existent physical address */
#define BUS_OBJERR  3   /* object specific hardware error */
/* hardware memory error consumed on a machine check: action required */
#define BUS_MCEERR_AR   4
/* hardware memory error detected in process but not consumed: action optional*/
#define BUS_MCEERR_AO   5
#define NSIGBUS     5

마지막으로 모든 신호는 사용자가 생성할 수도 있습니다(예: 킬).사용자가 생성한 경우 si_code는 SI_USER입니다.그래서 특별한 소스는 음의 si_code를 얻습니다.

/*
 * si_code values
 * Digital reserves positive values for kernel-generated signals.
 */
#define SI_USER     0       /* sent by kill, sigsend, raise */
#define SI_KERNEL   0x80        /* sent by the kernel from somewhere */
#define SI_QUEUE    -1      /* sent by sigqueue */
#define SI_TIMER    -2      /* sent by timer expiration */
#define SI_MESGQ    -3      /* sent by real time mesq state change */
#define SI_ASYNCIO  -4      /* sent by AIO completion */
#define SI_SIGIO    -5      /* sent by queued SIGIO */
#define SI_TKILL    -6      /* sent by tkill system call */
#define SI_DETHREAD -7      /* sent by execve() killing subsidiary threads */
#define SI_ASYNCNL  -60     /* sent by glibc async name lookup completion */

#define SI_FROMUSER(siptr)  ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr)    ((siptr)->si_code > 0)

나는 애플리케이션이 데이터 버스에 데이터 정렬 불량을 나타낼 때 커널이 SIGBUS를 발생시킨다고 믿는다.대부분의 프로세서용 최신 컴파일러는 프로그래머용 데이터를 패딩/얼라인하기 때문에 (적어도) 예전(적어도)의 얼라인먼트 문제가 완화되어 최근에는 SIGBUS를 자주 볼 수 없다고 생각합니다(AFAIK).

송신원: 여기

OS, CPU, 컴파일러 및 기타 요인에 따라 달라집니다.

일반적으로 이는 CPU 버스가 명령을 완료할 수 없거나 충돌이 발생했음을 의미하지만 실행 중인 환경과 코드에 따라 모든 범위의 문제를 의미할 수 있습니다.

blxtd가 위에서 응답한 내용에 더해 프로세스에서 특정 '변수'의 메모리에 액세스할 수 없는 경우에도 버스 오류가 발생합니다.

for (j = 0; i < n; j++) {
    for (i =0; i < m; i++) {
        a[n+1][j] += a[i][j];
    }
}

번째 'for loop'에서 변수 'i'의 'inadvert' 사용법에 주목하십시오.이것이 이 경우 버스 에러의 원인입니다.

일반적으로는 비정렬 액세스를 의미합니다.

물리적으로 존재하지 않는 메모리에 액세스하려고 하면 버스 에러가 발생하지만, MMU를 탑재한 프로세서와 버그가 없는 OS를 사용하고 있는 경우, 프로세스의 주소 공간에 매핑된 존재하지 않는 메모리가 없기 때문에, 이 에러는 표시되지 않습니다.

Mac OS X에서 버스 오류가 발생한 이유는 스택에 약 1Mb를 할당하려고 했기 때문입니다.이것은 하나의 스레드에서 잘 작동했지만, Mac OS X는 메인 스레드가 아닌 경우 스택 크기가 매우 제한적이기 때문에 openMP를 사용하면 이 드라이브가 버스 오류로 연결됩니다.

ARMv7 프로세서에서 최적화되지 않은 경우 분할 오류를 발생시키는 코드를 쓸 수 있지만 -O2(더 최적화)로 컴파일하면 버스 오류가 발생한다는 것을 알게 되었습니다.

Ubuntu 64비트의 GCC ARM gnueabihf 크로스 컴파일러를 사용하고 있습니다.

저는 실수로 어셈블리가 원래대로 돌아간다고 선언하지 않고 "버스 오류"를 트리거했습니다..text부분.당연한 것처럼 보일지 모르지만 나는 한동안 당황했다.

예.

.globl _myGlobal # Allocate a 64-bit global with the value 2
.data
.align 3
_myGlobal:
.quad 2
.globl _main # Main function code
_main:
push %rbp

데이터에서 코드로 돌아갈 때 텍스트 지시문이 누락되었습니다.

_myGlobal:
.quad 2
.text # <- This
.globl _main
_main:

이게 누군가에게 도움이 되길 바란다.

주목할 만한 원인 중 하나는 /dev/mem 영역을 mmap하려고 하면 SIGBUS가 반환되는 것입니다.

버스 오류를 일으키는 일반적인 버퍼 오버플로는 다음과 같습니다.

{
    char buf[255];
    sprintf(buf,"%s:%s\n", ifname, message);
}

여기서 큰따옴표("") 안의 문자열 크기가 buf 크기보다 크면 버스 오류가 발생합니다.

언급URL : https://stackoverflow.com/questions/212466/what-is-a-bus-error-is-it-different-from-a-segmentation-fault

반응형