インデックスが見つからない場合

もちろん、この問題はRussinovichほど興味深いものではありませんが、一部の開発者にとっては役に立つと思います。 プレゼンテーションの主な目的は、最低レベルでプログラムの動作を分析できる手段を示すことです。



そのため、.net framework 1.1を使用するC#で記述されたアプリケーションがあります(はい)。 いくつかの変更の後、アプリケーションはそのような情報のない例外をスローし始めました。

System.NullReferenceException: Object reference not set to an instance of an object.

at System.Data.DataTable. ResetIndexes ()

at System.Data.Merger.MergeTable(DataTable src, DataTable dst)

at System.Data.Merger.MergeTableData(DataTable src)

at System.Data.Merger.MergeTable(DataTable src)

at System.Data.DataSet.Merge(DataTable table, Boolean preserveChanges, MissingSchemaAction missingSchemaAction)

at Com.Product.App.RequestForm. InitEdit (InitRequestArgs args)






InitEditは、データを初期化するアプリケーションのフォーム関数です。 スローされるアプリケーションのソースコードの行:

dsRequestList.Merge(dsLast.Tables[ "TABLE_REQUESTS" ], false , MissingSchemaAction.Ignore);





リフレクターが示すResetIndexes関数コードは、非常に複雑であると言っているわけではありません。





  1. 内部 void ResetIndexes()
  2. {
  3. this .RecomputeCompareInfo();
  4. ifthis .indexes!= null
  5. {
  6. this .SetShadowIndexes();
  7. 試してみる
  8. {
  9. int count = this .shadowIndexes.Count;
  10. forint i = 0; i <count; i ++)
  11. {
  12. ((Index) this .shadowIndexes [i])。Reset();
  13. }
  14. }
  15. ついに
  16. {
  17. this .shadowIndexes = null ;
  18. }
  19. }
  20. }
*このソースコードは、 ソースコードハイライターで強調表示されました。


問題ないようです。 関数はインデックスを実行し、各Resetを呼び出します。 例外はどこにありますか? SetShadowIndexesは、単に「 this.shadowIndexes = this.LiveIndexes; 」を呼び出します。したがって、9行目が実行されると、shadowIndexesはゼロ以外になります。 したがって、この配列内のどこかにnull要素があり、それに応じて12行目に該当すると想定するのが妥当と思われます。これが問題だと思います。



windbgを起動し、プロセスに接続して、Son of Strike(sos.dll)をデバッガーにロードします。 誰もがそれが何であるかを知っていて、説明する必要はないと思います。



関数にブレークポイントを設定します。



0:023> !bp app.exe Com.Product.App.RequestForm. InitEdit

Setting breakpoint at : 0xcef7988

bp 0xcef7988 " .echo [DEFAULT] [hasThis] Boolean Com.Product.App.RequestForm.InitEdit(Class Com.Product.Tickets.InitArgs) "

Setting breakpoint at : 0xcef7a38

bp 0xcef7a38 " .echo [DEFAULT] [hasThis] Boolean Com.Product.App.RequestForm.InitEdit(Class Com.Product.App.Requests.InitRequestArgs) "








(2番目の関数だけが必要なので、windbgコマンドで最初のポイントをオフにします:bd 0)。



ResetIndexesブレークポイントを直接配置することはできません。アプリケーションはデータセットを非常に集中的に使用するため、多くの誤った呼び出しを逃す必要があるためです。

したがって、目的の関数を呼び出すときに、ポイントを順番に配置する必要があります。



デバッガーがInitEditで停止した後、 DataSet.Mergeにドットを配置します。

0:000> !bp system.data.dll System.Data.DataSet.Merge

Setting breakpoint at : 0x8185418

bp 0x8185418 " .echo [DEFAULT] [hasThis] Void System.Data.DataSet.Merge(Class System.Data.DataSet) "






(再び、SoSはオーバーロードされたすべてのMerge関数を停止するため、不要な関数は削除します)



DataSet.Mergeの後、 DataTable.ResetIndexesが呼び出されるSystem.Data.Merger.MergeTableに移動する必要があります



引数が実際に期待するものであることを確認します。

0:000> !clrstack -a 1

Thread 0

ESP EIP

ESP/REG Object Name

eax 0x191cca10 Com.Product.App.Requests.dsRequests/TABLE_USERSDataTable

ecx 0x1562815c System.Data.Merger

edx 0x1952b684 System.Data.DataTable

esi 0x1562815c System.Data.Merger

edi 0x1952b684 System.Data.DataTable

0x0012e9b4 0x08186d00 [DEFAULT] [hasThis] Void System.Data.Merger.MergeTable(Class System.Data.DataTable,Class System.Data.DataTable)

EDI 0x1952b684 ESI 0x1562815c EBX 0x00000000 EDX 0x1952b684 ECX 0x1562815c

EAX 0x191cca10 EBP 0x0012e9dc ESP 0x0012e9b4 EIP 0x08186d00








パラメータとして渡されるテーブルの名前を確認します。

0:000> !do (edx)

Name: System.Data.DataTable

MethodTable 0x04a633f8

EEClass 0x04a37244

Size 232(0xe8) bytes

GC Generation: 2

mdToken: 0x0200003d (c:\winxp\assembly\gac\system.data\1.0.5000.0__b77a5c561934e089\system.data.dll)

FieldDesc*: 0x04a62544

MT Field Offset Type Attr Value Name

0x7b308b0c 0x4000583 0x4 CLASS instance 0x00000000 site

...

0x04a633f8 0x40003fa 0x34 CLASS instance 0x15628170 extendedProperties

0x04a633f8 0x40003fb 0x38 CLASS instance 0x1952bc2c tableName

0x04a633f8 0x40003fc 0x3c CLASS instance 0x00000000 tableNamespace

...








テーブル名は、オブジェクトの先頭から0x38のオフセットでフィールドに書き込まれます。



0:000> !do poi(edx+38)

String: TABLE_USERS








TABLE_USERS-必要なテーブルではないので、会うまで先に進んでください



0:000> !do poi(edx+38)

String: TABLE_REQUESTS








その後のみ、 ResetIndexesブレークポイントを追加し、プログラムをさらに実行して、再び停止します。



0:000> g

[DEFAULT] [hasThis] Void System.Data.DataTable.ResetIndexes()

eax=191c76ec ebx=00000001 ecx=191c70b4 edx=0006471c esi=19508a4c edi=19221a28

eip=07eff838 esp=0012e988 ebp=191c70b4 iopl=0 nv up ei ng nz na po cy

cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000283

07eff838 55 push ebp

0:000> !clrstack -a 1

Thread 0

ESP EIP

ESP/REG Object Name

eax 0x191c76ec System.Collections.ArrayList

ecx 0x191c70b4 Com.Product.App.Requests.dsRequests/TABLE_REQUESTSDataTable

esi 0x19508a4c System.Data.DataRow

edi 0x19221a28 System.Data.DataTable

ebp 0x191c70b4 Com.Product.App.Requests.dsRequests/TABLE_REQUESTSDataTable

0x0012e988 0x07eff838 [DEFAULT] [hasThis] Void System.Data.DataTable.ResetIndexes()

EDI 0x19221a28 ESI 0x19508a4c EBX 0x00000001 EDX 0x0006471c ECX 0x191c70b4

EAX 0x191c76ec EBP 0x191c70b4 ESP 0x0012e988 EIP 0x07eff838








これはecxに渡され、それを取得して、 indexesフィールドの内容を確認します。



0:000> !do ecx

Name: Com.Product.App.Requests.dsRequests/TABLE_REQUESTSDataTable

MethodTable 0x10bb39f4

EEClass 0x10ac9a40

Size 580(0x244) bytes

GC Generation: 2

mdToken: 0x02000296

FieldDesc*: 0x10bb2eb4

MT Field Offset Type Attr Value Name

0x7b308b0c 0x4000583 0x4 CLASS instance 0x00000000 site

...

0x04a633f8 0x40003f8 0x2c CLASS instance 0x191c76ec indexes

0x04a633f8 0x40003f9 0x30 CLASS instance 0x00000000 shadowIndexes

0x04a633f8 0x40003fa 0x34 CLASS instance 0x15629d98 extendedProperties

...









これまでのところ良い。 ResetIndexeを入力した時点では、インデックスフィールドはゼロであり、 SetShadowIndexesを使用して設定されます。



0:000> !dc 0x191c76ec

Going to dump the Collection passed.

Name: System.Collections.ArrayList

GC Generation: 2



Address MT Class Name

0x1557971c 0x08121b80 System.Data.Index

0x1559e420 0x08121b80 System.Data.Index

0x1559e508 0x08121b80 System.Data.Index

0x1559e5f0 0x08121b80 System.Data.Index

0x1559e6d8 0x08121b80 System.Data.Index

0x1559e7c0 0x08121b80 System.Data.Index

0x1559e8a8 0x08121b80 System.Data.Index

0x1559e990 0x08121b80 System.Data.Index

0x1559ea78 0x08121b80 System.Data.Index

0x1559eb60 0x08121b80 System.Data.Index

0x1559ec48 0x08121b80 System.Data.Index

0x1559ed30 0x08121b80 System.Data.Index

0x1559ee18 0x08121b80 System.Data.Index

0x1559ef00 0x08121b80 System.Data.Index

0x1559efe8 0x08121b80 System.Data.Index

0x1559f0d0 0x08121b80 System.Data.Index

0x1559f1b8 0x08121b80 System.Data.Index

0x156f1a9c 0x08121b80 System.Data.Index

0x156f4cd4 0x08121b80 System.Data.Index

0x157962b0 0x08121b80 System.Data.Index

0x157ba910 0x08121b80 System.Data.Index








うーん...私の基本的な理論は、目の前でバラバラになっています。 ゼロ要素はありません。 これは不運です。 それでは、コードの実行を続け、windbg内からの例外を見てみましょう。 プログラムをリリースします。 例外が発生すると、デバッガーは停止します。

0:000> g

(1638.1738): Access violation - code c0000005 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

eax=191c70b4 ebx=00000015 ecx=00000000 edx=00000014 esi=195b0894 edi=00000014

eip=07eff899 esp=0012e960 ebp=0012e984 iopl=0 nv up ei ng nz ac pe cy

cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010297

07eff899 8b01 mov eax,dword ptr [ecx] ds:0023:00000000=????????








コマンド!Analyze -vを実行すると、その結果に、発生した例外に関するあらゆる種類のデータが非常に詰め込まれます。 私は圧縮されたフォームを持ってきます:



0:000> !analyze -v



*******************************************************************************

* *

* Exception Analysis *

* *

*******************************************************************************



FAULTING_IP:

+7eff899

07eff899 8b01 mov eax,dword ptr [ecx]



EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff)

.exr 0xffffffffffffffff

ExceptionAddress: 07eff899

ExceptionCode: c0000005 (Access violation)

ExceptionFlags: 00000000

NumberParameters: 2

Parameter[0]: 00000000

Parameter[1]: 00000000

Attempt to read from address 00000000



FAULTING_THREAD: 00001738



DEFAULT_BUCKET_ID: NULL_POINTER_READ



PROCESS_NAME: App.exe



ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory at "0x%08lx". The memory could not be "%s".



READ_ADDRESS: 00000000



FAILED_INSTRUCTION_ADDRESS:

+7eff899

07eff899 8b01 mov eax,dword ptr [ecx]



NTGLOBALFLAG: 0



APPLICATION_VERIFIER_FLAGS: 0



IP_ON_HEAP: 08186f34



MANAGED_STACK: !dumpstack -EE

!dumpstack -EE

Thread 0

Current frame: (MethodDesc 0x4a63200 +0x61 System.Data.DataTable.ResetIndexes)

ChildEBP RetAddr Caller,Callee

0012e984 08186f34 (MethodDesc 0x31fcff0 +0x234 System.Data.Merger.MergeTable)

0012e9b0 08185790 (MethodDesc 0x31fd020 +0x48 System.Data.Merger.MergeTableData)

0012e9dc 0818e31f (MethodDesc 0x31fcfe0 +0x2f System.Data.Merger.MergeTable)

0012e9ec 0818e2b1 (MethodDesc 0x7ec0ce8 +0x61 System.Data.DataSet.Merge)

0012ea00 0cef8056 (MethodDesc 0x7c8f8d0 +0x61e Com.Product.App.RequestForm.InitEdit)

0012ec3c 26a117e7 (MethodDesc 0x10eaee98 +0x57 Com.Product.Core.Entities.EntityContextCache..ctor)

0012ec50 0cef79df (MethodDesc 0x7c8f8c0 +0x57 Com.Product.App.RequestForm.InitEdit)

0012ec74 0818d593 (MethodDesc 0x7ec0448 +0x2b Com.CommonComponents.Tools.PerformanceTimer.sAddCheckPoint)

0012ec84 0cef7933 (MethodDesc 0x7c8da68 +0x8b Com.Product.Tickets.Ticket.OnInit)

0012ecb4 0cef7706 (MethodDesc 0x7d509e8 +0x6e Com.Product.App.RequestForm.OnInit)

0012ecf4 0cef766b (MethodDesc 0x7c8da58 +0x1b Com.Product.Tickets.Ticket.Init)

[ ]

---------









多少簡略化されたバージョンではありますが、すでにコールスタックを確認しています。 しかし、今ではコードを理解します。 例外の原因となったコードを見てみましょう。

07eff899 8b01 mov eax,dword ptr [ecx] ds:0023:00000000=????????







値は、ECXに含まれるアドレスのメモリから読み取られ、そこに(ECXで)表示されるように、ゼロ...



思いやりのあるjitコンパイラーによってx86プロセッサーの実行可能コードに変換されたResetIndexes関数を見てみましょう。 C#で関数コードを繰り返します。次に、アセンブラーコードと比較します。







  1. 内部 void ResetIndexes()
  2. {
  3. this .RecomputeCompareInfo();
  4. ifthis .indexes!= null
  5. {
  6. this .SetShadowIndexes();
  7. 試してみる
  8. {
  9. int count = this .shadowIndexes.Count;
  10. forint i = 0; i <count; i ++)
  11. {
  12. ((Index) this .shadowIndexes [i])。Reset();
  13. }
  14. }
  15. ついに
  16. {
  17. this .shadowIndexes = null ;
  18. }
  19. }
  20. }
*このソースコードは、 ソースコードハイライターで強調表示されました。




今windbgから分解します。 関数は小さいですが、アセンブラコードには2ページあります:(



0:000> !u

No value passed in, defaulting to EIP

Will print '>>> ' at address: 0x07eff899

Normal JIT generated code

[DEFAULT] [hasThis] Void System.Data.DataTable.ResetIndexes()

Begin 0x07eff838, size 0xc4

07eff838 push ebp

07eff839 mov ebp,esp

07eff83b sub esp,18h

07eff83e push edi

07eff83f push esi

07eff840 push ebx ; .

07eff841 mov dword ptr [ebp-8],0 ;

07eff848 mov dword ptr [ebp-14h],ecx ; "ebp-14h"

; DataTable,

; , this.

07eff84b mov ecx,dword ptr [ebp-14h]

07eff84e call 07eff420 (System.Data.DataTable.RecomputeCompareInfo) ; (3)

07eff853 mov eax,dword ptr [ebp-14h]

07eff856 cmp dword ptr [eax+2Ch],0 ; (4) if (this.indexes != null)

07eff85a jne 07eff863

07eff85c pop ebx

07eff85d pop esi

07eff85e pop edi

07eff85f mov esp,ebp

07eff861 pop ebp

07eff862 ret ; , indexes == null

07eff863 mov ecx,dword ptr [ebp-14h]

07eff866 call dword ptr ds:[4A634CCh] ; (6) this.LiveIndexes

07eff86c mov ebx,dword ptr [ebp-14h]

07eff86f lea edx,[ebx+30h] ; (6) this.indexes

07eff872 call 01003048 ; (6) indexes = LiveIndexes, ,

; -

; SetShadowIndexes,

; , ,

; .

07eff877 mov eax,dword ptr [ebp-14h] ; (9)

07eff87a mov dword ptr [ebp-18h],eax ; (9)

07eff87d mov ecx,dword ptr [eax+30h] ; (9) ECX shadowIndexes.

07eff880 mov eax,dword ptr [ecx] ; (9) :

; (9) (, [ecx]) -

; (9) MethodTable ,

07eff882 call dword ptr [eax+0D0h] ; (9) ,

; (9) 0xD0 -

; (9) , ArrayList.Count,

07eff888 mov ebx,eax ; (9) eax.

; (9) , 07eff877

; (9) -

; (9) int count = this.shadowIndexes.Count;

07eff88a xor edi,edi ;(10) int i = 0;

07eff88c cmp ebx,0 ;(10) ,

;(10) shadowIndexes.Count == 0.

07eff88f jle 07eff8cc

07eff891 mov eax,dword ptr [ebp-18h] ;(12)

07eff894 mov ecx,dword ptr [eax+30h] ;(12) ECX shadowIndexes.

07eff897 mov edx,edi

>>> 07eff mov eax,dword ptr [ecx] ;(12) MethodTable

;(12) shadowIndexes ( ArrayList)

07eff89b call dword ptr [eax+0A0h] ;(12) shadowIndexes[i]

07eff8a1 mov edx,eax

07eff8a3 mov ecx,8121B80h

07eff8a8 call mscorwks!JIT_ChkCastClass (791e381f) ;(12)

;(12) : ((Index)this.shadowIndexes[i])

07eff8ad mov esi,eax

07eff8af cmp dword ptr [esi],eax

07eff8b1 mov ecx,esi

07eff8b3 call dword ptr ds:[8121C44h] ;(12) Index.InitRecords();

07eff8b9 mov edx,dword ptr ds:[2208EC4h]

07eff8bf mov ecx,esi

07eff8c1 call dword ptr ds:[8121C54h] ;(12) Index.OnListChanged();

;(12) , Index.Reset(),

;(12)

;(12) InitRecords OnListChanged

;(12) ,



07eff8c7 inc edi ;(10) i++ for.

07eff8c8 cmp edi,ebx ;(10)

07eff8ca jl 07eff891 ;(10) - "i < count". .

;(10)

;(10) :

;(10) .

07eff8cc mov dword ptr [ebp-0Ch],0

07eff8d3 mov dword ptr [ebp-8],0FCh

07eff8da push 7EFF8EEh

07eff8df jmp 07eff8e1

07eff8e1 mov eax,dword ptr [ebp-14h]

07eff8e4 mov dword ptr [eax+30h],0 ;(17) shadowIndexes

;(17) finally.

07eff8eb pop eax

07eff8ec jmp eax

07eff8ee mov dword ptr [ebp-8],0

07eff8f5 pop ebx

07eff8f6 pop esi

07eff8f7 pop edi

07eff8f8 mov esp,ebp

07eff8fa pop ebp

07eff8fb ret







例外が生成される行には記号「>>>」が付けられており、非表示にするのはshadowIndexesリスト内の何らかのバグ要素ではなく、配列自体であることが明らかになります。ループを巻く過程で、shadowIndexesの値はnullになります。



犯人の特定は非常に簡単になりました。



DataTableフィールド(0x1990a1d4-これはこれと同じ、ECXからの値)を見てみましょう:

0:000> dd 0x1990a1d4 + 2c

1990a200 1990a80c 1990a80c 15b03c88 0142ea34

1990a210 00000000 011e11f4 00000000 00000000

1990a220 01200c24 00000000 00000000 00000000

1990a230 0124ca7c 155796bc 15579758 00000000

1990a240 00000000 00000000 155a4c5c 00000000

1990a250 00000000 00000000 00000000 00000000

1990a260 15ae8eec 00000000 00000000 1990a824

1990a270 1990a418 1990a480 1990a4e8 00000002








アドレス1990a200にはインデックス(オフセットが2のフィールド)があり、その隣にshadowIndexesがあります。 このメモリ領域のレコードにブレークポイントを設定ましょう。



0:000> ba w 4 1990a204







そして、プログラムを起動します。このプログラムは、いくつかの忘れられない瞬間の後、デバッガーに戻ります。 それで、確かに、私たちの興味のあるアドレスに特定の値が記録されました。



0:000> g

Breakpoint 12 hit

eax=1990a80c ebx=00000000 ecx=1990a80c edx=1990a204 esi=1990a1d4 edi=1990a1d4

eip=0100304a esp=0012e288 ebp=0012e2b4 iopl=0 nv up ei pl zr na pe nc

cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246

0100304a 81f81c825715 cmp eax,1557821Ch








現在の命令は「cmp eax、1557821Ch」であることがわかります。 一見、これは奇妙です。 このようなブレークポイントは、書き込みイベントの後にトリガーされるために表示されます。



!Clrstackコマンドは、リフレクション(System.Reflection.RuntimeMethodInfo.InternalInvokeスタックの最後のメソッドです。これはあまり役に立ちません)でいっぱいの呼び出しスタックを表示します。



dumpstackを使用します。



0:000> !dumpstack -ee

Thread 0

Current frame:

ChildEBP RetAddr Caller,Callee

0012e284 0814f725 (MethodDesc 0x4a631c0 +0x2d System.Data.DataTable.RecordStateChanged)

0012e2b4 08144d6d (MethodDesc 0x4a63280 +0x1c5 System.Data.DataTable.SetNewRecord)

0012e314 08145b29 (MethodDesc 0x812c488 +0x29 System.Data.DataRow.EndEdit)

0012e328 081458d9 (MethodDesc 0x812c3c8 +0x131 System.Data.DataRow.set_Item)

0012e348 03206651 (MethodDesc 0x812c3a8 +0x49 System.Data.DataRow.set_Item)

0012e360 0320bac2 (MethodDesc 0x7ec3760 +0x5a Com.Product.Core.Entities.EntityAdapter.DBAssign)

0012e394 2ea362d7 (MethodDesc 0x7ec3d90 +0x3f Com.Product.Core.Entities.Request.set_Price)

0012e3b8 2ea359ea (MethodDesc 0x7c8faa0 +0x252 Com.Product.App.RequestForm.UpdatePrice

0012e494 0cefdf89 (MethodDesc 0x7d50218 +0x1a1 Com.Product.App.RequestForm.panel1_RadioButtonsValueRealyChanged)


0012e4b0 7b8808cd (MethodDesc 0x7b9e38c8 +0x45 System.Windows.Forms.Control.AccessibilityNotifyClients)

0012e4c4 0cefd04c (MethodDesc 0xb989dd8 +0x4c Com.Product.CommonControls.DBControls.NullableRadioButtonsPanel.OnRadioButtonsValueReallyChanged)

0012e4e4 7b92a038 (MethodDesc 0x7ba1ea48 +0x68 System.Windows.Forms.RadioButton.set_Checked)

0012e4f0 0cefcda1 (MethodDesc 0xb989d78 +0x111 Com.Product.CommonControls.DBControls.NullableRadioButtonsPanel.set_RadioButtonsValue)

0012e760 799dd8c1 (MethodDesc 0x79bb1468 +0x141 System.Reflection.RuntimeMethodInfo.InternalInvoke)

0012e7a4 799dd768 (MethodDesc 0x79bb1458 +0x18 System.Reflection.RuntimeMethodInfo.Invoke)

0012e7bc 7b1f5c81 (MethodDesc 0x7b328e20 +0x139 System.ComponentModel.ReflectPropertyDescriptor.SetValue)

0012e810 7b8a1973 (MethodDesc 0x7ba38350 +0xd3 System.Windows.Forms.Binding.SetPropValue)

0012e82c 7b8a16d8 (MethodDesc 0x7ba38330 +0x50 System.Windows.Forms.Binding.FormatObject)

0012e840 7b8a1888 (MethodDesc 0x7ba38340 +0x38 System.Windows.Forms.Binding.PushData)

0012e848 7b8a311c (MethodDesc 0x7ba38938 +0x8c System.Windows.Forms.BindingManagerBase.PushData)

0012e85c 7b8bcde7 (MethodDesc 0x7ba38cf8 +0x37 System.Windows.Forms.CurrencyManager.CurrencyManager_PushData)

0012e87c 7b8a1996 (MethodDesc 0x7ba38350 +0xf6 System.Windows.Forms.Binding.SetPropValue)

0012e88c 7b8bdc33 (MethodDesc 0x7ba38df8 +0x5b System.Windows.Forms.CurrencyManager.OnItemChanged)

0012e8ac 7b8a1878 (MethodDesc 0x7ba38340 +0x28 System.Windows.Forms.Binding.PushData)

0012e8b4 7b8a1ad9 (MethodDesc 0x7ba38390 +0x59 System.Windows.Forms.Binding.UpdateIsBinding)

0012e8bc 7b8bdff0 (MethodDesc 0x7ba38e88 +0x110 System.Windows.Forms.CurrencyManager.UpdateIsBinding)

0012e8d0 7b8bdec8 (MethodDesc 0x7ba38e78 +0x8 System.Windows.Forms.CurrencyManager.UpdateIsBinding)

0012e8d4 7b8bd78c (MethodDesc 0x7ba38db8 +0x1c4 System.Windows.Forms.CurrencyManager.List_ListChanged)

0012e900 08181927 (MethodDesc 0x812ce50 +0x37 System.Data.DataView.OnListChanged)

0012e928 10c456ac (MethodDesc 0x812ce40 +0x34 System.Data.DataView.IndexListChanged)

0012e930 10525133 (MethodDesc 0x812ce30 +0x33 System.Data.DataView.FireEvent)

0012e940 10c45663 (MethodDesc 0x31fada0 +0x2b System.Data.DataViewListener.IndexListChanged)

0012e950 0814c5bc (MethodDesc 0x81219d0 +0x1c System.Data.Index.OnListChanged)

0012e958 07eff8c7 (MethodDesc 0x4a63200 +0x8f System.Data.DataTable.ResetIndexes)

0012e984 08186f34 (MethodDesc 0x31fcff0 +0x234 System.Data.Merger.MergeTable)

0012e9b0 08185790 (MethodDesc 0x31fd020 +0x48 System.Data.Merger.MergeTableData)

0012e9dc 0818e31f (MethodDesc 0x31fcfe0 +0x2f System.Data.Merger.MergeTable)

0012e9ec 0818e2b1 (MethodDesc 0x7ec0ce8 +0x61 System.Data.DataSet.Merge)

0012ea00 0cef8056 (MethodDesc 0x7c8f8d0 +0x61e Com.Product.App.RequestForm.InitEdit)

0012ec3c 26a117e7 (MethodDesc 0x10eaee98 +0x57 Com.Product.Core.Entities.EntityContextCache..ctor)

0012ec50 0cef79df (MethodDesc 0x7c8f8c0 +0x57 Com.Product.App.RequestForm.InitEdit)

0012ec74 0818d593 (MethodDesc 0x7ec0448 +0x2b Com.CommonComponents.Tools.PerformanceTimer.sAddCheckPoint)

0012ec84 0cef7933 (MethodDesc 0x7c8da68 +0x8b Com.Product.Tickets.Ticket.OnInit)

0012ecb4 0cef7706 (MethodDesc 0x7d509e8 +0x6e Com.Product.App.RequestForm.OnInit)

0012ecf4 0cef766b (MethodDesc 0x7c8da58 +0x1b Com.Product.Tickets.Ticket.Init)

....








まあ、実際には、犯人が見つかりました。 キー呼び出しはスタック上で強調表示されます。ResetIndexesはOnListChangedイベントを発生させ、UpdatePriceアプリケーションの関数を呼び出すバインダーにスムーズに流れます。 この関数は、偶然にも、データセット内のデータを変更するため、shadowIndexesの早期のゼロ化につながります。



sisharpaの技術的なナノハンマーでいくつかの動き、犯人は処罰され、プログラムが動作します。 やった!



All Articles