バスエラーとは何ですか?
-
03-07-2019 - |
質問
「バスエラー」の原因メッセージは、セグメンテーション違反とどのように違いますか?
解決
バスエラーは現在x86ではまれであり、プロセッサが要求されたメモリアクセスを試みることさえできない場合に発生します。通常は
- アライメント要件を満たさないアドレスでプロセッサ命令を使用する。
セグメンテーション違反は、プロセスに属していないメモリにアクセスするときに発生します。非常に一般的であり、通常は次の結果です:
- 割り当て解除された何かへのポインタを使用します。
- 初期化されていない、したがって偽のポインターを使用しています。
- nullポインターを使用。
- バッファをオーバーフローしています。
PS:より正確には、これは問題の原因となるポインター自体を操作するのではなく、ポインターが指すメモリーにアクセスしています(逆参照)。
他のヒント
セグメンテーション違反が、アクセスを許可されていないメモリにアクセスしています。読み取り専用で、権限がありません...
バスエラーが発生した可能性があるメモリにアクセスしようとしています。システムにとって意味のないアドレスを使用したか、その操作に間違った種類のアドレスを使用しました。
カーネルがSIGBUSを上げると思います アプリケーションがデータを示すとき データバスの位置ずれ。おもう ほとんどの[?]現代のコンパイラ以来 ほとんどのプロセッサでは、パッド/アライメント プログラマー向けのデータ、 (少なくとも)昔のアライメントのトラブル 軽減されたため、表示されません 最近のSIGBUSの頻度が高すぎます(AFAIK)。
From:ここ
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
as:
メモリオブジェクトの未定義部分へのアクセス。
mmap仕様には次のように記載されています:
paで始まり、オブジェクトの終わりに続くページ全体にlenバイト続くアドレス範囲内の参照は、SIGBUSシグナルの配信になります。
および shm_open
そうサイズ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でSIGBUSを ThunderX2サーバーマシン。
残念ながら、QEMU v4.0.0ユーザーモードでは再現できません。理由はわかりません。
障害はオプションであり、 SCTLR_ELx.SA
および SCTLR_EL1.SA0
フィールドによって制御されているようです。関連ドキュメントもう少しここ。
何らかの理由でコードページをページインできない場合にも、SIGBUSを取得できます。
バスエラーの古典的な例の1つは、 SPARC (少なくとも一部のSPARCは、おそらくこれが変更されているかもしれません)、ミスアライメントのアクセスを行うときです。例えば:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
このスニペットは、32ビット整数値 0xdeadf00d
を(ほとんどの場合)適切に位置合わせされていないアドレスに書き込もうとし、&quot; picky&quot;のアーキテクチャでバスエラーを生成します。この点について。ところで、Intel x86はそのようなアーキテクチャではそうではありません、アクセスを許可します(実行速度は遅くなりますが)。
OS、CPU、コンパイラ、およびその他の要因に依存します。
一般的には、CPUバスがコマンドを完了できなかったか、競合が発生したことを意味しますが、それは実行中の環境とコードに応じてすべてのことを意味する可能性があります。
-アダム
通常は、非境界整列アクセスを意味します。
物理的に存在しないメモリにアクセスしようとすると、バスエラーも発生しますが、MMUとバグのないOSを搭載したプロセッサを使用している場合、これは表示されません。存在しないメモリをプロセスのアドレス空間にマップします。
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ではバスエラーになります。どうして?本当にわからない。
ルートディレクトリが100%のときにバスエラーが発生しました。
Mac OS Xでバスエラーが発生する理由は、スタックに約1MBを割り当てようとしたためです。これは1つのスレッドでうまく機能しましたが、openMPを使用する場合、このエラーはバスエラーになります。MacOS Xでは非メインスレッドのスタックサイズ。
上記のblxtdの回答に追加するために、プロセスが特定の「変数」のメモリにアクセスを試みることができない 場合にもバスエラーが発生します。
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
内の 変数「i」 の「 偶然 」の使用に注意してください最初の「forループ」ですか? この場合、これがバスエラーの原因です。
ARMv7プロセッサ上で、最適化されていない場合にセグメンテーションフォールトが発生するが、-O2でコンパイルされた場合にバスエラーが発生する(さらに最適化する)コードを記述できる難しい方法を発見しました。 ubuntu x64からgcc arm gnueabihfクロスコンパイラを使用しています。
上記のすべての答えに同意します。 BUSエラーに関する私の2セントは次のとおりです。
BUSエラーは、プログラムのコード内の命令から発生する必要はありません。これは、バイナリを実行しているときに発生し、実行中にバイナリが変更されます(ビルドによって上書きまたは削除など)。
これが当てはまるかどうかの確認:
これが原因かどうかを確認する簡単な方法は、同じバイナリの実行中のインスタンスを起動して、ビルドを実行することです。ビルドが終了してバイナリ(両方のインスタンスが現在実行されているもの)を置き換えた直後に、実行中のインスタンスが両方とも SIGBUS
エラーでクラッシュします
根本的な理由: これは、OSがメモリページをスワップし、場合によってはバイナリ全体がメモリ内にある可能性があり、OSが同じバイナリから次のページをフェッチしようとしたときにこれらのクラッシュが発生しますが、バイナリは最後に読み取ってから変更されているためです
バスエラーを引き起こす典型的なバッファオーバーフローは、
{
char buf[255];
sprintf(buf,"%s:%s\n", ifname, message);
}
ここで、二重引用符(&quot;&quot;)で囲まれた文字列のサイズがbufサイズより大きい場合、バスエラーが発生します。