Apa arti pesan "kesalahan bus", dan bagaimana perbedaannya dari segfault?
Apa arti pesan "kesalahan bus", dan bagaimana perbedaannya dari segfault?
Jawaban:
Kesalahan bus jarang terjadi saat ini pada x86 dan terjadi ketika prosesor Anda bahkan tidak dapat mencoba akses memori yang diminta, biasanya:
Kesalahan segmentasi terjadi ketika mengakses memori yang bukan milik proses Anda, mereka sangat umum dan biasanya hasil dari:
PS: Untuk lebih tepatnya ini bukan memanipulasi pointer itu sendiri yang akan menyebabkan masalah, itu mengakses memori yang ditunjuknya (dereferencing).
/var/cache
hanya askubuntu.com/a/915520/493379
static_cast
mengedit 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.
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.
mmap
contoh minimal POSIX 7
"Bus error" terjadi ketika kernel mengirim SIGBUS
ke suatu proses.
Contoh minimal yang menghasilkannya karena ftruncate
dilupakan:
#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 = 0
kita 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.SA
dan SCTLR_EL1.SA0
bidang, saya telah meringkas dokumen terkait sedikit lebih jauh di sini .
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
Anda juga bisa mendapatkan SIGBUS ketika halaman kode tidak dapat digunakan untuk beberapa alasan.
mmap
file yang lebih besar dari ukuran/dev/shm
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 strcat
menambahkan 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.
"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).
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 0xdeadf00d
ke 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).
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
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.
scanf
). Apakah itu berarti bahwa OS X Mavericks buggy? Apa yang akan menjadi perilaku pada OS non-kereta?
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 .
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 SIGBUS
kesalahan 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.
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.
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.
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.