0

最近、厄介なシュレディンバグに出くわしました。ファイルをフラット メモリ表現にロードしようとしているときに、作成者は次のようなコードを記述していました。

class Line final { public:
    int stuff[3];
    char* data;
}

//...

Line* line = /*...*/;
//Trying to treat line->data like an array.  This is *wrong*.
line->data = reinterpret_cast<char*>(line) + 3*sizeof(int);

//...

line->data[0] = /*...*/
line->data[1] = /*...*/
//...
line->data[n] = /*...*/ //"line->data" changes because of this line!

したがって、何が起こっているかというと、コードの最初の行は基本的に にline->data等しく設定されてい&line->dataます。が指している値を変更すると、それ自体が指している値line->dataも変更される可能性があるため、これは誤りです。line->data

その時、問題が発生するまでに非常に長い時間がかかったことが不思議に思いました。私の理解では、restrict(または g++/MSVC で__restrict)修飾されていない限り、コンパイラはポインターがエイリアスされていると想定する必要があります。したがって、line->data[0]何かに設定すると、次のアクセスで表示され、line->data[1]ほぼ確実に無効になります。ただし、デバッガーでは、変更はかなり後になるまで表示されず、書き込みはしばらくの間順調に続きました。

コンパイラ (この場合は MSVC 2013) は、セルフエイリアスが可能であるとは考えていなかったと思います。それは許されますか?

4

2 に答える 2

0

問題が何であったかを正確に知ることは困難です。私はずっと前に問題を修正しており、今ではいくつかのプロジェクトが進んでいます。振り返ってみると、元の質問に対するコメントが、動作を説明する手がかりを与えるのに最も成功したようです。

システムのビット数によっては、パディングが原因である可能性があります。

と:

さて、すぐに頭に浮かぶのはアライメントです。これは 64 ビット プラットフォームで実行されていますか? その場合、ポインター演算の計算ではパディングが考慮されていません。

これが実際にコンパイルされていた64ビットアーキテクチャでは、元の質問のクラスは次のようにメモリに配置されると思います(明確にするために型を調整します):

int32_t stuff_0;
int32_t stuff_1;
int32_t stuff_2;
//4 bytes of empty space
char* data;

パディングは、ポインターをバイト単位で揃えるchar*必要があるために発生します。8最初の 3 つintの s は3*32/8=96/8=12バイトを使用するため、そのアライメントを取得するには、コンパイラは余分な4バイトを挿入して、オーバーヘッドをラウンド16バイトにする必要があります。

data初期化されると、空のスペースの先頭を指すように誤って初期化されました。に書き込みdata[n]0<=n<4パディングをヒットします。問題が発生するのはアクセス時のみdata[4]です。

ほとんどの場合、問題は5 回目のアクセスのあたりで発生しましたが、私の記憶では、後でデバッグ中に問題が発生することもありました。そして、私が書いたように、これシュレディンバグでした (つまり、発生するはずだったのに発生しなかったバグであり、今では観察されており、常に発生しています)。実行中の以前の種類のデータに関するデータはありませんが、おそらくロジックが原因でクリティカル ポインターの範囲が影響を受けない可能性があります。

于 2014-10-01T04:12:10.330 に答える
0

私の理解では、restrict (または g++/MSVC __restrict) で修飾されていない限り、コンパイラはポインターがエイリアス化されていると想定する必要があります。

これは正しくありません。コンパイラは、ポインターが同じ型を指すポインター、または へのポインターのみをエイリアスすることを想定することが許可されていますchar

class X;
class Y;
X *ptr_x = ...;
Y *ptr_y = ...;
char *ptr_char = ...;

ptr_xここで、コンパイラはがエイリアスではないと仮定できptr_yます。ただし、については推測できませんptr_char

于 2014-09-26T21:02:26.060 に答える