Re: CheckSoundMemで稀に不正アクセスを起こす ( No.1 ) |
- 名前:管理人 日時:2023/08/29 02:11
CheckSoundMem で不正アクセスが発生するといったお話は初めてですね… (・・;
幾つかご質問させてください
1.SetUseASyncLoadFlag を常に FALSE にした場合は不正アクセスは発生しないでしょうか?
2.SetEnableXAudioFlag( TRUE ); や SetEnableWASAPIFlag( FALSE ); 等で使用するサウンドAPIを変更していますでしょうか?
3.(『2』のご返答が『No』だった場合)、SetEnableXAudioFlag( TRUE ); を DxLib_Init() の呼び出し前に実行して使用APIを XAudio に変更した場合は不正アクセスは発生しないでしょうか?
4.複数のスレッドからDXライブラリの関数を呼んでいますでしょうか?
質問の数が多くてすみません m(_ _;m
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.2 ) |
- 名前:タニシン 日時:2023/08/29 19:36
> 1.SetUseASyncLoadFlag を常に FALSE にした場合は不正アクセスは発生しないでしょうか?
20回ほど試しましたが、今のところ発生しないです
ちなみに非同期処理の場合では体感で1〜2%の割合で不正アクセスが発生しています
> 2.SetEnableXAudioFlag( TRUE ); や SetEnableWASAPIFlag( FALSE ); 等で使用するサウンドAPIを変更していますでしょうか?
いいえ、どちらの関数も使っている箇所はなかったです
> 3.(『2』のご返答が『No』だった場合)、SetEnableXAudioFlag( TRUE ); を DxLib_Init() の呼び出し前に実行して使用APIを XAudio に変更した場合は不正アクセスは発生しないでしょうか?
こちらも不正アクセスが発生しました
> 4.複数のスレッドからDXライブラリの関数を呼んでいますでしょうか?
いいえ、シングルスレッドで動作させています
確認ですが、
CheckSoundMem に渡すハンドルは -1 の状態でも良いでしょうか?
今も試しているのですが、デバッグで見る限りどうやら非同期読み込み中のハンドルがあってそのハンドルが -1 の時に不正アクセスが発生するようです
(発生しない場合もあるので必ずではないではないようです)
試しに -1 を直渡しした場合も試しましたがこちらは一度も発生しなかったです
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.3 ) |
- 名前:管理人 日時:2023/08/30 04:35
ご返答ありがとうございます
SetUseASyncLoadFlag を FLASE にすると不正アクセスは発生しないですか…
手元でこのようなテストプログラムを組んでみたのですが、何ループしても
不正アクセスが発生することはありませんでした
#include "DxLib.h"
#define NUM 3
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
int LoopCount = 0 ;
int Handle[ NUM ] = { 0 } ;
// ウインドウモードで起動
ChangeWindowMode( TRUE ) ;
// DXライブラリの初期化
if( DxLib_Init() < 0 ) return -1 ;
// 非同期読み込みON
SetUseASyncLoadFlag( TRUE ) ;
// 描画先を裏画面に変更
SetDrawScreen( DX_SCREEN_BACK ) ;
// メインループ
while( ProcessMessage() == 0 )
{
// 画面をクリア
ClearDrawScreen() ;
// oggファイルを非同期読み込み開始
for( int i = 0 ; i < NUM ; i ++ )
{
Handle[ i ] = LoadSoundMem( "Test.ogg" ) ;
}
// CheckSoundMem を実行
for( int i = 0 ; i < NUM ; i ++ )
{
CheckSoundMem( Handle[ i ] ) ;
}
// サウンドハンドルを削除
for( int i = 0 ; i < NUM ; i ++ )
{
DeleteSoundMem( Handle[ i ] ) ;
}
// ループ回数を描画
LoopCount++ ;
DrawFormatString( 0, 0, GetColor( 255,255,255 ), "Loop : %d", LoopCount ) ;
// 裏画面の内容を表画面に反映
ScreenFlip() ;
}
// DXライブラリの後始末
DxLib_End() ;
// ソフトの終了
return 0 ;
}
よろしければ上記のプログラムであればタニシンさんの環境でも不正アクセスが発生しないか
お試し頂けないでしょうか? m(_ _)m
( すみません、Test.ogg の部分はお手持ちの ogg ファイルに置き換えてください )
> CheckSoundMem に渡すハンドルは -1 の状態でも良いでしょうか?
はい、-1 の場合は CheckSoundMem に入って直ぐの部分で return -1 ; で
関数から出ることになるので、問題ありません
> 今も試しているのですが、デバッグで見る限りどうやら非同期読み込み中のハンドルがあってそのハンドルが -1 の時に不正アクセスが発生するようです
うーん
それはありえない筈ですが…
CheckSoundMem のプログラムの冒頭部分はこのようになっていまして
// メモリに読みこんだWAVEデータが再生中か調べる
extern int NS_CheckSoundMem( int SoundHandle )
{
SOUND * Sound ;
int i ;
if( CheckSoundSystem_Initialize_PF() == FALSE )
{
return -1 ;
}
// エラー判定
if( SOUNDHCHK( SoundHandle, Sound ) )
return -1 ;
『SOUNDHCHK( SoundHandle, Sound )』の部分のマクロを展開すると以下のようになっていまして
( ( HandleManageArray[ (DX_HANDLETYPE_SOUND) ].InitializeFlag == FALSE ) ||
( ( (SoundHandle) & DX_HANDLEERROR_MASK ) != 0 ) ||
( ( (SoundHandle) & DX_HANDLETYPE_MASK ) != HandleManageArray[ (DX_HANDLETYPE_SOUND) ].HandleTypeMask ) ||
( ( (SoundHandle) & DX_HANDLEINDEX_MASK ) >= HandleManageArray[ (DX_HANDLETYPE_SOUND) ].MaxNum ) ||
( ( *( ( HANDLEINFO ** )&Sound ) = HandleManageArray[ (DX_HANDLETYPE_SOUND) ].Handle[ (SoundHandle) & DX_HANDLEINDEX_MASK ] ) == NULL ) ||
( (int)( (*( ( HANDLEINFO ** )&Sound ))->ID << DX_HANDLECHECK_ADDRESS ) != ( (SoundHandle) & DX_HANDLECHECK_MASK ) ) ||
( (*( ( HANDLEINFO ** )&Sound ))->ASyncLoadCount != 0 && ( MainThreadProcessASyncLoadData( (*( ( HANDLEINFO ** )&Sound ))->ASyncDataNumber ) < 0 || HandleManageArray[ (DX_HANDLETYPE_SOUND) ].Handle[ (SoundHandle) & DX_HANDLEINDEX_MASK ] == NULL ) ) )
2行目の ( (SoundHandle) & DX_HANDLEERROR_MASK ) != 0 がマイナスチェックとなっていまして、
ハンドル値がマイナスの場合は return -1 ; で関数から出るようになっていますので…
( || 演算子なので、2行目が真になった場合は、3行目以降の式は評価されません )
また、1行目の HandleManageArray[ (DX_HANDLETYPE_SOUND) ].InitializeFlag は
DX_HANDLETYPE_SOUND は 3 なので、HandleManageArray[ 3 ].InitializeFlag となり、
HandleManageArray は HANDLEMANAGE HandleManageArray[ 32 ] ; となっていますので、
やはりメモリの不正なアクセスは発生しえません…
その他、関数冒頭の CheckSoundSystem_Initialize_PF() ですが、実装は以下のようになっていまして
// サウンドシステムの初期化チェックの環境依存処理を行う関数( TRUE:初期化されている FALSE:初期化されていない )
int CheckSoundSystem_Initialize_PF( void )
{
return SoundSysData.PF.DirectSoundObject == NULL ? FALSE : TRUE ;
}
グローバル変数の値を参照するだけなので、やはりメモリの不正なアクセスが発生する余地はありません
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.4 ) |
- 名前:タニシン 日時:2023/09/07 20:54
返信が遅くなりすみません。
いただいたソースで実行したところ、エラーは発生しませんでした。
ただ、デバッグをしていて分かったことがあり、2の処理がエラーの根本と思っています。
1. CheckSoundMem が -1 以外でも不正アクセスが発生する場合がありました。
2. CheckSoundMem を呼び出すところまではいけているようで、その後の MainThreadProcessASyncLoadData(int) で不正アクセスを起こしているようでした。
こちらの関数は内部で呼び出しているものだと思いますが、何をしている処理なのでしょうか?
-----------
別件ですが、少し気になりまして。
大きめのサイズのファイルを読み込んで削除するまでの流れは非同期でも多少待つのですが、
この処理を完全に非同期にする(LoopCountを常に増やす)方法はありますでしょうか?
恐らく現在 DeleteSoundMem が同期処理だと思っていて、Load処理と同様に非同期でも動かせるようになったら滑らかにできるなと思いました。
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.5 ) |
- 名前:管理人 日時:2023/09/09 00:37
> 1. CheckSoundMem が -1 以外でも不正アクセスが発生する場合がありました。
了解です
-1 の場合は No.3 のご説明の通り必ず CheckSoundMem の処理の中で弾かれるはずなので、
-1 以外の場合の方が不正アクセスが発生したというお話としては自然です
> 2. CheckSoundMem を呼び出すところまではいけているようで、その後の MainThreadProcessASyncLoadData(int) で不正アクセスを起こしているようでした。
> こちらの関数は内部で呼び出しているものだと思いますが、何をしている処理なのでしょうか?
MainThreadProcessASyncLoadData は非同期読み込みを行っているハンドルの非同期読み込みが終わるまで待つ関数です
CheckSoundMem は非同期読み込み中には実行できない関数なので、非同期読み込み中に CheckSoundMem が
呼ばれた場合は内部で MainThreadProcessASyncLoadData が呼ばれて、非同期読み込みが終わるまで待ちます
> 大きめのサイズのファイルを読み込んで削除するまでの流れは非同期でも多少待つのですが、
> この処理を完全に非同期にする(LoopCountを常に増やす)方法はありますでしょうか?
> 恐らく現在 DeleteSoundMem が同期処理だと思っていて、Load処理と同様に非同期でも動かせるようになったら滑らかにできるなと思いました。
DeleteSoundMem も同期処理ですが、前述の通り CheckSoundMem も同期処理なので、DeleteSoundMem だけ非同期にしても
CheckSoundMem で同期することになります
不正アクセスが発生しているところを直接確認できれば原因を直ぐに突き止めることができると思いますので、
よろしければ不正アクセスが発生してしまうプロジェクトを丸ごと( 若しくは不正アクセスの再現に必要の無い
データやプログラムを削除した上で )zip圧縮して頂き、こちらのメールアドレス
BQE00322(あっとまーく)nifty.com
( (あっとまーく) は @ に置き換えてください )
に送って頂けないでしょうか? m(_ _;m
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.6 ) |
- 名前:タニシン 日時:2023/09/11 00:11
プロジェクトをお送りしましたので、ご確認お願いいたします。
> MainThreadProcessASyncLoadData は非同期読み込みを行っているハンドルの非同期読み込みが終わるまで待つ関数です
ご回答ありがとうございます。
結構長く触れていても知らない関数が出てくるので、奥深いなと思います。
> DeleteSoundMem も同期処理ですが、前述の通り CheckSoundMem も同期処理なので、DeleteSoundMem だけ非同期にしても
> CheckSoundMem で同期することになります
CheckSoundMem も同期処理でしたか。
両方を非同期にできれば(もしくは非同期用の関数を作る等で)個人的に望む動作ができる箇所があるのですが、こちらの対応は難しそうでしょうか。
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.7 ) |
- 名前:管理人 日時:2023/09/12 03:33
メールありがとうございます
送っていただいたプロジェクトで手元の環境でも不正アクセスが再現できました
No.3 でご説明した
( ( HandleManageArray[ (DX_HANDLETYPE_SOUND) ].InitializeFlag == FALSE ) ||
( ( (SoundHandle) & DX_HANDLEERROR_MASK ) != 0 ) ||
( ( (SoundHandle) & DX_HANDLETYPE_MASK ) != HandleManageArray[ (DX_HANDLETYPE_SOUND) ].HandleTypeMask ) ||
( ( (SoundHandle) & DX_HANDLEINDEX_MASK ) >= HandleManageArray[ (DX_HANDLETYPE_SOUND) ].MaxNum ) ||
( ( *( ( HANDLEINFO ** )&Sound ) = HandleManageArray[ (DX_HANDLETYPE_SOUND) ].Handle[ (SoundHandle) & DX_HANDLEINDEX_MASK ] ) == NULL ) ||
( (int)( (*( ( HANDLEINFO ** )&Sound ))->ID << DX_HANDLECHECK_ADDRESS ) != ( (SoundHandle) & DX_HANDLECHECK_MASK ) ) ||
( (*( ( HANDLEINFO ** )&Sound ))->ASyncLoadCount != 0 && ( MainThreadProcessASyncLoadData( (*( ( HANDLEINFO ** )&Sound ))->ASyncDataNumber ) < 0 || HandleManageArray[ (DX_HANDLETYPE_SOUND) ].Handle[ (SoundHandle) & DX_HANDLEINDEX_MASK ] == NULL ) ) )
↑
こちらの最後の行の部分に誤りがありました
ASyncDataNumber は -1 になることがあるのですが、この処理は -1 になることを想定したものとなっておらず
MainThreadProcessASyncLoadData に -1 が渡されることで内部でメモリの不正なアクセスが発生していました
修正後は以下のようになっています
( (*( ( HANDLEINFO ** )&Sound ))->ASyncLoadCount != 0 && ( ( ( (*( ( HANDLEINFO ** )&Sound ))->ASyncLoadCount > 1 || (*( ( HANDLEINFO ** )&Sound ))->ASyncDataNumber < 0 ) ? WaitASyncLoad( (SoundHandle) ) : ( MainThreadProcessASyncLoadData( (*( ( HANDLEINFO ** )&Sound ))->ASyncDataNumber ) ) ) < 0 || HandleManageArray[ (DX_HANDLETYPE_SOUND) ].Handle[ (SoundHandle) & DX_HANDLEINDEX_MASK ] == NULL ) ) )
上記修正を施した後は再現手順を何回繰り返しても不正アクセスは発生しませんでしたので
直ったかと思います
こちらに修正版をアップしましたので、よろしければお試しください m(_ _;m
https://dxlib.xsrv.jp/temp/DxLibVCTest.zip // Windows版 VisualC++ 用
https://dxlib.xsrv.jp/temp/DxLibBCCTest.zip // Windows版 BorlandC++ 用
https://dxlib.xsrv.jp/temp/DxLibBCC2Test.zip // Windows版 C++ Builder 11.3 用
https://dxlib.xsrv.jp/temp/DxLibGCC_MinGWTest.zip // Windows版 MinGW 用
https://dxlib.xsrv.jp/temp/DxLibDotNet.zip // Windows版 .NET用
https://dxlib.xsrv.jp/temp/DxLibMakeTest.zip // ソース
(中身を既存のライブラリのファイルに上書きして『リビルド』をして下さい)
> CheckSoundMem も同期処理でしたか。
> 両方を非同期にできれば(もしくは非同期用の関数を作る等で)個人的に望む動作ができる箇所があるのですが、こちらの対応は難しそうでしょうか。
CheckSoundMem は CheckHandleASyncLoad の戻り値が TRUE だった場合は非同期読み込みはまだ完了していないとして
FALSE を返すようなラッパー関数を作ることで現状でも非同期にすることはできます
( CheckHandleASyncLoad は非同期なので )
int CheckSoundMemASync( int SoundHandle )
{
if( CheckHandleASyncLoad( SoundHandle ) == TRUE )
{
return FALSE;
}
return CheckSoundMem( SoundHandle );
}
DeleteSoundMem の非同期は実装可能かもしれませんが、内部では引き続き処理が行われるので、例えば仮に
1.大量のサウンドを非同期読み込み開始
↓
2.読み込みが終わる前に1のサウンドが不要になったので全て非同期DeleteSoundMem で削除
↓
3.別の大量のサウンドを非同期読み込み開始
↓
4.2に戻る
上記のような『大量の非同期読み込み』と『大量の非同期読み込み完了前非同期削除』を繰り返すと
処理が追いつかずどんどんメモリ使用容量が増えてしまうという状態になりますので、
GetASyncLoadNum() の戻り値( 非同期処理を行っている数 )が一定上の値になったら
while( ProcessMessage() == 0 && GetASyncLoadNum() > 50 )
{
SleepThread( 1 );
}
↑
このような処理で非同期処理の抑制を行う必要が発生しますが、それでも非同期DeleteSoundMem があったら使われますでしょうか?
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.8 ) |
- 名前:タニシン 日時:2023/09/12 20:56
ご対応いただきありがとうございます。
ダウンロードして、今のところ不正アクセスが発生していませんので大丈夫かなと思います。
ただ、動作の影響はないですがビルド時に以下のような文言が出てきましたのでご確認いただきたいです。
C:\DxLib_VC\プロジェクトに追加すべきファイル_VC用\DxLib.h(4870,1): warning C4819: ファイルは、現在のコード ページ (932) で表示できない文字を含んでいます。データの損失を防ぐために、ファイルを Unicode 形式で保存してください。
> CheckSoundMem は CheckHandleASyncLoad の戻り値が TRUE だった場合は非同期読み込みはまだ完了していないとして
> FALSE を返すようなラッパー関数を作ることで現状でも非同期にすることはできます
> ( CheckHandleASyncLoad は非同期なので )
有用なコードだと思いますので、後で試してみます。
> このような処理で非同期処理の抑制を行う必要が発生しますが、それでも非同期DeleteSoundMem があったら使われますでしょうか?
あったら使います。
私自身は同時に非同期DeleteSoundMemをする予定のハンドル数が少ない(10前後)ので大丈夫だと思います。
一つ案を出しますと、非同期DeleteSoundMem は引数に「GetASyncLoadNumの上限値」を持つようにして内部でGetASyncLoadNumを呼び出し、
引数値の上限を超えていたら同期処理を行う内容にすれば抑制を考えなくても良いかと思いますがいかがでしょうか?
普段は GetASyncLoadNumの上限値を意識しないで済むように初期値を設定してみても良いかもしれません。
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.9 ) |
- 名前:管理人 日時:2023/09/13 13:07
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.10 ) |
- 名前:タニシン 日時:2023/09/14 00:05
ありがとうございます。
いただいたバージョンで警告が出なくなりました。
> DeleteSoundMem の非同期化は少し作業時間が掛かるのですが、平日はその時間が確保できないので
> 次の週末にその作業を行います、なので実装完了は少しお待ちください m(_ _)m
承知しました。
急ぎではないので、お時間あるときにお願いいたします。
> ご提案ありがとうございます
> その案を採用させていただきます( 初期値は -1 にして、内部で -1 の場合はデフォルト値( 100 )を適用するなど )
ありがとうございます。
それができるならば今まで通りの処理方法で簡単に使いこなせると思いますので助かります。
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.11 ) |
- 名前:管理人 日時:2023/09/16 08:22
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.12 ) |
- 名前:タニシン 日時:2023/09/17 07:26
処理を追加いただきありがとうございます。
以下のようなコード順序で非同期時のみアクセス違反が発生しましたので、ご確認をお願いしたいです。
(png画像を読み込んでもし存在しなければjpg画像を読み込むというものですが、確認のためのDrawGraphで不正アクセスが発生しました)
{
GrHandle.Set(LoadGraph(FileNamePng));
}
// 読み込めなかったらJPEGで読み込み
if (DrawGraph(0, 0, GrHandle.Get(), TRUE) == -1) { // 不正アクセス検知
GrGandle.Set(LoadGraph(FileNameJpg));
}
また、以下の部分で先日と同様に半角スペース対応が必要そうですので、ご確認お願いいたします。
DxLib.h(2989,1)
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.13 ) |
- 名前:管理人 日時:2023/09/17 14:17
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.14 ) |
- 名前:タニシン 日時:2023/09/17 18:43
修正版を試しましたが、同様の箇所で不正アクセスが発生してしまいます。
半角スペースの警告はなくなりました。
ご確認よろしくお願いいたします。
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.15 ) |
- 名前:管理人 日時:2023/09/17 23:31
エラーが発生してしまいましたか… (・・;
手元ではこちらのようなプログラムでエラーが発生しないことを確認しました
#include "DxLib.h"
#define NUM 3
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
int Handle[ NUM ] = { 0 } ;
int i ;
// ウインドウモードで起動
ChangeWindowMode( TRUE ) ;
// DXライブラリの初期化
if( DxLib_Init() < 0 ) return -1 ;
// 描画先を裏画面に変更
SetDrawScreen( DX_SCREEN_BACK ) ;
// メインループ
while( ProcessMessage() == 0 )
{
// 画面をクリア
ClearDrawScreen() ;
for( i = 0; i < NUM; i ++ )
{
if( DrawGraph( 0, 0, Handle[ 0 ], FALSE ) < 0 )
{
Handle[ i ] = LoadGraph( "Test.bmp" ) ;
}
}
for( i = 0 ; i < NUM ; i ++ )
{
DeleteGraph( Handle[ i ] ) ;
}
// 裏画面の内容を表画面に反映
ScreenFlip() ;
}
// DXライブラリの後始末
DxLib_End() ;
// ソフトの終了
return 0 ;
}
よろしければタニシンさんの環境では上記のプログラムでも不正なメモリのアクセスが
発生してしまうか試していただけないでしょうか? m(_ _;m
( プログラム中にある "Test.bmp" の部分はお手元にある画像ファイル名に変更してください )
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.16 ) |
- 名前:タニシン 日時:2023/09/18 00:30
いただいたプログラムでは再現しませんでした。
(DrawGraphの第四引数をTRUEにしても正常でした)
以前お送りしたプロジェクトを同様の手順で行えば再現できると思いますので、
恐れ入りますが、管理人さんのほうでもお試しいただけないでしょうか?
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.17 ) |
- 名前:管理人 日時:2023/09/18 23:30
|
Re: CheckSoundMemで稀に不正アクセスを起こす ( No.18 ) |
- 名前:タニシン(解決) 日時:2023/09/19 23:56
最新版でエラーが解消されました。
他にもエラーパターンがあるかもしれないので、
何かありましたらまたご相談したいと思います。
ありがとうございました。
|