「バスエラー」メッセージはどういう意味ですか、またそれはセグメンテーション違反とどう違うのですか?
X86ではバスエラーは最近ではまれであり、プロセッサが要求されたメモリアクセスを試みることすらできないときに発生します。
セグメンテーションフォルトはあなたのプロセスに属さないメモリにアクセスするときに発生します、それらは非常に一般的であり、通常以下の結果です。
PS:より正確に言うと、これは問題を引き起こすポインタ自体を操作することではなく、それが指すメモリにアクセスしています(間接参照)。
セグメンテーション違反は、あなたがアクセスを許可されていないメモリにアクセスしています。それは読み取り専用です、あなたは許可を得ていません、など。
バスエラーが発生した可能性があるメモリにアクセスしようとしています。システムにとって無意味なアドレス、またはその操作には誤った種類のアドレスを使用しました。
アプリケーションがデータバス上でデータの不整合を示すと、カーネルがSIGBUSを発生させると思います。最近のほとんどのプロセッサ向けのコンパイラは、プログラマ向けにデータをパディング/アラインするので、(少なくとも)これまでのアラインメントの問題は軽減されたと考えられます。
から: ここ
mmap
最小限のPOSIX 7の例
カーネルがプロセスに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のオブジェクトを生成すると言います:
共有メモリオブジェクトのサイズは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
そのプログラムは、Ubuntu 18.04 aarch64、Linuxカーネル4.15.0 ThunderX2サーバマシン でSIGBUSを発生させます。
残念ながら、QEMU v4.0.0のユーザーモードで再現することはできません、理由はわかりません。
この障害はオプションで、SCTLR_ELx.SA
およびSCTLR_EL1.SA0
フィールドによって制御されているようです。関連ドキュメント をもう少しここ にまとめました。
何らかの理由でコードページをページインできない場合にも、SIGBUSを取得できます。
バスエラーの典型的な例は、 SPARC (少なくとも一部のSPARC、これが変更された可能性があります)など、特定のアーキテクチャで発生します。例えば:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
このスニペットは、32ビット整数値0xdeadf00d
を(ほとんどの場合)適切にアライメントされていないアドレスに書き込もうとし、この点で「ピッキー」なアーキテクチャでバスエラーを生成します。ところで、Intel x86はnotそのようなアーキテクチャであり、アクセスを許可します(実行速度は遅くなりますが)。
それは、OS、CPU、コンパイラー、そしておそらく他の要因に依存します。
一般に、CPUバスがコマンドを完了できなかったか、競合が発生したことを意味しますが、それは実行中の環境とコードに応じてすべてのことを意味する可能性があります。
-アダム
通常、非境界整列アクセスを意味します。
物理的に存在しないメモリにアクセスしようとすると、バスエラーが発生しますが、MMUおよびバグのないOSを搭載したプロセッサを使用している場合、これは表示されません。存在しないメモリがプロセスのアドレス空間にマップされることはありません。
ルートディレクトリが100%のときにバスエラーが発生しました。
OS XでCをプログラミングしているときに発生したバスエラーの具体例:
#include <string.h>
#include <stdio.h>
int main(void)
{
char buffer[120];
fgets(buffer, sizeof buffer, stdin);
strcat("foo", buffer);
return 0;
}
ドキュメントを覚えていない場合は、strcat
が最初の引数を変更することで最初の引数に2番目の引数を追加します(引数を反転すると正常に動作します)。 Linuxでは、これはセグメンテーションフォールト(予想どおり)になりますが、OS Xではバスエラーになります。どうして?私は本当に知りません。
Mac OS Xでバスエラーが発生する理由は、スタックに約1 MBを割り当てようとしたためです。これは1つのスレッドでうまく機能しましたが、openMPを使用する場合、このエラーはバスエラーになります。これは、Mac OS Xの 非メインスレッドのスタックサイズ が非常に限られているためです。
上記のすべての答えに同意します。 BUSエラーに関する私の2セントは次のとおりです。
BUSエラーは、プログラムのコード内の命令から発生する必要はありません。これは、バイナリを実行しているときに発生し、実行中にバイナリが変更されます(ビルドによって上書きまたは削除など)。
これが当てはまるかどうかの検証:これが原因かどうかを確認する簡単な方法は、同じバイナリの実行中のインスタンスを起動してビルドを実行することです。ビルドが終了し、バイナリ(両方のインスタンスが現在実行されているもの)を置き換えた直後に、実行中のインスタンスが両方ともSIGBUS
エラーでクラッシュします。
nderlying Reason:これは、OSがメモリページをスワップし、場合によってはバイナリ全体がメモリ内に存在し、OSが同じバイナリから次のページを取得しようとするとこれらのクラッシュが発生するためです。バイナリは最後に読み取られてから変更されています。
上記のblxtdが答えたものに追加するために、プロセスが特定の「変数」のメモリにアクセスできない場合にもバスエラーが発生します。
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
「inadvertent 'variable' i ' in first 'for loop'?それがバスの原因ですこの場合のエラー。
ARMv7プロセッサで、最適化されていない場合はセグメンテーションフォールトが発生するが、-O2(さらに最適化された場合)でコンパイルされるとバスエラーが発生するコードを作成できるという困難な方法を発見しました。 ubuntu x64からgcc arm gnueabihfクロスコンパイラを使用しています。