【问题标题】:CToolBar MFC 64-bit crash when it runs on 32-bitCToolBar MFC 64 位在 32 位上运行时崩溃
【发布时间】:2020-03-17 05:41:08
【问题描述】:

我有一个 c++98 应用程序,它可以在 32 位中正常工作。但在 64 位中,它会随机启动崩溃。也许在 10 次中它不会突然崩溃它会连续崩溃 3 次。

此崩溃发生在创建菜单栏的过程中。这个菜单栏是一个继承自CToolBar的类。

const DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_TOOLTIPS | CBRS_FLYBY;

m_menuBar.SetSizes( CSize( 16,15 ), CSize( 1,1 ) );
const BOOL bCreated = m_menuBar.CreateEx( this, TBSTYLE_FLAT | TBSTYLE_LIST, dwStyle, CRect(0,0,0,0), AFX_IDW_TOOLBAR );

最近根据我们经理的决定,我们从 Visual Studio 2010 更新到 Visual Studio 2019,现在崩溃在 64 位中系统地发生,但在 32 位中仍然没有发生。

可能是什么问题?

编辑以添加我的堆栈:

Kernel.dll!000000001f009540()
user32.dll!00007fff7c7c63ed()
user32.dll!00007fff7c7c5fbc()
user32.dll!00007fff7c7d28d3()
ntdll.dll!00007fff7e4dfe14()
win32u.dll!00007fff7c4c1f24()
user32.dll!00007fff7c7b8011()
user32.dll!00007fff7c7b7c04()
user32.dll!00007fff7c7db122()
mfc140d.dll!00007fff3ba05208()
mfc140d.dll!00007fff3b9f4e56()
mfc140d.dll!00007fff3b9f4715()
mfc140d.dll!00007fff3b84a4c3()
d.exe!CDcmMainFrame::CreateMenuBar() Line 1001
d_d.exe!CDcmMainFrame::OnCreate(tagCREATESTRUCTA * lpCreateStruct) Line 925
[External Code]
d_d.exe!CVSDicomApp::InitInstance() Line 3074
[External Code]
d.exe!WinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, char * lpCmdLine, int nCmdShow) Line 26
d_d.exe!main(int ac, char * * av) Line 24
[External Code]

【问题讨论】:

  • 我已阅读文档。的CMFCMenuBar Class 找到一些我记得从 x86 切换到 x64 时的常见陷阱。我不能。如果this 不符合预期怎么办(即这是对早先发生的其他事情的后续行动)?一个具体的问题,我记得:句柄存储为DWORD,这在 x86 中很好,但在 x64 中可能会中断。这是不正当的,因为句柄可能具有高 32 位为 0 的值。在这种情况下,它可以工作 - 您不会注意到失败。
  • 在哪里 它到底是在哪里崩溃的?调用堆栈将告诉您崩溃发生在 MFC 中的确切位置。
  • 也许您将指针存储为 DWORD 或类似的东西。这是一个经典的。
  • 堆栈说它在 CreateEx 行中崩溃...我试图查看所有指针,但似乎并非如此,但也许我跳过了一些内容。应用有点乱。
  • @Jalg 是this 指针吗?还是崩溃实际上是在SetSizes?在那里放一个断点并检查。

标签: c++ .net mfc


【解决方案1】:

很可能根本原因位于您发布的代码之外,并且与无效的指针转换有关。了解更多有关代码上下文的信息会很有帮助。 我能想象的:

  • 您发布的代码位于 CWnd 派生类的方法中。
  • 指向该类的指针被转换并存储在一个 32 位整数中。
  • 该方法是通过指向该类的指针调用的,该指针是通过将 32 位整数转换回您的类的指针而生成的。
  • 在 64 位系统上,这会导致清除指针的高 32 位。
  • 如果这些位为零,则不会发生任何事情,因为指针没有改变。
  • 如果这些位不为零,则指针会损坏并指向无效的内存区域。最后,这个损坏的指针在调用 CreateEx 时用“this”表示,最终访问了错误的内存位置。
  • 在 32 位系统上,代码有效,因为指针只有 32 位,并且在转换为 32 位整数时不会被截断。

您可以尝试以下方法:

插入一个

Trace("*** MyClass = %p ***\n", this);

调用你的类的构造函数和直接在 CreateEx 调用之前。如果发生崩溃,两个调试输出是否匹配?

您可以尝试的另一件事是为 CreateEx 调用设置断点,以便在调用 CreateEx 之前停止执行。然后检查“this”指针。班级的所有成员看起来都有效吗?特别是 m_hWnd 应该是 != NULL。 (当然,这必须针对发生崩溃的情况进行评估,因此您可能需要多次尝试,因为您事先并不知道。)此外,您可以在创建“this”后直接输出一次 m_hWnd " 窗口,直接在 CreateEx 调用之前。他们是平等的吗?

如果我没看错,代码位于您的主应用程序中 - 而不是在 dll 中,对吗? (过去在 dll 中创建 MFC 对象以及忘记 AFX_MANAGE_STATE 宏时,我有一些奇怪的行为。)

您是否在应用程序中使用多个线程?可能是 CreateEx 调用有时是由不同的线程完成的吗?在一个类中混合来自不同线程的 MFC 调用时,MFC 会遇到麻烦。您可以将上面的调试输出扩展为

    Trace("*** MyClass = %p, ThreadId = %u ***\n", this, GetCurrentThreadId());

(线程 ID 应始终与“this”指针相同。)

【讨论】:

  • 此创建菜单的调用在来自 COXFrameWndSizeDock 的 MainFrame 派生类中。我会尝试找到一些与您定义的相似的指针。
  • 这是两个跟踪的输出:atlTraceGeneral - *** MyClass = 000000001BB5C1E0 *** atlTraceGeneral - *** MyClass = 000000001BB5C1E0 *** 所以是一样的......
  • 没有必要为了转储一些信息而添加任何代码。你可以log info with tracepoints 代替。
  • 一些成员为空,但 m_hWnd 不是。
  • 崩溃时不为空,但它说未使用=???,我现在不知道这意味着什么,或者是否正常。是位于我的主应用程序中。我正在尝试解决一些与 32/64 位问题相关的警告,这些问题 pvs 对我的评价没有成功。该应用程序是多线程的,但我认为开始始终是主线程,我会更加关注。
猜你喜欢
  • 2012-05-30
  • 2012-04-17
  • 2010-09-16
  • 2011-05-13
  • 1970-01-01
  • 1970-01-01
  • 2014-03-23
  • 2011-03-18
  • 2012-11-03
相关资源
最近更新 更多