【发布时间】:2015-04-03 02:55:25
【问题描述】:
我们有一个相当旧的代码库,我们正在迁移到 64 位以利用一些新的 3rd 方 64 位工具。我们在 Windows 7 上运行,使用 VS2010,代码用 C++ 编写。
过去两天,我们试图找出一个成员变量未设置为预期值的问题。使用 VS2010 内存调试器,我们能够看到成员变量内存位置偏移了四个字节。一些研究引导我们使用 struct 对齐和 64 位。
原来类中定义的第一个变量是一个 32 位整数,第二个变量是一个指针。如果我们将指针移到类的顶部,则所有成员变量都正确对齐。这解决了问题。
我们还注意到
- 在类的顶部添加一个四字节缓冲区“修复”了问题
- 将包对齐设置为四个字节也“修复”了该问题。
问题是,您如何检测这些错误?我们将警告级别设置为 EnabelAllWarnings 并尝试了几个静态 c++ 分析器,但都没有成功。
发生这种情况的一个例子。由于保密协议,我无法显示另一个。
class CTaskBar
{
public:
bool CreateTaskbarIcon( HWND hWnd,
HINSTANCE hInstance,
UINT unNotifyMessage,
UINT unIcon,
LPCTSTR szCaption)
{
if (hWnd == NULL)
return false;
if (hInstance == NULL)
return false;
m_hWnd = hWnd;
m_hInstance = hInstance;
m_NIDTaskbarIconData.cbSize = sizeof(NOTIFYICONDATA);
m_NIDTaskbarIconData.hWnd = m_hWnd;
m_NIDTaskbarIconData.uID = IDI_TASKBARICON;
if ( unIcon ) {
if ( m_hTaskbarIcon )
DestroyIcon( m_hTaskbarIcon );
m_hTaskbarIcon = ::LoadIcon( m_hInstance, MAKEINTRESOURCE( unIcon ) );
m_NIDTaskbarIconData.hIcon = m_hTaskbarIcon;
m_NIDTaskbarIconData.uFlags |= NIF_ICON;
}
if ( unNotifyMessage ) {
m_NIDTaskbarIconData.uCallbackMessage = unNotifyMessage;
m_NIDTaskbarIconData.uFlags |= NIF_MESSAGE;
}
if ( szCaption ) {
strcpy(m_NIDTaskbarIconData.szTip, szCaption);
m_NIDTaskbarIconData.uFlags |= NIF_TIP;
}
// The Shell_NotifyIcon call will add the icon to the task bar.
if ( Shell_NotifyIcon(NIM_ADD, &m_NIDTaskbarIconData) )
return true;
return false;
}
private:
NOTIFYICONDATA m_NIDTaskbarIconData;
HINSTANCE m_hInstance;
HWND m_hWnd;
HMENU m_hTaskbarMenu;
HICON m_hTaskbarIcon;
};
基本上,应用程序在 Windows API 调用深处的 Shell_NotifyIcon 处崩溃。如果我们查看内存调试器,我们可以看到内存被设置,但偏移了四个字节。如果我将 m_NIDTaskbarIconData 移动到 m_hTaskbarIcon 之后。在内存调试器中一切看起来都是正确的,没有崩溃。
【问题讨论】:
-
当你编译为 64 位时,所有带有指针的结构都应该至少对齐到 8 个字节。是否正在进行一些编译指示包装? (编辑:哦,我刚看到你的第二颗子弹。正在打包。)
-
这对我来说闻起来像是未定义的行为(甚至可能违反了一个定义规则),如果是这种情况,静态检查器通常很难检测到。您能否提供有关该问题的更多具体细节?
-
@Mysticial 从某种意义上说,我们知道我们可以设置它并且事情似乎会自行解决,因此正在打包。这两个应用程序都进行了一些打包,因为它们通过 TCP 发送和接收二进制打包消息。当我们意识到设置打包让事情消失时,我们确实回顾了使用打包的单个头文件以确保在底部重置打包,并使用 #pragma pack(show) 重新检查以进行验证。
-
我没有看到好的信号。也许没有完全初始化 NOTIFYICONDATA 并且没有使用 NIM_SETVERSION。如果它实际上在 shell 内崩溃,那么你有一个很好的提示,它正在访问已释放的内存,或者你现在正在目睹 32 位中已经存在的潜在堆损坏问题的副作用版本。
标签: c++ visual-studio-2010 64-bit