web-dev-qa-db-ja.com

バスエラーとは何ですか?

「バスエラー」メッセージはどういう意味ですか、またそれはセグメンテーション違反とどう違うのですか?

238
raldi

X86ではバスエラーは最近ではまれであり、プロセッサが要求されたメモリアクセスを試みることすらできないときに発生します。

  • アライメント要件を満たさないアドレスでプロセッサ命令を使用する。

セグメンテーションフォルトはあなたのプロセスに属さないメモリにアクセスするときに発生します、それらは非常に一般的であり、通常以下の結果です。

  • 割り当て解除されたものへのポインタを使用する。
  • 未初期化のために偽のポインタを使用しています。
  • nULLポインタを使用します。
  • バッファオーバーフロー.

PS:より正確に言うと、これは問題を引き起こすポインタ自体を操作することではなく、それが指すメモリにアクセスしています(間接参照)。

223
bltxd

セグメンテーション違反は、あなたがアクセスを許可されていないメモリにアクセスしています。それは読み取り専用です、あなたは許可を得ていません、など。

バスエラーが発生した可能性があるメモリにアクセスしようとしています。システムにとって無意味なアドレス、またはその操作には誤った種類のアドレスを使用しました。

78
Clinton Pierce

アプリケーションがデータバス上でデータの不整合を示すと、カーネルがSIGBUSを発生させると思います。最近のほとんどのプロセッサ向けのコンパイラは、プログラマ向けにデータをパディング/アラインするので、(少なくとも)これまでのアラインメントの問題は軽減されたと考えられます。

から: ここ

11
Oli

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を取得できます。

6
Joshua

バスエラーの典型的な例は、 SPARC (少なくとも一部のSPARC、これが変更された可能性があります)など、特定のアーキテクチャで発生します。例えば:

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

このスニペットは、32ビット整数値0xdeadf00dを(ほとんどの場合)適切にアライメントされていないアドレスに書き込もうとし、この点で「ピッキー」なアーキテクチャでバスエラーを生成します。ところで、Intel x86はnotそのようなアーキテクチャであり、アクセスを許可します(実行速度は遅くなりますが)。

3
unwind

それは、OS、CPU、コンパイラー、そしておそらく他の要因に依存します。

一般に、CPUバスがコマンドを完了できなかったか、競合が発生したことを意味しますが、それは実行中の環境とコードに応じてすべてのことを意味する可能性があります。

-アダム

2
Adam Davis

通常、非境界整列アクセスを意味します。

物理的に存在しないメモリにアクセスしようとすると、バスエラーが発生しますが、MMUおよびバグのないOSを搭載したプロセッサを使用している場合、これは表示されません。存在しないメモリがプロセスのアドレス空間にマップされることはありません。

2
Mark Baker

ルートディレクトリが100%のときにバスエラーが発生しました。

2
goCards

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ではバスエラーになります。どうして?私は本当に知りません。

2
Erik Vesteraas

Mac OS Xでバスエラーが発生する理由は、スタックに約1 MBを割り当てようとしたためです。これは1つのスレッドでうまく機能しましたが、openMPを使用する場合、このエラーはバスエラーになります。これは、Mac OS Xの 非メインスレッドのスタックサイズ が非常に限られているためです。

1
Alleo

上記のすべての答えに同意します。 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'?それがバスの原因ですこの場合のエラー。

0
stuxnetting

ARMv7プロセッサで、最適化されていない場合はセグメンテーションフォールトが発生するが、-O2(さらに最適化された場合)でコンパイルされるとバスエラーが発生するコードを作成できるという困難な方法を発見しました。 ubuntu x64からgcc arm gnueabihfクロスコンパイラを使用しています。

0
oromoiluig