ข้อความ "ข้อผิดพลาดของบัส" หมายความว่าอย่างไรและแตกต่างจาก segfault อย่างไร
ข้อความ "ข้อผิดพลาดของบัส" หมายความว่าอย่างไรและแตกต่างจาก segfault อย่างไร
คำตอบ:
ข้อผิดพลาดของบัสหายากในปัจจุบันใน x86 และเกิดขึ้นเมื่อโปรเซสเซอร์ของคุณไม่สามารถแม้แต่จะพยายามเข้าถึงหน่วยความจำที่ร้องขอโดยทั่วไปแล้ว:
ความผิดพลาดในการแบ่งกลุ่มเกิดขึ้นเมื่อเข้าถึงหน่วยความจำที่ไม่ได้อยู่ในกระบวนการของคุณซึ่งเป็นเรื่องปกติมากและมักเป็นผลมาจาก:
PS: เพื่อให้มีความแม่นยำมากขึ้นนี้ไม่ได้จัดการตัวชี้ที่จะทำให้เกิดปัญหาก็คือการเข้าถึงหน่วยความจำที่ชี้ไปที่ (dereferencing)
/var/cache
เพียงเต็มaskubuntu.com/a/915520/493379
static_cast
แก้ไขvoid *
พารามิเตอร์ให้กับวัตถุที่เก็บการโทรกลับ (หนึ่งคุณลักษณะชี้ไปที่วัตถุและอื่น ๆ ที่วิธีการ) จากนั้นโทรกลับถูกเรียก อย่างไรก็ตามสิ่งที่ผ่านเป็นvoid *
สิ่งที่แตกต่างกันอย่างสมบูรณ์และทำให้การเรียกวิธีการทำให้เกิดข้อผิดพลาดรถบัส
segfault กำลังเข้าถึงหน่วยความจำที่คุณไม่ได้รับอนุญาตให้เข้าถึง มันเป็นแบบอ่านอย่างเดียวคุณไม่ได้รับอนุญาต ฯลฯ ...
ข้อผิดพลาดของบัสกำลังพยายามเข้าถึงหน่วยความจำที่ไม่สามารถอยู่ได้ คุณใช้ที่อยู่ที่ไม่มีความหมายต่อระบบหรือที่อยู่ผิดประเภทสำหรับการดำเนินการนั้น
mmap
ตัวอย่าง POSIX ที่น้อยที่สุด 7
"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:
วัตถุหน่วยความจำที่ใช้ร่วมกันมีขนาดเป็นศูนย์
ดังนั้นเมื่อ*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
โปรแกรมที่แล้วเพิ่ม SIGBUS บน Ubuntu 18.04 aarch64 ลินุกซ์เคอร์เนล 4.15.0 ในเครื่องเซิร์ฟเวอร์ ThunderX2
น่าเสียดายที่ฉันทำซ้ำไม่ได้ในโหมดผู้ใช้ QEMU v4.0.0 ฉันไม่แน่ใจว่าทำไม
ความผิดที่ดูเหมือนจะเป็นตัวเลือกและควบคุมโดยSCTLR_ELx.SA
และSCTLR_EL1.SA0
สาขาที่ผมได้สรุปเอกสารที่เกี่ยวข้องบิตต่อที่นี่
ฉันเชื่อว่าเคอร์เนลจะเพิ่ม SIGBUS เมื่อแอปพลิเคชันแสดงข้อมูลที่ไม่ตรงแนวบนดาต้าบัส ฉันคิดว่าเนื่องจากคอมไพเลอร์สมัยใหม่ส่วนใหญ่ [?] สำหรับโปรเซสเซอร์ส่วนใหญ่จะวางแผ่น / จัดเรียงข้อมูลสำหรับโปรแกรมเมอร์ปัญหาการจัดตำแหน่งของสมัยก่อน (อย่างน้อย) ก็ลดลงและด้วยเหตุนี้เราจึงไม่เห็น SIGBUS บ่อยเกินไปในวันนี้ (AFAIK)
จาก: ที่นี่
คุณยังสามารถรับ SIGBUS เมื่อเพจโค้ดไม่สามารถเพจได้ด้วยเหตุผลบางประการ
mmap
ไฟล์ที่มีขนาดใหญ่กว่า/dev/shm
ตัวอย่างเฉพาะของข้อผิดพลาดเกี่ยวกับบัสที่ฉันเพิ่งพบขณะเขียนโปรแกรม C บน OS X:
#include <string.h>
#include <stdio.h>
int main(void)
{
char buffer[120];
fgets(buffer, sizeof buffer, stdin);
strcat("foo", buffer);
return 0;
}
ในกรณีที่คุณจำไม่ได้เอกสารจะต่อstrcat
ท้ายอาร์กิวเมนต์ที่สองเป็นอันดับแรกโดยเปลี่ยนอาร์กิวเมนต์แรก (พลิกอาร์กิวเมนต์และทำงานได้ดี) บน linux สิ่งนี้จะทำให้เกิดความผิดพลาดในการแบ่งส่วน (ตามที่คาดไว้) แต่ใน OS X จะทำให้เกิดข้อผิดพลาดของบัส ทำไม? ฉันไม่รู้จริงๆ
"foo"
ถูกเก็บไว้ในหน่วยความจำแบบอ่านอย่างเดียวดังนั้นจึงเป็นไปไม่ได้ที่จะเขียนลงไป มันจะไม่ป้องกันการล้นสแต็คเพียงการป้องกันการเขียนหน่วยความจำ (นี่คือช่องโหว่ความปลอดภัยหากโปรแกรมของคุณสามารถเขียนใหม่เอง)
อินสแตนซ์คลาสสิกอย่างหนึ่งของข้อผิดพลาดของบัสอยู่ในการออกแบบสถาปัตยกรรมบางอย่างเช่นSPARC (อย่างน้อย SPARC บางอันอาจมีการเปลี่ยนแปลง) คือเมื่อคุณทำการเข้าถึงที่ไม่ถูกต้อง ตัวอย่างเช่น
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
ตัวอย่างนี้พยายามเขียนค่าจำนวนเต็มแบบ 32 บิต0xdeadf00d
ไปยังที่อยู่ซึ่งไม่น่าจะจัดตำแหน่งอย่างเหมาะสมและจะสร้างข้อผิดพลาดของบัสบนสถาปัตยกรรมที่ "จู้จี้จุกจิก" ในเรื่องนี้ Intel x86 ไม่ได้เป็นสถาปัตยกรรม แต่จะอนุญาตให้เข้าถึงได้ (แม้ว่าจะรันช้ากว่า)
ขึ้นอยู่กับ OS, CPU, Compiler และปัจจัยอื่น ๆ
โดยทั่วไปหมายถึง CPU bus ไม่สามารถดำเนินการตามคำสั่งหรือประสบความขัดแย้ง แต่อาจหมายถึงสิ่งต่าง ๆ ทั้งหมดขึ้นอยู่กับสภาพแวดล้อมและรหัสที่ใช้งาน
อดัม
ปกติแล้วหมายถึงการเข้าถึงที่ไม่จัดชิด
ความพยายามในการเข้าถึงหน่วยความจำที่ไม่ได้มีอยู่จริงจะทำให้เกิดข้อผิดพลาดกับบัส แต่คุณจะไม่เห็นสิ่งนี้หากคุณใช้โปรเซสเซอร์ที่มี MMU และระบบปฏิบัติการที่ไม่ใช่รถเข็นเพราะคุณจะไม่มี หน่วยความจำที่มีอยู่แมปไปยังพื้นที่ที่อยู่ของกระบวนการของคุณ
scanf
) นั่นหมายความว่า OS X Mavericks เป็นรถหรือเปล่า สิ่งที่จะได้รับพฤติกรรมในระบบปฏิบัติการที่ไม่ใช่รถ?
ฉันได้รับข้อผิดพลาดของบัสเมื่อไดเรกทอรีรากอยู่ที่ 100%
ฉันเห็นด้วยกับคำตอบทั้งหมดข้างต้น นี่คือ 2 เซ็นต์ของฉันเกี่ยวกับข้อผิดพลาด BUS:
ข้อผิดพลาด BUS ไม่จำเป็นต้องเกิดขึ้นจากคำแนะนำภายในรหัสของโปรแกรม สิ่งนี้สามารถเกิดขึ้นได้เมื่อคุณรันไบนารีและในระหว่างการประมวลผลไบนารีจะถูกแก้ไข (เขียนทับโดยบิลด์หรือลบเป็นต้น)
การตรวจสอบว่าเป็นกรณีนี้:
วิธีง่ายๆในการตรวจสอบว่านี่คือสาเหตุหรือไม่โดยเรียกใช้อินสแตนซ์ของไบนารีเดียวกันและเรียกใช้บิลด์ ทั้งอินสแตนซ์ที่กำลังทำงานอยู่จะทำงานล้มเหลวโดยมีSIGBUS
ข้อผิดพลาดหลังจากสร้างเสร็จและแทนที่ไบนารี (อินสแตนซ์ที่ทั้งสองอินสแตนซ์กำลังทำงานอยู่)
เหตุผลพื้นฐาน: นี่เป็นเพราะ OS สลับหน้าหน่วยความจำและในบางกรณีไบนารีอาจไม่ได้โหลดอย่างสมบูรณ์ในหน่วยความจำและความล้มเหลวเหล่านี้จะเกิดขึ้นเมื่อระบบปฏิบัติการพยายามดึงหน้าถัดไปจากไบนารีเดียวกัน แต่ไบนารีมีการเปลี่ยนแปลงตั้งแต่สุดท้าย อ่านมัน
หากต้องการเพิ่มคำตอบ blxtd ข้างต้นข้อผิดพลาดของบัสก็เกิดขึ้นเช่นกันเมื่อกระบวนการของคุณไม่สามารถเข้าถึงหน่วยความจำของ 'ตัวแปร' ที่เฉพาะเจาะจงได้
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
สังเกตว่าการใช้ตัวแปร 'i ' โดยไม่ตั้งใจใน'for loop' ครั้งแรก นั่นคือสิ่งที่ทำให้เกิดข้อผิดพลาดของรถบัสในกรณีนี้
ฉันเพิ่งค้นพบวิธีที่ยากที่สุดในโปรเซสเซอร์ ARMv7 คุณสามารถเขียนโค้ดบางส่วนที่ให้การแบ่งส่วนที่ผิดพลาดเมื่อไม่ได้เพิ่มประสิทธิภาพ แต่มันทำให้คุณเกิดข้อผิดพลาดกับบัสเมื่อคอมไพล์ด้วย -O2 (ปรับให้เหมาะสมมากขึ้น)
ฉันกำลังใช้ GCC ARM gnueabihf cross compiler จาก Ubuntu 64 bit
บัฟเฟอร์ล้นทั่วไปซึ่งส่งผลให้เกิดข้อผิดพลาด Bus คือ
{
char buf[255];
sprintf(buf,"%s:%s\n", ifname, message);
}
ที่นี่หากขนาดของสตริงในเครื่องหมายคำพูดคู่ ("") มากกว่าขนาด buf จะทำให้เกิดข้อผิดพลาดของบัส