版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433460
mgncs(1.2.0) 的ncsCreateModalDialogFromID
函数存在一个隐患,原代码很简单,如下:
int ncsCreateModalDialogFromID (HPACKAGE package, Uint32 dlgId,
HWND owner, HICON hIcon, HMENU hMenu,
NCS_EVENT_HANDLER_INFO* handlers, NCS_EVENT_CONNECT_INFO* connects)
{
int ret = 0;
mDialogBox * dialog = SAFE_CAST(mDialogBox,
ncsCreateMainWindowIndirectFromID(package, dlgId, owner, hIcon, hMenu, handlers, connects, 0));
if (dialog) {
ret = _c(dialog)->doModal(dialog, TRUE);
MainWindowThreadCleanup(dialog->hwnd);
}
return ret;
}
上面的代码中在调用doModal
成员函数后,又调用MainWindowThreadCleanup
函数清除主窗口所使用的消息队列,内存等系统资源,看着好像没错。
下面是MiniGUI中MainWindowThreadCleanup
函数的实现代码,可以看到函数最后释放了hMainWnd
(pWin)指向的内存,这也没错:
void GUIAPI MainWindowThreadCleanup (HWND hMainWnd)
{
PMAINWIN pWin = (PMAINWIN)hMainWnd;
_MG_PRINTF ("GUI>Window: MainWindowThreadCleanup called: %p (%s)n", pWin, pWin->spCaption);
if (!MG_IS_DESTROYED_WINDOW (hMainWnd)) {
_MG_PRINTF ("GUI>Window: Unexpected calling of "
"(MainWindowThreadCleanup); Window (%p) "
"not destroyed yet!n", hMainWnd);
return;
}
#ifdef _MGRM_THREADS
if (pWin->pHosting == NULL) {
mg_FreeMsgQueueThisThread ();
_MG_PRINTF ("GUI>Window: Message queure is freed: %p (%s)n", pWin, pWin->spCaption);
}
#endif
#ifdef __THREADX__
/* to avoid threadx keep pWin's value,which will lead to wrong way */
memset (pWin, 0xcc, sizeof(MAINWIN));
#endif
free (pWin);
}
但是如果进一步剖析doModal
成员函数的代码,就会发现当doModal
的bAutoDestroy
参数为TRUE时,会在doModal
结束的时候调用MainWindowThreadCleanup
函数。
下面是doModal
成员函数的实现代码节选:
static DWORD mMainWnd_doModal(mMainWnd*self, BOOL bAutoDestroy)
{
HWND hwnd;
IncludeWindowStyle(self->hwnd, NCSS_MNWND_MODE);
// 。。。。
hwnd = self->hwnd;
// 。。。。
if((GetWindowStyle(self->hwnd)&NCSS_MNWND_MODE) && bAutoDestroy)
{
HWND hwnd = self->hwnd;
//destroy
DestroyMainWindow(self->hwnd);
// 本文作者注:MainWindowCleanup 为宏定义,等价于MainWindowThreadCleanup
MainWindowCleanup(hwnd);
}
else
{
ExcludeWindowStyle(self->hwnd, NCSS_MNWND_MODE);
}
return ret;
}
那么问题就来了:bAutoDestroy
为TRUE调用doModal
成员函数之后,dialog->hwnd
指向的内存已经被释放,dialog->hwnd
已经是个野指针(wild pointer),再调用MainWindowThreadCleanup
函数就可能会产生不可预知的后果。
所以ncsCreateModalDialogFromID
函数中调用doModal
成员函数之后,就没有必要也不能再调用MainWindowThreadCleanup
函数,删除之就可以解决这个隐患。修正的代码如下:
int ncsCreateModalDialogFromID (HPACKAGE package, Uint32 dlgId,
HWND owner, HICON hIcon, HMENU hMenu,
NCS_EVENT_HANDLER_INFO* handlers, NCS_EVENT_CONNECT_INFO* connects)
{
int ret = 0;
mDialogBox * dialog = SAFE_CAST(mDialogBox,
ncsCreateMainWindowIndirectFromID(package, dlgId, owner, hIcon, hMenu, handlers, connects, 0));
if (dialog) {
ret = _c(dialog)->doModal(dialog, TRUE);
}
return ret;
}