2012-03-19 53 views
10

我試圖編譯編譯我的桌面上,但我的筆記本電腦,它編譯,但給我只要運行這個錯誤完全正常的程序編譯:堆損壞,但只有當筆記本電腦

Windows有在RR.exe中觸發了一個斷點。

這可能是由於堆損壞導致RR.exe或其中已加載的任何DLL文件存在bug。

這也可能是由於用戶在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(); 
} 

的main.cpp

#include "window.h" 

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

    return 0; 
} 
+3

+1用於提供一個完整的,相對短的測試情況。 – 2012-03-19 11:46:26

+1

你有你保證在兩臺機器上都有完全相同版本的系統/運行時DLL? – 2012-03-19 11:47:28

+0

它們是完全相同的DLL,.libs和pro因爲我將它們放在保管箱中。 – Lerp 2012-03-19 11:50:17

回答

6

這個問題似乎領先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顯然是設置,它定義的API函數與__stdcall調用轉換。

但是當使用庫時你還沒有定義GLFW_DLL,所以你的代碼假設調用了__cdecl轉換。_cdecl__stdcall之間的區別一般是來電功能應該先清理堆棧,最後一種情況應清除被呼叫者。所以你清理了兩次堆棧,這就是爲什麼你的堆棧損壞。

在我的程序中定義了GLFW_DLL之後,它包含glfw,它開始正常工作。還請注意,我使用了mingw,並且在定義了GLFW_DLL之後,必須鏈接到glfwdll.a而不是glfw.a

+0

這也適用於我。我設法通過將多線程調試DLL的運行時庫更改爲多線程DLL來實現它。你能解釋爲什麼傳遞常量值而不是變量不會導致堆損壞?它是否以不同的方式調用函數,因爲所有參數都是不變的? – Lerp 2012-03-20 13:09:44

+0

@Rarge,「多線程調試DLL到多線程DLL的運行時庫」似乎與一些WinCRT的東西,而不是GLFW連接。既不設置常量值也不改變項目設置_prevents_堆損壞,但只_隱藏_它。 – Lol4t0 2012-03-20 13:25:59

1

堆損壞漏洞almomst從來沒有表現出他們最初發生的地步,這是什麼讓他們如此痛苦的診斷。它在一個系統而不是另一個系統上工作的事實意味着未定義的行爲。

我在代碼的快速檢查中沒有看到任何明顯的錯誤。如果你有權使用Purify for Windows,或者在Linux上編譯能力,你可以使用valgrind。我相信這些工具中的任何一個都會比簡單的代碼檢查有更高的成功變化。

0

另一種解決方案,我碰到:

通過改變運行時庫(項目屬性> C/C++>從多線程調試DLL(/ MDD)到多線程DLL(/ MD)堆損壞不不再發生。

我不知道爲什麼,雖然,也許有人有更多的知識可以可以在此提供一些線索。