2010-01-18 43 views
10

Điều gì có thể gây SIGBUS (lỗi bus) trên ứng dụng chung của người dùng x86 trong Linux? Tất cả các cuộc thảo luận tôi đã có thể tìm thấy trực tuyến là liên quan đến lỗi liên kết bộ nhớ, mà từ những gì tôi hiểu không thực sự áp dụng cho x86.Gỡ lỗi SIGBUS trên x86 Linux

(mã của tôi đang chạy trên một Geode, trong trường hợp có bất kỳ quirks xử lý cụ thể liên quan ở đó.)

Trả lời

13

Bạn có thể nhận SIGBUS từ truy cập chưa được ký nếu bạn bật bẫy truy cập chưa được căn chỉnh, nhưng thông thường là tắt trên x86. Bạn cũng có thể làm cho nó truy cập vào một thiết bị được ánh xạ bộ nhớ nếu có lỗi nào đó.

Đặt cược tốt nhất của bạn là sử dụng trình gỡ lỗi để xác định hướng dẫn lỗi (SIGBUS là đồng bộ) và cố gắng xem nó đang cố gắng làm gì.

+1

Trình gỡ lỗi cho thấy SIGBUS xảy ra ngay lập tức khi nhập hàm. Có lẽ tôi có một số tham nhũng bộ nhớ, hoặc có thể một trong các thông số chức năng là xấu? Tôi sẽ phải kiểm tra việc tháo gỡ trong trình gỡ rối để biết thêm chi tiết nếu lỗi xảy ra lần nữa. –

+1

@Josh - kiểm tra xem hướng dẫn thất bại thực sự là gì - nếu nó là push hay pop thì con trỏ ngăn xếp của bạn bị hỏng. Nếu một cái gì đó khác của nó, sau đó địa chỉ trong hướng dẫn là vấn đề. –

0

Một nguyên nhân phổ biến của một lỗi xe buýt trên x86 Linux đang cố gắng dereference cái gì đó không thực sự là một con trỏ, hoặc là một con trỏ hoang dã. Ví dụ, không khởi tạo một con trỏ, hoặc gán một số nguyên tùy ý cho một con trỏ và sau đó cố gắng dereference nó thường sẽ tạo ra một lỗi phân đoạn hoặc một lỗi bus.

Căn chỉnh áp dụng cho x86. Mặc dù bộ nhớ trên x86 là địa chỉ byte (vì vậy bạn có thể có một con trỏ char đến bất kỳ địa chỉ nào), nếu bạn có ví dụ một con trỏ đến một số nguyên 4 byte, con trỏ đó phải được căn chỉnh.

Bạn nên chạy chương trình của mình trong gdb và xác định truy cập con trỏ nào đang tạo ra lỗi bus để chẩn đoán sự cố.

+4

Truy cập chưa được căn chỉnh của các số nguyên hoạt động trên x86. – Joshua

+5

không cho các chỉ dẫn SSE –

+3

Tất cả các hướng dẫn tải/lưu trữ SSE đều có các phiên bản được canh lề và căn chỉnh. Đối với các truy cập SSE (128 bit), chúng thực sự chạy ở tốc độ tối đa trên kiến ​​trúc Intel đương đại, vì vậy không có hình phạt thực sự chỉ bằng cách sử dụng các bước không có điều kiện vô điều kiện (trừ khi bạn tối ưu hóa mức độ đáng kể, không chắc chắn). –

15

SIGBUS có thể xảy ra trong Linux vì một vài lý do khác với lỗi liên kết bộ nhớ - ví dụ: nếu bạn cố gắng truy cập khu vực mmap ngoài phần cuối của tệp được ánh xạ.

Bạn có đang sử dụng bất cứ thứ gì như mmap, khu vực bộ nhớ dùng chung hoặc tương tự không?

+2

Có, chúng tôi đang sử dụng các vùng bộ nhớ dùng chung. Tôi sẽ điều tra khả năng đó vào lần tới khi lỗi này xuất hiện. Cảm ơn. –

+0

mmap là nhất thiết phải được sử dụng bởi bất kỳ chương trình gọi malloc, kể từ hôm nay malloc là một chuyển tiếp đến mmap. –

+0

@ v.oddou: Đó là mmap ẩn danh, không có khái niệm "vượt quá kết thúc của tệp được ánh xạ". – caf

3

Ồ vâng, có một cách kỳ lạ hơn để nhận SIGBUS.

Nếu hạt nhân không thể trang trong trang mã do áp lực bộ nhớ (OOM killer phải được tắt) hoặc yêu cầu IO không thành công, SIGBUS.

0

Đó là một chút so với đường bị đánh, nhưng bạn có thể lấy SIGBUS từ một tải SSE2 (m128) chưa được căn chỉnh.

+2

Bạn có thể? Nó thường dẫn đến #GP, ánh xạ tới SIGSEGV. – Ruslan

+1

Xin lỗi, bạn nói đúng. – Mischa

6

SIGBUS trên x86 (bao gồm x86_64) Linux là một con thú quý hiếm. Nó có thể xuất hiện từ nỗ lực truy cập vào cuối tệp mmap ed hoặc một số tình huống khác được mô tả bởi POSIX.

Nhưng do lỗi phần cứng, việc lấy SIGBUS không dễ dàng. Cụ thể là, truy cập không được gán từ bất kỳ lệnh nào - có thể là SIMD hay không - thường là kết quả trong SIGSEGV. Chồng tràn kết quả trong SIGSEGV. Ngay cả khi truy cập vào các địa chỉ không có dạng thức kinh điển dẫn đến SIGSEGV. Tất cả điều này do #GP được nâng lên, hầu như luôn luôn ánh xạ tới SIGSEGV.

Bây giờ, here're một số cách để có được SIGBUS do một ngoại lệ CPU:

  1. Enable AC bit trong EFLAGS, sau đó làm truy cập unaligned bởi bất kỳ bộ nhớ đọc hoặc viết hướng dẫn. Xem this discussion để biết chi tiết.

  2. Vi phạm chính tắc qua đăng ký con trỏ ngăn xếp (rsp hoặc rbp), tạo #SS.Dưới đây là một ví dụ cho GCC (biên dịch với gcc test.c -o test -masm=intel):

 
int main() 
{ 
    __asm__("mov rbp,0x400000000000000\n" 
      "mov rax,[rbp]\n" 
      "ud2\n"); 
} 
1

là một thời gian ngắn này đề cập ở trên là một "thất bại IO yêu cầu", nhưng tôi sẽ mở rộng khi nó một chút.

Trường hợp thường xuyên là khi bạn lười biếng phát triển tệp bằng ftruncate, ánh xạ nó vào bộ nhớ, bắt đầu viết dữ liệu và sau đó hết dung lượng trong hệ thống tệp của bạn. Không gian vật lý cho tệp được ánh xạ được phân bổ trên các lỗi trang, nếu không có gì còn lại thì quá trình sẽ nhận được SIGBUS.

Nếu bạn cần ứng dụng của mình khôi phục chính xác từ lỗi này, bạn nên đặt trước khoảng trống trước khi mmap bằng cách sử dụng sai chỗ. Xử lý ENOSPC trong errno sau khi rút gọn cuộc gọi đơn giản hơn nhiều so với xử lý tín hiệu, đặc biệt là trong một ứng dụng đa luồng.

Các vấn đề liên quan