browser icon
You are using an insecure version of your web browser. Please update your browser!
Using an outdated browser makes your computer unsafe. For a safer, faster, more enjoyable user experience, please update your browser today or try a newer browser.

MFC 4.2 中 CFileDialog 的一处崩溃隐患

Posted by on 2010 年 07 月 09 日

你可以任意转载本文,但请在转载后的文章中注明作者和原始链接。
媒体约稿请联系 titilima_AT_163.com(把“_AT_”换成“@”)。

CFileDialog 是 MFC 对 OPENFILENAME 及 GetOpenFileName/GetSaveFileName 的封装。在 VC6(MFC 4.2)之中,其定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CFileDialog : public CCommonDialog
{
    DECLARE_DYNAMIC(CFileDialog)
 
public:
// Attributes
    OPENFILENAME m_ofn; // open file parameter block
 
// Constructors
    CFileDialog(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
        LPCTSTR lpszDefExt = NULL,
        LPCTSTR lpszFileName = NULL,
        DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
        LPCTSTR lpszFilter = NULL,
        CWnd* pParentWnd = NULL);
 
// Operations
    virtual int DoModal();
// …
};

让我们来看看这处隐藏得极深的崩溃,先从 OPENFILENAME 的定义开始:

1
2
3
4
5
6
7
8
typedef struct tagOFN {
  // …
#if (_WIN32_WINNT >= 0×0500)
  void *        pvReserved;
  DWORD         dwReserved;
  DWORD         FlagsEx;
#endif // (_WIN32_WINNT >= 0×0500)
} OPENFILENAME, *LPOPENFILENAME;

也就是说,随着 _WIN32_WINNT 定义的不同,OPENFILENAME 的大小将是不同的。又由于 OPENFILENAME 是 CFileDialog 的一个成员变量,所以在 OPENFILENAME 之后定义的成员变量偏移量也有可能是不同的。
更糟糕的是,CFileDialog 没有实现析构函数,这就意味着当我们在代码中使用 CFileDialog 的时候,编译器将会为其实现一个默认的析构函数。
好了,现在我们来看看 MFC42D.dll 之中,CFileDialog 构造函数的汇编代码:

1
2
3
mov     ecx, [ebp+this]
add     ecx, 0B0h       ; offset of m_strFilter
call    ??0CString@@QAE@XZ_0 ; CString::CString(void)

而编译器实现的析构函数是:

1
2
3
mov     ecx,dword ptr [ebp-10h]
add     ecx,offset <Unloaded_RT40.dll>+0xbb (000000bc) ; oops!!
call    MaxDU!CString::~CString (006b29b2)

如你所见,当应用程序代码与 MFC42D.dll 的 _WIN32_WINNT 不一致的时候,在析构 m_strFilter 的时候将导致崩溃。

最新的 MFC 代码将 OPENFILENAME 修改成为了指针成员,解决了此问题。

订阅本站

2 Comments

(Required)
(Required, will not be published)