Apa itu kesalahan bus?

254

Apa arti pesan "kesalahan bus", dan bagaimana perbedaannya dari segfault?

raldi
sumber
5
Saya ingin menambahkan penjelasan sederhana untuk keduanya: Kesalahan segmentasi berarti Anda mencoba mengakses memori yang tidak diizinkan (mis. Itu bukan bagian dari program Anda). Namun, pada kesalahan bus biasanya berarti bahwa Anda mencoba mengakses memori yang tidak ada (misalnya Anda mencoba mengakses alamat pada 12G tetapi Anda hanya memiliki memori 8G) atau jika Anda melebihi batas memori yang dapat digunakan.
xdevs23
Pada platform apa Anda melihat ini? PC? Mac? x86? 32/64?
Peter Mortensen

Jawaban:

243

Kesalahan bus jarang terjadi saat ini pada x86 dan terjadi ketika prosesor Anda bahkan tidak dapat mencoba akses memori yang diminta, biasanya:

  • menggunakan instruksi prosesor dengan alamat yang tidak memenuhi persyaratan penyelarasannya.

Kesalahan segmentasi terjadi ketika mengakses memori yang bukan milik proses Anda, mereka sangat umum dan biasanya hasil dari:

  • menggunakan pointer ke sesuatu yang tidak dapat dialokasikan.
  • menggunakan pointer palsu maka tidak diinisialisasi.
  • menggunakan pointer nol.
  • meluap buffer.

PS: Untuk lebih tepatnya ini bukan memanipulasi pointer itu sendiri yang akan menyebabkan masalah, itu mengakses memori yang ditunjuknya (dereferencing).

bltxd
sumber
106
Mereka tidak jarang; Saya hanya di Latihan 9 dari Cara Belajar C dengan Keras dan sudah menemukan satu ...
11684
24
Penyebab lain kesalahan bus (di Linux tetap) adalah ketika sistem operasi tidak dapat mendukung halaman virtual dengan memori fisik (misalnya kondisi memori rendah atau keluar dari halaman besar saat menggunakan memori halaman besar). Biasanya mmap (dan malloc) hanya cadangan ruang alamat virtual, dan kernel memberikan memori fisik sesuai permintaan (disebut soft page faults). Buat malloc yang cukup besar, dan kemudian tulis cukup untuk itu dan Anda akan mendapatkan kesalahan bus.
Eloff
1
bagi saya, partisi yang berisi /var/cachehanya askubuntu.com/a/915520/493379
c33s
2
Dalam kasus saya, metode static_castmengedit void *parameter ke objek yang menyimpan panggilan balik (satu atribut menunjuk ke objek dan yang lainnya ke metode). Kemudian panggilan balik dipanggil. Namun, apa yang disahkan void *adalah sesuatu yang sangat berbeda dan dengan demikian pemanggilan metode menyebabkan kesalahan bus.
Christopher K.
@bltxd Tahukah Anda sifat kesalahan bus. yaitu apakah pesan pada bus ring memiliki beberapa mekanisme di mana pemberhentian pada cincin juga menerima pesan yang dikirim olehnya tetapi ke tujuan mana pun karena menunjukkan bahwa ia telah pergi sepanjang putaran cincin dan belum diterima. Saya menduga buffer baris mengisi mengembalikan status kesalahan dan ketika sudah pensiun itu flushes pipa dan memanggil microroutine pengecualian yang benar. Ini pada dasarnya mensyaratkan bahwa pengontrol memori menerima semua alamat dalam jangkauannya yang akan menyarankan bahwa ketika BARs dll diubah, itu harus internal
Lewis Kelsey
84

Segfault mengakses memori yang tidak boleh Anda akses. Ini hanya baca, Anda tidak memiliki izin, dll ...

Galat bus sedang mencoba mengakses memori yang tidak mungkin ada di sana. Anda telah menggunakan alamat yang tidak berarti bagi sistem, atau jenis alamat yang salah untuk operasi itu.

Clinton Pierce
sumber
14

mmap contoh minimal POSIX 7

"Bus error" terjadi ketika kernel mengirim SIGBUSke suatu proses.

Contoh minimal yang menghasilkannya karena ftruncatedilupakan:

#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;
}

Jalankan dengan:

gcc -std=c99 main.c -lrt
./a.out

Diuji di Ubuntu 14.04.

POSIX menggambarkan SIGBUS sebagai:

Akses ke bagian yang tidak ditentukan dari objek memori.

Spesifikasi mmap mengatakan bahwa:

Referensi dalam kisaran alamat mulai dari pa dan dilanjutkan untuk len byte ke seluruh halaman setelah akhir objek akan menghasilkan pengiriman sinyal SIGBUS.

Dan shm_open mengatakan bahwa itu menghasilkan objek berukuran 0:

Objek memori bersama memiliki ukuran nol.

Jadi *map = 0kita menyentuh melewati akhir objek yang dialokasikan.

Memori stack yang tidak selaras mengakses ARMv8 aarch64

Ini disebutkan di: Apa itu kesalahan bus? untuk SPARC, tetapi di sini saya akan memberikan contoh yang lebih dapat direproduksi.

Yang Anda butuhkan hanyalah program aarch64 yang berdiri sendiri:

.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

Program itu kemudian memunculkan SIGBUS pada Ubuntu 18.04 aarch64, kernel Linux 4.15.0 di mesin server ThunderX2 .

Sayangnya, saya tidak dapat mereproduksi pada mode pengguna QEMU v4.0.0, saya tidak yakin mengapa.

Kesalahan tampaknya bersifat opsional dan dikendalikan oleh SCTLR_ELx.SAdan SCTLR_EL1.SA0bidang, saya telah meringkas dokumen terkait sedikit lebih jauh di sini .

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
11

Saya percaya kernel meningkatkan SIGBUS ketika sebuah aplikasi menunjukkan ketidakselarasan data pada bus data. Saya pikir karena sebagian besar [?] Kompiler modern untuk sebagian besar prosesor pad / menyelaraskan data untuk programmer, masalah penyelarasan dahulu kala (setidaknya) dikurangi, dan karenanya orang tidak melihat SIGBUS terlalu sering hari ini (AFAIK).

Dari: Di Sini

Oli
sumber
1
Tergantung pada trik jahat yang Anda lakukan dengan kode Anda. Anda dapat memicu kesalahan BUS / Alignment Trap jika Anda melakukan sesuatu yang konyol seperti melakukan pointer matematika dan kemudian mengetik perkiraan untuk akses ke mode masalah (yaitu Anda mengatur array uint8_t, tambahkan satu, dua, atau tiga ke pointer array dan kemudian ketik untuk jangka pendek, int, atau panjang dan mencoba mengakses hasil yang menyinggung.) Sistem X86 akan cukup banyak membiarkan Anda melakukan ini, meskipun dengan penalti kinerja nyata. BEBERAPA sistem ARMv7 akan membiarkan Anda melakukan ini- tetapi sebagian besar ARM, MIPS, Power, dll. Akan menggerutu pada Anda tentang hal itu.
Svartalf
6

Anda juga bisa mendapatkan SIGBUS ketika halaman kode tidak dapat digunakan untuk beberapa alasan.

Joshua
sumber
7
Ini sering terjadi ketika saya memperbarui file .so saat menjalankan proses
poordeveloper
Alasan lain untuk terjadi adalah jika Anda mencoba untuk mmapfile yang lebih besar dari ukuran/dev/shm
ilija139
3

Contoh spesifik kesalahan bus yang baru saja saya temui saat memprogram C pada OS X:

#include <string.h>
#include <stdio.h>

int main(void)
{
    char buffer[120];
    fgets(buffer, sizeof buffer, stdin);
    strcat("foo", buffer);
    return 0;
}

Jika Anda tidak ingat, dokumen strcatmenambahkan argumen kedua ke argumen pertama dengan mengubah argumen pertama (balik argumen dan berfungsi dengan baik). Di linux ini memberikan kesalahan segmentasi (seperti yang diharapkan), tetapi pada OS X memberikan kesalahan bus. Mengapa? Saya benar-benar tidak tahu.

Erik Vesteraas
sumber
Mungkin stack overflow protection memunculkan kesalahan bus.
Joshua
1
"foo"disimpan dalam segmen memori hanya baca, jadi tidak mungkin untuk menulisnya. Ini bukan perlindungan overflow tumpukan, hanya perlindungan penulisan memori (ini adalah lubang keamanan jika program Anda dapat menulis ulang sendiri).
Mark Lakata
3

Salah satu contoh klasik dari kesalahan bus adalah pada arsitektur tertentu, seperti SPARC (setidaknya beberapa SPARC , mungkin ini telah diubah), adalah ketika Anda melakukan akses yang tidak sejajar. Misalnya:

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

Cuplikan ini mencoba untuk menulis nilai integer 32-bit 0xdeadf00dke alamat yang (kemungkinan besar) tidak selaras dengan benar, dan akan menghasilkan kesalahan bus pada arsitektur yang "pilih-pilih" dalam hal ini. Intel x86, omong-omong, bukan arsitektur seperti itu, itu akan memungkinkan akses (meskipun mengeksekusi lebih lambat).

beristirahat
sumber
1
Dalam hal ini, saya memiliki data [8]; Ini sekarang merupakan kelipatan dari 4 dalam arsitektur 32-bit. Jadi, itu selaras. Akankah saya masih mendapatkan kesalahan sekarang? Juga, tolong jelaskan, apakah itu ide buruk untuk konversi tipe data untuk pointer. Apakah ini akan menyebabkan kesalahan mis-alignment pada arsitektur yang rapuh. Tolong jelaskan, ini akan membantu saya.
Cekatan
Heh. Ini bukan konversi tipe yang banyak karena Anda melakukan konversi tipe pada pointer yang telah Anda lakukan matematika pointer. Melihat dengan hati-hati di kode di atas. Kompiler telah dengan hati-hati menyelaraskan pointer Anda untuk data- dan kemudian Anda mengacaukan semuanya pada kompiler dengan mengimbangi referensi dengan DUA dan mengetikkan ke sangat banyak perlu akses yang sejalan dengan apa yang akan menjadi batas non-kata.
Svartalf
"Rapuh" bukan kata yang saya gunakan untuk semua ini. Mesin dan kode X86 membuat orang melakukan hal-hal yang agak konyol untuk sementara waktu sekarang, ini salah satunya. Pikirkan kembali kode Anda jika Anda mengalami masalah seperti ini - itu tidak terlalu berkinerja di X86 untuk memulai.
Svartalf
@Svartalf: Pada x86, akses kata pada pointer yang tidak selaras tentu lebih lambat daripada akses kata ke pointer yang disejajarkan, tetapi setidaknya secara historis mereka lebih cepat daripada kode sederhana yang tanpa syarat merakit hal-hal dari byte, dan mereka tentu lebih sederhana daripada kode yang mencoba untuk menggunakan kombinasi optimal berbagai ukuran operasi. Saya berharap standar C akan mencakup cara pengemasan / pembongkaran tipe integer yang lebih besar ke / dari urutan integer / karakter yang lebih kecil sehingga memungkinkan kompiler menggunakan pendekatan apa pun yang terbaik pada platform yang diberikan.
supercat
@ Supercat: Masalahnya adalah ini - Anda lolos begitu saja di X86. Anda mencoba ini pada ARM, MIPS, Power, dll dan Anda akan mendapatkan hal-hal buruk terjadi pada Anda. Pada ARM kurang dari Arch V7, Anda akan memiliki kode Anda mengalami kegagalan pelurusan - dan pada V7, Anda bisa, JIKA runtime Anda diatur untuk itu, tangani dengan hit kinerja SEVERE. Anda hanya tidak ingin melakukan ini. Praktek yang buruk, terus terang. : D
Svartalf
2

Itu tergantung pada OS Anda, CPU, Kompiler, dan mungkin faktor lainnya.

Secara umum itu berarti bus CPU tidak dapat menyelesaikan perintah, atau mengalami konflik, tetapi itu bisa berarti berbagai hal tergantung pada lingkungan dan kode yang sedang dijalankan.

-Adam

Adam Davis
sumber
2

Ini biasanya berarti akses yang tidak selaras.

Upaya untuk mengakses memori yang tidak ada secara fisik juga akan memberikan kesalahan bus, tetapi Anda tidak akan melihat ini jika Anda menggunakan prosesor dengan MMU dan OS yang tidak bermasalah, karena Anda tidak akan memiliki masalah apa pun. Memori -existent dipetakan ke ruang alamat proses Anda.

Mark Baker
sumber
2
I7 saya pasti memiliki MMU, tapi saya masih menemukan kesalahan ini saat belajar C pada OS X (lewat pointer tidak diinisialisasi ke scanf). Apakah itu berarti bahwa OS X Mavericks buggy? Apa yang akan menjadi perilaku pada OS non-kereta?
Calvin Huang
2

Saya mendapatkan kesalahan bus ketika direktori root di 100%.

goCard
sumber
1

Alasan saya untuk kesalahan bus di Mac OS X adalah saya mencoba mengalokasikan sekitar 1Mb di stack. Ini bekerja dengan baik dalam satu utas, tetapi ketika menggunakan openMP ini mendorong ke bus kesalahan, karena Mac OS X memiliki ukuran tumpukan yang sangat terbatas untuk utas non-utama .

Alleo
sumber
1

Saya setuju dengan semua jawaban di atas. Berikut 2 sen saya tentang kesalahan BUS:

Kesalahan BUS tidak perlu muncul dari instruksi dalam kode program. Ini bisa terjadi ketika Anda menjalankan biner dan selama eksekusi, biner dimodifikasi (ditimpa oleh build atau dihapus, dll.).

Memverifikasi apakah ini masalahnya: Cara sederhana untuk memeriksa apakah ini penyebabnya adalah dengan meluncurkan instance yang berjalan dari biner yang sama dan menjalankan build. Kedua instance yang berjalan akan mengalami crash dengan SIGBUSkesalahan sesaat setelah build selesai dan menggantikan binarynya (yang kedua instance tersebut sedang berjalan)

Alasan yang mendasari: Ini karena OS menukar halaman memori dan dalam beberapa kasus biner mungkin tidak sepenuhnya dimuat dalam memori dan crash ini akan terjadi ketika OS mencoba untuk mengambil halaman berikutnya dari biner yang sama, tetapi biner telah berubah sejak terakhir membacanya.

Aditya Vikas Devarapalli
sumber
Setuju, ini adalah penyebab paling umum kesalahan bus dalam pengalaman saya.
itaych
0

Untuk menambahkan apa yang dijawab blxtd di atas, kesalahan bus juga terjadi ketika proses Anda tidak dapat mengakses memori 'variabel' tertentu .

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

Perhatikan ' sengaja ' penggunaan variabel 'i' di pertama 'untuk loop'? Itulah yang menyebabkan kesalahan bus dalam hal ini.

stuxnetting
sumber
Jika m> = n maka loop luar akan dieksekusi sekali atau tidak sama sekali, tergantung pada nilai i yang sudah ada sebelumnya. Jika m <n maka itu akan berjalan tanpa batas dengan indeks j meningkat, sampai Anda akan kehabisan batas array Anda dan kemungkinan besar menyebabkan kesalahan segmentasi, bukan kesalahan bus. Jika kode ini dikompilasi, maka tidak ada masalah mengakses memori dari variabel 'i' itu sendiri. Maaf tapi jawaban ini salah.
itaych
0

Saya baru saja menemukan cara yang sulit bahwa pada prosesor ARMv7 Anda dapat menulis beberapa kode yang memberi Anda kesalahan segmentasi ketika tidak dioptimalkan, tetapi itu memberi Anda kesalahan bus ketika dikompilasi dengan -O2 (mengoptimalkan lebih banyak).

Saya menggunakan kompiler lintas GCC ARM gnueabihf dari Ubuntu 64 bit.

oromoiluig
sumber
Bagaimana ini menjawab pertanyaan?
Peter Mortensen
-1

Buffer buffer khas yang menghasilkan kesalahan Bus adalah,

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

Di sini jika ukuran string dalam tanda kutip ganda ("") lebih dari ukuran buf itu memberikan kesalahan bus.

Vinaya Sagar
sumber
1
Heh ... jika ini masalahnya, Anda akan memiliki masalah kesalahan BUS alih-alih eksploitasi tumpukan yang Anda baca sepanjang waktu untuk Windows dan mesin lainnya. Kesalahan BUS disebabkan oleh upaya untuk mengakses "memori" yang tidak dapat diakses oleh mesin karena alamat tidak valid. (Oleh karena itu istilah "BUS" error.) Ini dapat disebabkan oleh sejumlah kegagalan, termasuk keberpihakan yang tidak valid, dan sejenisnya - selama prosesor tidak dapat menempatkan alamat pada jalur bus.
Svartalf