最近公司有個項目使用的百度Carlife語音識別出現wavedev.dll報錯問題。根據經驗,這種報錯問題,一般都是指針越界或者stack over flow等錯誤。
於是根據wavedev.map文件定位到了midiNote.cpp的函數NoteOn中的數組PitchTable。可仔細分析這個函數以及這個數組,認爲怎麼都不可能導致內存越
界錯誤——PitchTable[ Note % 12 ],Note的值怎麼都不可能使得引用這個數組時越界。map文件的定位錯誤的方法有時——尤其是底層驅動層涉及到
硬件上下文的庫中,不管用!
爲了正確定位出報錯的位置,另闢思路,從應用層調用waveOutOpen、waveOutWrite函數開始,加入打印語句,一直追蹤這兩個API函數的調用過程,看
看哪個打印語句沒有打印出來,報錯的位置就很有可能出現在這個函數中!爲了調查這個問題,也同時將wave驅動的框架弄明白了——我有篇文章大致
介紹了waveOutOpen、waveOutWrite的調用過程。從這個過程中,可以看出PCM數據是如何從應用層流到驅動層的。
遵循着上面的思路,終於在函數OutputStreamContextNonPCM::Render2中定位到了異常:
1、wave驅動層的Render2函數在訪問用戶的PCM數據時,越界訪問!
2、這個函數聲明瞭太多的局部變量,導致stack over flow!
於是針對上面兩個錯誤,給出瞭如下兩個辦法:
1、在這個函數裏面訪問用戶數據之前,加入內存邊界檢查!例如:
if(m_WaveFormatEx.dwChannelMask & SPEAKER_FRONT_LEFT)
{
if (pCurrData16>=pCurrDataEnd16)//added by zhujw for check PCM data buffer valid
{
goto Exit;
}
pCurrSamp0[0] = *pCurrData16;
pCurrData16++;
}
2、將所有佔用內存較大的局部變量,全部改爲在heap中分配內存。
#if 1 //must use new heap memory .....comment by zhujw 20170630
LONG *pCurrSamp0 = new LONG[MAXDADONUM];
LONG *pCurrSamp1 = new LONG[MAXDADONUM];
LONG *pPrevSamp0 = new LONG[MAXDADONUM];
LONG *pPrevSamp1 = new LONG[MAXDADONUM];
LONG *pOutSamp0 = new LONG[MAXDADONUM];
LONG *pOutSamp1 = new LONG[MAXDADONUM];
#else//if use stack memory,it will be 'Data Abort'....comment by zhujw 20170630
LONG CurrSamp0[MAXDADONUM];
LONG CurrSamp1[MAXDADONUM];
LONG PrevSamp0[MAXDADONUM];
LONG PrevSamp1[MAXDADONUM];
LONG OutSamp0[MAXDADONUM];
LONG OutSamp1[MAXDADONUM];
#endif
至此,經過測試,問題完美解決!