【问题标题】:Heap Corruption but only when compiled on laptop堆损坏,但仅在笔记本电脑上编译时
【发布时间】:2012-04-03 21:35:55
【问题描述】:

我正在尝试编译一个程序,该程序在我的台式机上编译得非常好,但在我的笔记本电脑上,它可以编译,但无论何时运行都会给我这个错误:

Windows 已在 RR.exe 中触发断点。

这可能是由于堆损坏,这表明存在错误 RR.exe 或它已加载的任何 DLL。

这也可能是由于用户在 RR.exe 获得焦点时按 F12。

输出窗口可能有更多的诊断信息。

我已经注释掉了行,直到找到导致错误的行:

if(glfwOpenWindow(width_, height_, 0, 0, 0, 0, 32, 0, GLFW_WINDOW) != GL_TRUE) {
    throw std::runtime_error("Unable to open GLFW window");
}

奇怪的是,如果我用常量替换 width_height_,例如分别为 800 和 600,它会停止堆损坏。此外,如果我只使用构造函数设置的默认值而不是传递值,它不会崩溃。

这是完整的代码。以上几行在Window 构造函数中。

window.h

#pragma once

#include <iostream>
#include <GL\glew.h>
#include <GL\glfw.h>

#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glew32.lib")
#pragma comment(lib, "GLFW.lib")

class Window {
public:
    Window(unsigned width = 800, unsigned height = 600);
    ~Window();

    void clear();
    inline void display() { glfwSwapBuffers(); }
    inline bool exit() { return !glfwGetWindowParam(GLFW_OPENED); }

private:
    unsigned width_, height_;
};

window.cpp

#include "window.h"

Window::Window(unsigned width, unsigned height) : width_(width), height_(height) {
    if(glfwInit() != GL_TRUE) {
        throw std::runtime_error("Unable to initialize GLFW");
    }

    if(glfwOpenWindow(width_, height_, 0, 0, 0, 0, 32, 0, GLFW_WINDOW) != GL_TRUE) { //crash
    //if(glfwOpenWindow(800, 600, 0, 0, 0, 0, 32, 0, GLFW_WINDOW) != GL_TRUE) { //no crash
        throw std::runtime_error("Unable to open GLFW window");
    }

    GLenum result = glewInit();
    if(result != GLEW_OK) {
        std::stringstream ss;
        ss << "Unable to initialize glew: " << glewGetErrorString(result);
        throw std::runtime_error(ss.str());
    }
}

Window::~Window() {
    glfwTerminate();
}

void Window::clear() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
}

ma​​in.cpp

#include "window.h"

int main() {
    Window wind(1024, 800); //crash
    Window wind(800, 600); //crash
    Window wind(); //works

    return 0;
}

【问题讨论】:

  • +1 用于提供完整的、相对较短的测试用例。
  • 您是否确保两台机器上的系统/运行时 DLL 版本完全相同?
  • 它们是完全相同的 DLL、.libs 和项目,因为我将它们保存在 Dropbox 上。
  • 窗风(); - 这是一个函数声明,而不是 Window 类型的默认构造变量
  • 你确定 glfwOpenWindow 的行会导致崩溃,而不仅仅是暴露它吗? width_ 和 height_ 在调用时是否包含有效且正确的值?

标签: c++ glfw


【解决方案1】:

我遇到的另一个解决方案:

通过将运行时库(项目属性 > C/C++ >从多线程调试 DLL (/MDd) 更改为多线程 DLL (/MD),不再发生堆损坏。

我不知道为什么,也许有更多知识的人可以对此有所了解。

【讨论】:

    【解决方案2】:

    问题似乎与 glfw 有关:

    我假设,您正在尝试使用动态链接的GLFW。 glfw 标头中的注释:

    #if defined(_WIN32) && defined(GLFW_BUILD_DLL)
    
    /* We are building a Win32 DLL */
     #define GLFWAPI      __declspec(dllexport)
     #define GLFWAPIENTRY __stdcall
     #define GLFWCALL     __stdcall
    #elif defined(_WIN32) && defined(GLFW_DLL)
    
     /* We are calling a Win32 DLL */
     #if defined(__LCC__)
      #define GLFWAPI      extern
     #else
      #define GLFWAPI      __declspec(dllimport)
     #endif
     #define GLFWAPIENTRY __stdcall
     #define GLFWCALL     __stdcall
    
    #else
    
     /* We are either building/calling a static lib or we are non-win32 */
     #define GLFWAPIENTRY
     #define GLFWAPI
     #define GLFWCALL
    
    #endif
    

    GLFW_BUILD_DLL 显然是在构建 dll 时设置的,它定义了带有 __stdcall 调用转换的 API 函数。

    但是在使用库时你还没有定义GLFW_DLL,所以你的代码假设__cdecl调用转换。 _cdecl__stdcall 之间的区别通常是 caller function 应该首先清理堆栈,而 callee 在最后一个情况下。所以你清理了两次堆栈,这就是堆栈损坏的原因。

    在我在您的程序中包含glfw 之前定义GLFW_DLL 之后,它开始正常工作。另请注意,我使用了 mingw 并且在定义 GLFW_DLL 之后必须链接到 glfwdll.a 而不是 glfw.a

    【讨论】:

    • 这也对我有用。我还设法通过将多线程调试 DLL 的运行时库更改为多线程 DLL 来使其工作。您能否解释为什么传递常量值而不是变量不会导致堆损坏?它是否以不同的方式调用函数,因为所有参数都是常量?
    • @Rarge,“多线程调试 DLL 到多线程 DLL 的运行时库”似乎与一些 WinCRT 的东西有关,而不是 GLFW。设置常量值或更改项目设置都不会防止堆损坏,而只是隐藏它。
    【解决方案3】:

    堆损坏错误几乎不会在它们最初发生的时候出现,这就是让诊断它们变得如此痛苦的原因。它适用于一个系统而不是另一个系统这一事实意味着未定义的行为。

    在快速检查您的代码时,我没有发现任何明显的错误。如果您可以访问 Purify for Windows,或者替代在 Linux 上编译的能力,您可以使用 valgrind。我相信这些工具中的任何一个都会比简单的代码检查带来更大的成功变化。

    【讨论】:

      猜你喜欢
      • 2016-02-19
      • 1970-01-01
      • 2020-09-27
      • 2013-08-23
      • 2018-06-20
      • 1970-01-01
      • 1970-01-01
      • 2019-07-30
      • 2018-07-09
      相关资源
      最近更新 更多