70

システムでアクセス違反が発生してプログラムがクラッシュしたため、私の会社に多くの顧客から電話がかかってきました。

クラッシュは、アプリケーションの一部として出荷されている SQLite 3.6.23.1 で発生します。(アプリの残りの部分と同じ VC++ ライブラリを使用するために、カスタム ビルドを出荷しますが、これはストック SQLite コードです。)

WinDbg コールスタックで示されているように、 をpcache1Fetch実行するとクラッシュが発生します。call 00000000

0b50e5c4 719f9fad 06fe35f0 00000000 000079ad 0x0
0b50e5d8 719f9216 058d1628 000079ad 00000001 SQLite_Interop!pcache1Fetch+0x2d [sqlite3.c @ 31530]
0b50e5f4 719fd581 000079ad 00000001 0b50e63c SQLite_Interop!sqlite3PcacheFetch+0x76 [sqlite3.c @ 30651]
0b50e61c 719fff0c 000079ad 0b50e63c 00000000 SQLite_Interop!sqlite3PagerAcquire+0x51 [sqlite3.c @ 36026]
0b50e644 71a029ba 0b50e65c 00000001 00000e00 SQLite_Interop!getAndInitPage+0x1c [sqlite3.c @ 40158]
0b50e65c 71a030f8 000079ad 0aecd680 071ce030 SQLite_Interop!moveToChild+0x2a [sqlite3.c @ 42555]
0b50e690 71a0c637 0aecd6f0 00000000 0001edbe SQLite_Interop!sqlite3BtreeMovetoUnpacked+0x378 [sqlite3.c @ 43016]
0b50e6b8 71a109ed 06fd53e0 00000000 071ce030 SQLite_Interop!sqlite3VdbeCursorMoveto+0x27 [sqlite3.c @ 50624]
0b50e824 71a0db76 071ce030 0b50e880 071ce030 SQLite_Interop!sqlite3VdbeExec+0x14fd [sqlite3.c @ 55409]
0b50e850 71a0dcb5 0b50e880 21f9b4c0 00402540 SQLite_Interop!sqlite3Step+0x116 [sqlite3.c @ 51744]
0b50e870 00629a30 071ce030 76897ff4 70f24970 SQLite_Interop!sqlite3_step+0x75 [sqlite3.c @ 51806]

関連する C コードの行は次のとおりです。

if( createFlag==1 ) sqlite3BeginBenignMalloc();

コンパイラは inlinessqlite3BeginBenignMallocを次のように定義します。

typedef struct BenignMallocHooks BenignMallocHooks;
static SQLITE_WSD struct BenignMallocHooks {
  void (*xBenignBegin)(void);
  void (*xBenignEnd)(void);
} sqlite3Hooks = { 0, 0 };

# define wsdHooksInit
# define wsdHooks sqlite3Hooks

SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void){
  wsdHooksInit;
  if( wsdHooks.xBenignBegin ){
    wsdHooks.xBenignBegin();
  }
}

そして、このためのアセンブリは次のとおりです。

719f9f99    mov     esi,dword ptr [esp+1Ch]
719f9f9d    cmp     esi,1
719f9fa0    jne     SQLite_Interop!pcache1Fetch+0x2d (719f9fad)
719f9fa2    mov     eax,dword ptr [SQLite_Interop!sqlite3Hooks (71a7813c)]
719f9fa7    test    eax,eax
719f9fa9    je      SQLite_Interop!pcache1Fetch+0x2d (719f9fad)
719f9fab    call    eax ; *** CRASH HERE ***
719f9fad    mov     ebx,dword ptr [esp+14h]

レジスタは次のとおりです。

eax=00000000 ebx=00000001 ecx=000013f0 edx=fffffffe esi=00000001 edi=00000000
eip=00000000 esp=0b50e5c8 ebp=000079ad iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202

が 0 の場合eax(これはそうです)、 によってゼロ フラグを設定する必要がありますが、ゼロではありませんtest eax, eax。ゼロフラグが設定されていないため、jeジャンプせず、実行しようとしてアプリがクラッシュしcall eax (00000000)ます。

更新:コードのビルドでは設定されていないeaxため、ここでは常に 0 にする必要があります。定義済みでsqlite3Hooks.xBenignBeginSQLite を再構築できます。これにより、コードが有効になり、このコード パスが完全に省略されます。これで問題は解決するかもしれませんが、「本当の」修正とは思えません。他のコードパスでそれが起こるのを止めるものは何ですか?SQLITE_OMIT_BUILTIN_TEST#define sqlite3BeginBenignMalloc()

これまでのところ、すべての顧客が「Windows 7 Home Premium 64 ビット (6.1、Build 7601) Service Pack 1」を実行しており、次のいずれかの CPU を搭載しているという共通点があります (DxDiag による)。

  • AMD A6-3400M APU、Radeon(tm) HD グラフィックス (4 CPU)、~1.4GHz
  • AMD A8-3500M APU、Radeon(tm) HD グラフィックス (4 CPU)、~1.5GHz
  • AMD A8-3850 APU、Radeon(tm) HD グラフィックス (4 CPU)、~2.9GHz

ウィキペディアのAMD Fusion の記事によると、これらはすべて K10 コアをベースにした「Llano」モデルの AMD Fusion チップであり、2011 年 6 月にリリースされたもので、最初に報告を受け始めた時期です。

最も一般的な顧客システムは Toshiba Satellite L775D ですが、HP Pavilion dv6 & dv7 および Gateway システムからのクラッシュ レポートもあります。

このクラッシュの原因は CPU エラー ( Errata for AMD Family 12h Processors を参照) でしょうか、それとも他に見落としている可能性があるのでしょうか? (Raymond によると、それはオーバークロックである可能性がありますが、もしそうなら、この特定の CPU モデルだけが影響を受けるのは奇妙です。)

正直なところ、これが実際に CPU または OS のエラーである可能性は低いと思われます。なぜなら、顧客はブルースクリーンや他のアプリケーションでのクラッシュを経験していないからです。他にもっと可能性が高い説明があるに違いありませんが、何ですか?

8 月 15 日更新: AMD A6-3400M プロセッサを搭載した Toshiba L745D ノートブックを入手しました。プログラムを実行すると、一貫してクラッシュを再現できます。クラッシュは常に同じ命令で発生します。.timeクラッシュ前のユーザー時間は 1 分 30 秒から 7 分です。最初の投稿で言及しなかった 1 つの事実 (この問題に関連している可能性があります) は、アプリケーションがマルチスレッドであり、CPU と I/O の両方の使用率が高いということです。アプリケーションはデフォルトで 4 つのワーカー スレッドを生成し、クラッシュするまで 80% 以上の CPU 使用率を示します (I/O と SQLite コードのミューテックスのブロックがあります)。2 つのスレッドのみを使用するようにアプリケーションを変更しましたが、それでもクラッシュしました (ただし、発生するまでには時間がかかりました)。現在、スレッドを 1 つだけ使用してテストを実行していますが、まだクラッシュしていません。

また、純粋に CPU 負荷の問題ではないようです。システムでエラーなしで Prime95 を実行でき、CPU 温度が 70°C を超えるまで上昇しますが、実行中のアプリケーションの温度はほとんど 50°C を超えません。

8 月 16 日更新:指示を少し変更すると、問題が「解消」されます。mov eax,dword ptr [SQLite_Interop!sqlite3Hooks (71a7813c)]たとえば、メモリ負荷 ( ) を次のように置き換えるとxor eax, eax、クラッシュが回避されます。元の C コードを変更してステートメントに余分なチェックを追加するif( createFlag==1 )と、コンパイルされたコード内のさまざまなジャンプの相対オフセット (test eax, eaxおよびcall eaxステートメントの場所) が変更され、問題が回避されるようにも見えます。

私がこれまでに見つけた最も奇妙な結果は、jneat719f9fa0を 2 つの命令に変更すると ( /の値に関係なく、nop制御が常に命令にフォールスルーされるように)、プログラムがクラッシュすることなく実行できるようになることです。test eax, eaxcreateFlagesi

4

3 に答える 3

29

このエラーについて Microsoft Build カンファレンスで AMD のエンジニアと話をし、私の再現を見せました。彼は今朝私にメールをくれました:

調査の結果、これは Llano APU ファミリの既知のエラータによるものであることがわかりました。OEM によっては、BIOS の更新によって修正できます。可能であれば、顧客に推奨してください (回避策がある場合でも)。

興味がある場合は、ファミリ 12h リビジョン ガイド (45 ページを参照) の正誤表は 665 です: http://support.amd.com/TechDocs/44739_12h_Rev_Gd.pdf#page=45

その正誤表の説明は次のとおりです。

665 整数除算命令により、予期しない動作が発生する可能性があります

説明

非常に具体的で詳細な一連の内部タイミング条件の下で、プロセッサ コアは投機的な DIV または IDIV 整数除算命令を中止する可能性があります (分岐の予測ミスなどにより投機的な実行がリダイレクトされるため)。非投機的なパスの指示。

システムへの潜在的な影響

予期しないシステムの動作。通常はシステム ハングが発生します。

推奨される回避策

BIOS は MSRC001_1029[31] を設定する必要があります。

この回避策は、AMD ファミリ 10h および 12h プロセッサのソフトウェア最適化ガイド、注文番号 40546で指定されている DIV/IDIV 命令レイテンシを変更します。この回避策を適用すると、AMD ファミリ 12h プロセッサの DIV/IDIV レイテンシは DIV/IDIV レイテンシと同様になります。 AMD ファミリ 10h プロセッサ用。

修正予定

いいえ

于 2011-10-04T01:19:46.823 に答える
1

if (wsdHooks.xBenignBegin)生成されたコードがあまり一般的ではないことが少し心配です。唯一の真の値は であると想定していますが、ゼロ以外の値1を実際にテストする必要があります。それでも、MSVC はそのように困惑することがあります。それはおそらく何もありません。 気にしないでください。これらの手順は、C提示されていないコード用です。

eflagZビットがクリアEAXされていてゼロであることを考えると、命令を実行してもコードはここに到達しませんでした。

719f9fa7    test    eax,eax

719f9fa9 je SQLite_Interop!pcache1Fetch+0x2d別の場所から次の命令 ( ) またはcall命令自体へのジャンプが必要です。

もう 1 つの複雑な問題は、x86 ファミリでは、無効なジャンプ ターゲット (命令の 2 番目のバイトなどJE) が、かなりの数の命令を乱されずに (エラーなしで) 実行することが一般的であり、最終的には適切な命令アライメントに戻ることがよくあることです。別の言い方をすれば、これらの命令の先頭へのジャンプを探しているわけではない可能性があります。ジャンプはバイトの途中にある可能性があり、その結果、add [al+ebp],al気付かれない傾向があるような目立たない操作が実行される可能性があります。

test命令のブレークポイントが例外にヒットしないと予測しています。そのような原因を見つける唯一の方法は、非常に幸運であるか、すべてを疑って1つずつ無実であることを証明することです.

于 2011-08-10T06:50:01.870 に答える
-1

CPU バグの可能性を検討する前に、より可能性の高い原因を除外してみてください

  1. 呼び出し命令への別のコード パス。コマンドを使用しufて関数を逆アセンブルし、呼び出し命令への他のジャンプ/分岐を探します

  2. フック関数から0へジャンプ/コール。 dps SQLite_Interop!sqlite3Hooks l 2null が表示されていることを確認します。

于 2011-08-15T17:23:44.147 に答える