これは、susie 純正プラグイン全般で見られる有名なバグです。
この原因は、LocalFree() に間違った HLOCAL を渡しているために発生しています。
通常は「デバッグがしにくい」くらいであまり実害はありません。
lhasad.spi のコードを検討した結果、各 API の先頭で LocalAlloc() を使用しない「メモリ獲得関数」を呼び出し、 API の終了直前にその値を LocalFree() に渡しているのが原因と思われます。
またこのときに LocalFree() 渡される間違ったハンドルの多くは、プラグイン内で VirtualAlloc() されたブロック内のアドレスを指しています。これはおそらくライブラリの例えば malloc() などの関数が、その内部的に使用しているブロック内のアドレスなのではないかと予測しています。
このため、わずかずつメモリリークが発生しているのではないかと予測されます。
また、ごくまれに LocalAlloc() に HLOCAL として認識されてしまうような誤ったハンドルが渡ってしまう可能性があります。 この場合は予期しない結果を招くかも知れません。
WindowsNT の DEBUG 環境以外ではこのアサートは発生しませんが、 他の環境でもアサートが発生しないだけでこの問題は同様に発生しています。
これに対しては、通常の方法では具体的な対策はありません。
KLARAでは plug-in の LocalAlloc() / LocalReAlloc() / LocalFree() を独自に hook する事により HLOCAL を監視し、このエラーを検出しています。
ちなみに、なぜここまでしつこく調査したかというと、KLARA の開発初期の頃であったため、 プラグインよりも自作プログラムの方を遙かに疑っていたためです。 そのため、原因を特定するのにかなり多くの時間を割くことになったのでした。
以下に参考として KLARA が使用している LocalFree() のフックコードを示します。
残念なことに LocalFlags() に間違った HLOCAL を渡すと、やっぱり int 3 が発生してしまうので、 その頻度は減りますがアサートを回避することは出来ませんでした。 ただ、その原因を特定するのには大きく貢献しました。
なお、フック方法については、ここで扱う範囲を大きく逸脱するので説明はしません。
HLOCAL WINAPI WatchHLOCAL::iLocalFree( HLOCAL handle )
{
CString msg;
UINT flags;
if ( watchHLOCAL.isExistHandle( handle ) ){
if ( ( flags = ::LocalFlags( handle ) ) == LMEM_INVALID_HANDLE ){
msg.Format( "iLocalFree: invalid handle! (0x%08x)\n", handle );
Msg( msg );
} else {
VERIFY( watchHLOCAL.removeHandle( handle ) );
handle = ::LocalFree( handle );
ASSERT( handle == NULL );
}
} else {
if ( ( flags = ::LocalFlags( handle ) ) == LMEM_INVALID_HANDLE )
msg.Format( "iLocalFree: invalid and unknown handle! (0x%08x)\n", handle );
else {
msg.Format( "iLocalFree: free unknown handle! (0x%08x)\n", handle );
handle = ::LocalFree( handle );
ASSERT( handle == NULL );
}
Msg( msg );
}
return( handle );
}
HLOCAL WINAPI WatchHLOCAL::iLocalAlloc( UINT flags, UINT size )
{
HLOCAL handle = ::LocalAlloc( flags, size );
if ( handle )
watchHLOCAL.addHandle( handle, size );
return( handle );
}
HLOCAL WINAPI WatchHLOCAL::iLocalReAlloc( HLOCAL handle, UINT size, UINT flags )
{
VERIFY( watchHLOCAL.removeHandle( handle ) );
if ( handle = ::LocalReAlloc( handle, size, flags ) )
watchHLOCAL.addHandle( handle, size );
return( handle );
}
ここで生成されるメッセージを KLARA で確認するためには、
KLARA のレジストリ設定を次のように変更して下さい。
msgLevel キーはデフォルトでは設定されていませんので、キーを新規作成してください。
HKEY_CURRENT_USER\Software\HobbyTools\KLARA\settings\msgLevel = 8