Thông báo "lỗi bus" có nghĩa là gì và nó khác với segfault như thế nào?
Thông báo "lỗi bus" có nghĩa là gì và nó khác với segfault như thế nào?
Câu trả lời:
Lỗi bus hiện nay rất hiếm trên x86 và xảy ra khi bộ xử lý của bạn thậm chí không thể thử truy cập bộ nhớ được yêu cầu, thường là:
Lỗi phân đoạn xảy ra khi truy cập bộ nhớ không thuộc về quy trình của bạn, chúng rất phổ biến và thường là kết quả của:
PS: Nói chính xác hơn, đây không phải là thao tác với chính con trỏ sẽ gây ra sự cố, nó truy cập vào bộ nhớ mà nó trỏ tới (hội nghị truyền hình).
/var/cache
chỉ đơn giản là đầy đủ Askubfox.com/a/915520/493379
static_cast
ed một void *
tham số cho một đối tượng lưu trữ một cuộc gọi lại (một thuộc tính trỏ đến đối tượng và một thuộc tính khác cho phương thức). Sau đó, cuộc gọi lại được gọi. Tuy nhiên, những gì đã được thông qua void *
là một cái gì đó hoàn toàn khác và do đó, cuộc gọi phương thức gây ra lỗi bus.
Một segfault đang truy cập bộ nhớ mà bạn không được phép truy cập. Nó chỉ đọc, bạn không có quyền, v.v ...
Một lỗi xe buýt đang cố truy cập vào bộ nhớ không thể có ở đó. Bạn đã sử dụng một địa chỉ vô nghĩa đối với hệ thống hoặc loại địa chỉ sai cho hoạt động đó.
mmap
ví dụ POSIX tối thiểu 7
"Lỗi bus" xảy ra khi kernel gửi SIGBUS
tới một tiến trình.
Một ví dụ tối thiểu tạo ra nó vì ftruncate
đã bị lãng quên:
#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;
}
Chạy với:
gcc -std=c99 main.c -lrt
./a.out
Đã thử nghiệm trong Ubuntu 14.04.
POSIX mô tả SIGBUS
như sau:
Truy cập vào một phần không xác định của một đối tượng bộ nhớ.
Thông số mmap nói rằng:
Các tham chiếu trong phạm vi địa chỉ bắt đầu từ pa và tiếp tục cho các byte len đến toàn bộ các trang sau khi kết thúc một đối tượng sẽ dẫn đến việc phát tín hiệu SIGBUS.
Và shm_open
nói rằng nó tạo ra các đối tượng có kích thước 0:
Đối tượng bộ nhớ chia sẻ có kích thước bằng không.
Vì vậy, tại *map = 0
chúng tôi đang chạm qua cuối của đối tượng được phân bổ.
Truy cập bộ nhớ ngăn xếp không được chỉ định trong ARMv8 aarch64
Điều này đã được đề cập tại: Lỗi xe buýt là gì? cho SPARC, nhưng ở đây tôi sẽ cung cấp một ví dụ dễ tái tạo hơn.
Tất cả bạn cần là một chương trình aarch64 độc lập:
.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
Chương trình đó sau đó tăng SIGBUS trên Ubuntu 18.04 aarch64, nhân Linux 4.15.0 trong máy chủ ThunderX2 .
Thật không may, tôi không thể sao chép nó trên chế độ người dùng QEMU v4.0.0, tôi không chắc tại sao.
Lỗi dường như là tùy chọn và được kiểm soát bởi SCTLR_ELx.SA
và SCTLR_EL1.SA0
các trường, tôi đã tóm tắt các tài liệu liên quan xa hơn một chút ở đây .
Tôi tin rằng hạt nhân tăng SIGBUS khi một ứng dụng thể hiện sự sai lệch dữ liệu trên bus dữ liệu. Tôi nghĩ rằng vì hầu hết [?] Trình biên dịch hiện đại cho hầu hết các bộ xử lý đệm / căn chỉnh dữ liệu cho các lập trình viên, nên các vấn đề liên kết của giảm bớt (ít nhất) đã giảm bớt và do đó người ta không thấy SIGBUS quá thường xuyên trong những ngày này (AFAIK).
Từ: Đây
Bạn cũng có thể nhận SIGBUS khi một trang mã không thể được phân trang vì một số lý do.
mmap
một tệp lớn hơn kích thước của/dev/shm
Một ví dụ cụ thể về lỗi bus tôi vừa gặp khi lập trình C trên OS X:
#include <string.h>
#include <stdio.h>
int main(void)
{
char buffer[120];
fgets(buffer, sizeof buffer, stdin);
strcat("foo", buffer);
return 0;
}
Trong trường hợp bạn không nhớ các tài liệu sẽ strcat
nối đối số thứ hai với đối số thứ nhất bằng cách thay đổi đối số thứ nhất (lật các đối số và nó hoạt động tốt). Trên linux, lỗi này phân đoạn (như mong đợi), nhưng trên OS X, nó báo lỗi bus. Tại sao? Tôi thực sự không biết.
"foo"
được lưu trữ trong một phân đoạn chỉ đọc của bộ nhớ, vì vậy không thể ghi vào nó. Nó sẽ không được bảo vệ chống chồng, chỉ là bảo vệ ghi bộ nhớ (đây là lỗ hổng bảo mật nếu chương trình của bạn có thể tự viết lại).
Một trường hợp kinh điển của lỗi xe buýt là trên một số kiến trúc nhất định, chẳng hạn như SPARC (ít nhất là một số SPARC, có thể điều này đã bị thay đổi), là khi bạn thực hiện truy cập sai. Ví dụ:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
Đoạn mã này cố gắng ghi giá trị số nguyên 32 bit 0xdeadf00d
vào một địa chỉ (rất có thể) không được căn chỉnh chính xác và sẽ tạo ra lỗi bus trên các kiến trúc "kén chọn" trong vấn đề này. Nhân tiện, Intel x86 không phải là một kiến trúc như vậy, nó sẽ cho phép truy cập (mặc dù thực thi nó chậm hơn).
Nó phụ thuộc vào hệ điều hành, CPU, Trình biên dịch của bạn và có thể các yếu tố khác.
Nói chung, điều đó có nghĩa là bus CPU không thể hoàn thành một lệnh hoặc bị xung đột, nhưng điều đó có thể có nghĩa là toàn bộ mọi thứ tùy thuộc vào môi trường và mã được chạy.
-Adam
Nó thường có nghĩa là một truy cập không liên kết.
Nỗ lực truy cập bộ nhớ không có mặt thực tế cũng sẽ gây ra lỗi xe buýt, nhưng bạn sẽ không thấy điều này nếu bạn đang sử dụng bộ xử lý có MMU và HĐH không có lỗi, vì bạn sẽ không gặp phải lỗi nào bộ nhớ hiện tại được ánh xạ tới không gian địa chỉ của quá trình của bạn.
scanf
). Điều đó có nghĩa là OS X Mavericks có lỗi? Điều gì sẽ là hành vi trên một hệ điều hành không có lỗi?
Lý do của tôi cho lỗi bus trên Mac OS X là tôi đã cố gắng phân bổ khoảng 1Mb trên ngăn xếp. Điều này hoạt động tốt trong một luồng, nhưng khi sử dụng openMP, ổ đĩa này bị lỗi bus, vì Mac OS X có kích thước ngăn xếp rất hạn chế đối với các luồng không chính .
Tôi đồng ý với tất cả các câu trả lời ở trên. Dưới đây là 2 xu của tôi liên quan đến lỗi BUS:
Một lỗi Bus không cần phải phát sinh từ các hướng dẫn trong mã của chương trình. Điều này có thể xảy ra khi bạn đang chạy nhị phân và trong quá trình thực thi, nhị phân được sửa đổi (được ghi đè bởi bản dựng hoặc bị xóa, v.v.).
Xác minh nếu đây là trường hợp:
Một cách đơn giản để kiểm tra xem đây có phải là nguyên nhân hay không bằng cách khởi chạy các phiên bản đang chạy của cùng một nhị phân và để chạy một bản dựng. Cả hai phiên bản đang chạy sẽ SIGBUS
gặp lỗi ngay sau khi quá trình xây dựng kết thúc và thay thế nhị phân (phiên bản mà cả hai phiên bản hiện đang chạy)
Lý do ngầm: Điều này là do HĐH hoán đổi các trang bộ nhớ và trong một số trường hợp, nhị phân có thể không được tải hoàn toàn vào bộ nhớ và các sự cố này sẽ xảy ra khi HĐH cố gắng tìm nạp trang tiếp theo từ cùng một nhị phân, nhưng nhị phân đã thay đổi kể từ lần cuối đọc nó.
Để thêm vào những gì blxtd đã trả lời ở trên, lỗi bus cũng xảy ra khi quá trình của bạn không thể truy cập vào bộ nhớ của một 'biến' cụ thể .
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
Lưu ý cách sử dụng ' vô tình ' của biến 'i' trong 'vòng lặp' đầu tiên? Đó là những gì gây ra lỗi xe buýt trong trường hợp này.
Tôi chỉ phát hiện ra một cách khó khăn là trên bộ xử lý ARMv7, bạn có thể viết một số mã gây ra lỗi phân đoạn khi không được tối ưu hóa, nhưng nó gây ra lỗi bus khi được biên dịch với -O2 (tối ưu hóa nhiều hơn).
Tôi đang sử dụng trình biên dịch chéo gnuispihf GCC ARM từ Ubuntu 64 bit.
Một lỗi tràn bộ đệm điển hình dẫn đến lỗi Bus là,
{
char buf[255];
sprintf(buf,"%s:%s\n", ifname, message);
}
Ở đây nếu kích thước của chuỗi trong dấu ngoặc kép ("") lớn hơn kích thước buf thì nó sẽ báo lỗi bus.