A few days ago, my company changed our operation system from Windows XP to Windows 7 (32-bit) for security matters.
I use C++ in VS 2008, QT 4.8.1, and Boost. Struct Member Alignment in my application is 1 byte (/Zp1).
After the change, I found one bug:
I load the library I made with QPluginLoader and then I use qobject_cast to cast it to my interface. In my library I might load another.
When I test my application on Debug mode after the operating system changed, it was all OK. Everything was working like it suppose to, then I changed it to Release and my application started crashing.
When I debugged it with VS 2008, I saw this error:
A buffer overrun has occurred in my_app.exe which has corrupted the program's internal state. Press Break to debug the program or Continue to terminate the program.
For more details please see Help topic 'How to debug Buffer Overrun Issues'.
The application still work fine on Windows XP (Release and Debug mode).
At the beginning, I thought it was because of a dependency or something I missed. After a couple of hours testing and tracing my application with logging in Release mode, I finally found out what was wrong. My application crashes when one method tries to return a value (anything) to another that called it inside the library.
For example:
Method B return Bool and I call it in Method A. When Method B is finished and ready to return a Bool value to Method A, wy application crashes. It also crashes when it wants to return to the method that loaded the library, if the method returns a value. Somehow, it's ok with a method that don't return any value (void).
To be sure what is wrong exactly, the code inside my methods, I made another application (tester) and started to add my code part-by-part to find the error. I believe it has something to do with QT.
Please check the following code and tell me if you know what is wrong.
I have main.cpp that loads a plugin like this:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString filename = "correct path";
QPluginLoader* pluginLoader = new QPluginLoader(filename);
QObject *plugin = pluginLoader->instance();
PluginInterface* plugin_instance;
if (plugin)
{
SecureZeroMemory(&plugin_instance, sizeof(PluginInterface));
plugin_instance = qobject_cast<PluginInterface *>(plugin);
}
bool result = plugin_instance->initialize();
return a.exec();
}
This is my interface:
class PluginInterface
{
public:
virtual bool initialize() = 0;
};
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(PluginInterface,"some text");
QT_END_NAMESPACE
I make my library like this:
plugin.hpp
class Plugin : public QObject, public PluginInterface
{
Q_OBJECT
Q_INTERFACES(PluginInterface)
public:
Plugin();
bool initialize();
};
plugin.cpp
#define SUPPORTED_VERSIONS 0x01011403
#define WFS_TRACE_NONE 0
bool Plugin::initialize()
{
WFSVERSION wfs_version;
HRESULT hRes;
cout << "WFSStartUp" << endl;
hRes = WFSStartUp(SUPPORTED_VERSIONS, &wfs_version);
WORD version = wfs_version.wVersion;
cout << "version : " << version << endl;
DWORD dwTrace = WFS_TRACE_NONE;
cout << "WFSCreateAppHandle" << endl;
HRESULT hRes2;
HANDLE app_handle;
hRes2 = WFSCreateAppHandle(&app_handle);
cout << "Result : " << hRes2 << endl;
return true;
}
Q_EXPORT_PLUGIN2(my_plugin, Plugin);
This is the output of my tester application:
WFSStartUp
version : 63424
WFSCreateAppHandle
Result : 0
Application Crash!!
The code inside Plugin::initialize() works fine. I copy/paste it to main() and ran the application to be sure about it.
What is wrong here? What am I missing?
This code:
PluginInterface* plugin_instance;
if (plugin)
{
SecureZeroMemory(&plugin_instance, sizeof(PluginInterface));
plugin_instance = qobject_cast<PluginInterface *>(plugin);
}
would be very much crash-inducing if SecureZeroMemory does what its name says it does.
To zero a pointer just set it to 0.
But, to mention also that, that would be meaningless when the next thing you do is to assign to it, as above.
I already tested without SecureZeroMemory and it still crash, SecureZeroMemery its not the cause of the crash!
Quite probably there are other bugs like that in other places in the code - places that you don't show.
At the very least, are you compiling everything in your application (all libraries, DLLs, etc.) with the same compiler, and using same settings? If you use "/Zp1", you must use it for every piece of code, including Qt itself. Such compiler flags make the code compiled with them binary incompatible with code compiled without them.
Besides, "/Zp1" is a performance killer. If you want to pack structures for dumping them to disk etc., you're going about it the wrong way. The structure that you use shouldn't be packed. Only when you're copying it to/from disk should you have another structure defined internally that is packed, and you first copy the data from unpacked to packed structure, and only then dump to disk. You're supposed to pack individual structures by using proper pragmas/attributes, not everything!
I had to change few Visual Studio build options to fix this problem!
Optimization = Custom (Configuration Properties -> C/C++ ->
Optimization)
Inline Function Expansion = Default (Configuration
Properties -> C/C++ -> Optimization)
Related
I have a question which is quite general, but I hope someone will be able to at least point me in the right direction.
I created my project a I was building it only in Debug mode with /MDd flag.
But it started to have perfomance issues, so I wanted to try it in Release mode to see, how it goes.
Problem is, that when I use /MD or /MT flag and Release mode my application instantly crashes.
So I tried to find out why. It works fine in Debug. I've tried some code changes, but nothing helped. So I decided to make my app just start and comment out rest of my code. But it was still crashing. Even when my code was unused. It didn't crash only, when I completly removed those unused parts of code.
I think it's something with variable inicialization/declaration, but I'm not quite sure what I should look for.
Could someone suggest me what can cause application to crash even if it's just Declaration/Inicialization and is not even used in RunTime?
I hope you can somehow understand what is my problem.
Thanks for any suggestions!
EDIT: Code which crashes, when unused code is in project, but does not crash when i remove unused code.
#include "core/oxygine.h"
#include "Stage.h"
#include "DebugActor.h"
//#include "Galatex.h"
using namespace oxygine;
//called each frame
int mainloop()
{
//galatex_update();
//update our stage
//update all actors. Actor::update would be called also for all children
getStage()->update();
if (core::beginRendering())
{
Color clearColor(32, 32, 32, 255);
Rect viewport(Point(0, 0), core::getDisplaySize());
//render all actors. Actor::render would be called also for all children
getStage()->render(clearColor, viewport);
core::swapDisplayBuffers();
}
//update internal components
//all input events would be passed to Stage::instance.handleEvent
//if done is true then User requests quit from app.
bool done = core::update();
return done ? 1 : 0;
}
//it is application entry point
void run()
{
ObjectBase::__startTracingLeaks();
//initialize Oxygine's internal stuff
core::init_desc desc;
#if OXYGINE_SDL || OXYGINE_EMSCRIPTEN
//we could setup initial window size on SDL builds
desc.w = 1800;
desc.h = 1000;
//marmalade settings could be changed from emulator's menu
#endif
//galatex_preinit();
core::init(&desc);
//create Stage. Stage is a root node
Stage::instance = new Stage(true);
Point size = core::getDisplaySize();
getStage()->setSize(size);
//DebugActor is a helper actor node. It shows FPS, memory usage and other useful stuff
DebugActor::show();
//initialize this example stuff. see example.cpp
//galatex_init();
#ifdef EMSCRIPTEN
/*
if you build for Emscripten mainloop would be called automatically outside.
see emscripten_set_main_loop below
*/
return;
#endif
//here is main game loop
while (1)
{
int done = mainloop();
if (done)
break;
}
//user wants to leave application...
//lets dump all created objects into log
//all created and not freed resources would be displayed
ObjectBase::dumpCreatedObjects();
//lets cleanup everything right now and call ObjectBase::dumpObjects() again
//we need to free all allocated resources and delete all created actors
//all actors/sprites are smart pointer objects and actually you don't need it remove them by hands
//but now we want delete it by hands
//check example.cpp
//galatex_destroy();
//renderer.cleanup();
/**releases all internal components and Stage*/
core::release();
//dump list should be empty now
//we deleted everything and could be sure that there aren't any memory leaks
ObjectBase::dumpCreatedObjects();
ObjectBase::__stopTracingLeaks();
//end
}
#ifdef __S3E__
int main(int argc, char* argv[])
{
run();
return 0;
}
#endif
#ifdef OXYGINE_SDL
#include "SDL_main.h"
extern "C"
{
int main(int argc, char* argv[])
{
run();
return 0;
}
};
#endif
#ifdef EMSCRIPTEN
#include <emscripten.h>
void one() { mainloop(); }
int main(int argc, char* argv[])
{
run();
emscripten_set_main_loop(one, 0, 0);
return 0;
}
#endif
So I'll write it here for possibly other newbies like me which would find themselves in similar sutiation.
My problem was in Initialization of static and other variables which were "outside of function". For example:
MyObject object = new MyObject(); //This was the reason, why it was crashing, just had to move
// initialization of such variables to function which was called with object creation.
void MyClass::myFunction(){
object->doSomething();
}
So when program started inicialization of those variables caused crash of program.
Note: It seems like it was problem with objects, cause variables like Integers or such were just fine.
Well, I'm not totally sure why this is allowed in Debug mode, but crashes Release mode right after start, maybe someone could answer under this comment and explain this behavior, I'm just begginer and I'm doing lot of bad stuff, but I'm trying and that's good, right? :D
I hope i didn't waste too much of your time guys and maybe this post will be useful to someone in future.
EDIT: PROBLEM SOLVED, see my answer. TL;DR: wasn't related to Qt, I made a stupid mistake with array (std::vector) ranges.
Using Windows7, Qt version 4.8.7, x86_64-w64-mingw32-g++ as compiler, Cygwin for compiling, Notepad++ for editing. (The same project has Flex and Bisonc++ in it as well, but those are not related to the issue and work fine.)
I have an std::vector< QLabel* >, and I attempt to fill it with data. In one test case (which is the QFrame containing the vector getting the data from the main function with no involvement from other classes) this works out fine, as expected.
In another case, when using a QMainWindow to trigger it's own slot-method which calls for the same function, it runs into a segmentation fault at the QLabel.setText( QString::number() ) part.
ui_parts.h
#ifndef UI_PARTS_H_INCLUDED
#define UI_PARTS_H_INCLUDED
#include <QWidget>
#include <QLabel>
#include <QGridLayout>
#include <QFrame>
#include <vector>
#include <string>
class regDisplay : public QFrame{
Q_OBJECT
public:
regDisplay(int _meret, const std::string &nev, QWidget *parent = 0);
~regDisplay() {}; // not actually in the header, here for compression
int size() const { return meret; };
void setValues(const std::vector<AP_UC> &val);
private:
QGridLayout* gridLayout;
int meret;
std::vector<unsigned char> valueVec;
std::vector<QLabel*> valueLabel;
};
#endif // UI_PARTS_H_INCLUDED
ui_parts.cpp
#include <iostream>
#include "ui_parts.h"
using namespace std;
regDisplay::regDisplay(int _meret, const std::string &nev, QWidget *parent)
: QFrame(parent), name(nev), meret(_meret){
valueVec.resize(meret, 0);
valueLabel.resize(meret, NULL);
gridLayout = new QGridLayout(this);
// [...] setting up other properties of the widget
for (int i = 0; i < meret; ++i){
valueLabel[i] = new QLabel(this);
// [...] set properties for valueLabel[i]
gridLayout -> addWidget( valueLabel[i], 1, i);
}
}
// the following function which is suspected with causing the segfault
void regDisplay::setValues(const std::vector<AP_UC> &val){
for (int i = 0; i < meret; ++i)
{
valueVec[i] = val[i];
cout << (int)valueVec[i] << "\t" << (QString::number( (int)valueVec[i] )).toStdString() << endl;
cout << "ptr: " << (valueLabel[i]) << endl;
if ( valueLabel[i] == NULL ){
cout << "NULL POINTER? WTF " << i << endl;
} else{
cout << "not null pointer " << i << endl;
}
cout << "kek" << endl;
valueLabel[i] -> setText( QString::number( (int)valueVec[i] )); // SEGFAULT
cout << i << "+" << endl;
}
}
Calling the function:
vector<unsigned char> vecUC(4);
allapot.get_reg("eax", vecUC); // I'm 100% sure this works correctly, tested thoroughly
// it makes vecUC equal to an std::vector<unsigned char> which is 4 long
eax -> setValues( vecUC ); // regDisplay* eax;
// initialized: eax = new regDisplay(4, "eax", this ); in the constructor of this class (which inherits from QMainWindow)
Console output of this piece of code:
0 0
ptr: 0x32f160
not null pointer 0
kek
Segmentation fault
My read on this:
valueVec[i] and its QString version are both 0 (the argument of setText() seems to be fine)
valueLabel[i] has a pointer value which isn't 0, initialized as such in the constructor
valueLabel[i] is not a nullpointer (i == 0 in this case)
the first cout before the setText() works, the second does not
Removing (commenting) the setText() calls from throughout the code make it work properly (but I need some way of putting out text on the UI, so they're needed in some form for the purpose of the program).
'make ui_vec' creates the testing module for the regDisplay and veremDisplay classes, which works fine
'make ui_main' creates the testing module for mainDisplay, which causes the issues to arise
I do not know what causes the issue and I'd appreciate any help with removing it. Thank you in advance.
Update (16.05.14):
I recreated the entire project in wxWidgets, and it worked fairly similarly, but at basically the same point it also started throwing segfaults around. It appears to happen randomly, sometimes the entire program works correctly, sometimes on the first action it fails.
However, running the program through gdb completely solved the issue, I haven't encountered any segfaults.
Update (16.05.16):
After some further testing, it appears that the problem is somewhere in the bisonc++ / flex parser I created. There is one piece of code using it that works completely fine every time, and if I try to add to it (going back with an std::stack to previous states; using a class to navigate) it segfaults after the second instruction (the first works fine).
Footnotes:
Link for repository - the problem is in src/cpp/ui_parts.cpp line79 (regDisplay::setValues()), called from mainDisplay::displayAllapot() (src/cpp/ui_main.cpp line195). Debug messages might have changed a bit, rest of the code is the same.
Most of the documentation and commments are in Hungarian and not in English, my apologies for that.
Another (probably related issue): the very same program sometimes runs into the same segmentation fault at different locations - sometimes the regDisplay::setValues() works fine, and the problem appears at veremDisplay::updateValues() - during a loop, maybe on the first run, maybe later, sometimes it works through the entire thing, and I haven't seen any consistency in it yet (it mostly stops working on the first run).
Third problem (again, most likely related): when calling the openFile() function, it runs properly until the end (the last instruction being a debug message and working correctly), but gives a seg-fault (this would make me think of destructor issues). However, if I connect a different function (oF2()) to the same event instead, then have oF2() call openFile() and write a debug message (and to nothing else), then the debug message shows and the segmentation fault appears afterward - and there were no local variables or parameters received, so no destructor should run between the last instruction of the code and the function terminating.
I found the issue, I went up to 10 in an std::vector that was only 7 in size (it only appeared in some test cases), fixing that solved every issue I had, no segmentation faults appeared so far in fairly extensive testing.
Since the real problem wasn't related to Qt in any way (also not to bisonc++ or flex), apart from the "check your array ranges" lesson, I don't think there is any real reason to keep this thread around. If mods see this, feel free to delete the question - if the solution isn't enough to keep it up.
I don't see in your code problem that may cause segfault.
But my guess that your compilation flags may cause such segfault.
For example, you use std::string and toStdString.
If Qt compiled with another version of compiler, or for example if you link you program statically with c++ runtime library (which you do accroding to your makefile[-static-libgcc -static-libstdc++]) and Qt links with dll variant of c++ runtime, then your program and Qt library may think that they work with the same version of std::string, but actually the work wtih different versions of std::string,
and std::string that allocated inside Qt may cause segfault, when you call
destructor of it inside your program. Or you create QFile with FILE * created by fopen, and you catch segfault in ~QFile, because of Qt FILE and your FILE are different.
So make sure, that your Qt compiled with the same compiler as your program,
and Qt builds with the same flags as your program.
Actually sizeof(std::string) and sizeof(FILE) may be the same, but can be used different allocators.
I'm writing an application, for learning purposes, that is composed of two executables. Among other things, each executable creates a shared memory segment of his own (with different keys), after that executable A tries to create a segment using B's key, and B does the same with A's key (the purpose of this is for each executable to check if the other is still running. I know that this probably isnt the best way of accomplishing this but i ask you to not focus on this fact). If either program succeeds in creating a segment with the other's key, it assumes the other is not running and takes action accordingly.
The problem that happens is that this works OK when B checks A. But when A checks B, it can create a segment with the same key B has already created. I'm pretty sure i checked all race conditions possible, and im also pretty sure that both segments exist at the same time with the same key (both QSharedMemory create calls with this key return true). In fact, just for giggles, i've placed the create call inside a loop and it can keep creating the segment with the same key for as long as the loop goes. I tried passing the key directly in the constructor, using setKey() and using setNativeKey() and none worked.
And as said before, what really boggles my mind is that the same approach works for B checking A, but not the other way around.
I dont know why this is happening? Does the key have to follow any standards? Does QSharedMemory have a restriction or specific behavior when being used inside a thread/signal/method?
A's code snipet (method is called using signals - DOES NOT WORK):
//Process A "signature" creation
QSharedMemory process_a_signature("61BB200D-3579-453e-9044-");
if(process_a_signature.create(512,QSharedMemory::ReadWrite)==true) {
qDebug() << "Process A signature created.";
} else exit(0);
...
//Method that checks for process B (monitor)
void LaRunTime::checkMonitorProcess(){
QSharedMemory monitorsignature("61BB201D-3569-453e-9144-");
if(monitorsignature.create(512,QSharedMemory::ReadWrite)==true) {
qDebug() << "Process B is not running.";
} else {
qDebug() << "Process B is running.";
}
B's code snippet (method is also called using signals - WORKS)
//Process B "signature" creation
QSharedMemory monitorsignature("61BB201D-3569-453e-9144-");
if(monitorsignature.create(512,QSharedMemory::ReadWrite)==true) {
qDebug() << "Process B signature created.";
} else {
exit(0);
}
...
//Method that checks for process A
void LaClientMonitor::checkProcess(){
QSharedMemory process_a_signature("61BB200D-3579-453e-9044-");
if(process_a_signature.create(512,QSharedMemory::ReadWrite)==true) {
qDebug() << "Process A is not running.";
} else {
qDebug() << "Process A is running.";
}
So, after fiddling with the code in a few other ocasions i found out that the problem was happening because i was creating the shared memory segment inside a class / object, and for some reason (i believe related to the life cycle of the object) it was being destroyed right after its creation.
Moving the code that creates the memory segment to main.cpp file solved the problem.
I have been messing around all day trying to get my MFC application to show the log output of a console application on the screen. Starting with what Visual Studio 2013's wizard gave me, I was able to modify their code to take a string as input and make a running log of application messages (below):
void COutputWnd::FillBuildWindow(std::string build_text)
{
std::wstring wsTmp(build_text.begin(), build_text.end());
std::wstring z = wsTmp;
LPTSTR x = new TCHAR[z.size() + 1];
_tcscpy(x, z.c_str());
m_wndOutputBuild.AddString(x);
free(x);
}
However, I cannot call this from outside the MFC function for a number of reasons. One is the object is not visible globally and two I am using windows.h in the console parts of my application and it does not play nicely with MFC.
Much of my application is already written and I am trying to put a GUI around it and use the ribbon features. Is there any way to take the cout statements and pipe them to a message log display in my MFC app? I have googled a ton of things today and not found anything that is either straightforward or clearly for applications which have both MFC and console code as part of their solution. I am not invoking a separate executable or dll. This is all compiled as a single standalone exe.
I have no idea about MFC but I would derive a class from std::streambuf to redirect its output to an MFC class and install the resulting stream buffer into std::cout. The stream buffer deals with the output written to a stream and you can get hold of the written characters in its overflow() and sync() methods:
class windowbuf
: std::streambuf {
SomeHandle handle;
char buffer[256];
public:
typedef std::char_traits<char> traits;
windowbuf(SomeHandle handle): handle(handle) { this->setp(buffer, buffer + 255); }
int overflow(int c) {
if (!traits::eq_int_type(c, traits::eof())) {
*this->pptr() = traits::to_char_type(c);
this->pbump(1);
}
return this->sync() == -1? traits::eof(): traits::not_eof(c);
}
int sync() {
writeToHandle(this->handle, this->pbase(), this->pptr() - this->pbase());
this->setp(buffer, buffer + 255);
return 0;
}
};
The above is a simple stream buffer which transfers characters somewhere identified by handle when its buffer is full or when the stream is flushed. I think it should be doable to come up with some handle and a write function which transfers the characters to an MFC window although I don't know anything about that part.
To have std::cout send its characters to the above stream buffer, you just need to install this stream buffer into std::cout, e.g., using
int main() {
SomeHandle handle = get_a_handle_from_somewhere();
std::streambuf* cout_rdbuf = std::cout.rdbuf(new windowbuf(handle));
// run your program here
std::cout.rdbuf(cout_rdbuf); // this should really be restored using RAII approaches
}
I'd think something like the above approach should be able to bridge the gap between some code writing to std::cout and other parts of the code displaying information with some sort of GUI.
Is there any sense to step-execute release code? I noticed that some lines of code are omitted, i.e. some method calls. Also variable preview doesn't show some variables and shows invalid (not real) values for some others, so it's all quite misleading.
I'm asking this question, because loading WinDbg crashdump file into Visual Studio brings the same stack and variables partial view as step-execution. Are there any way to improve crashdump analyze experience, except recompiling application without optimalizations?
Windows, Visual Studio 2005, unmanaged C++
Yes - if you have the .pdb for the build, and the .dmp file from the crash, then you can open the debugger on the exact point of failure, and examine the state of your app at that point.
As several have noted - some variables will be optimized away, but if you're mildly creative / inquisitive, you'll find ways to obtain those values.
You can build in a root crash handler for your code to generate a .dmp file automatically which works on all Windows flavors (assuming you are creating a Windows app) using something like the following:
// capture the unhandled exception hook - we will create a mini dump for ourselves
// NOTE: according to docs, if a debugger is present, this API won't succeed (ie. debug builds ignore this)
MiniDumper::Install(
true,
filename,
"Please send a copy of this file, along with a brief description of the problem, to [insert your email address here] so that we might fix this issue."
);
The above would require the MiniDumper class I wrote, below:
#pragma once
#include <dbghelp.h>
#include "DynamicLinkLibrary.h"
#include "FileName.h"
//////////////////////////////////////////////////////////////////////////
// MiniDumper
//
// Provides a mechanism whereby an application will generate its own mini dump file anytime
// it throws an unhandled exception (or at the client's request - see GenerateMiniDump, below).
//
// Warning: the C-runtime will NOT invoke our unhandled handler if you are running a debugger
// due to the way that the SetUnhandledExceptionFilter() API works (q.v.)
//
// To use this facility, simply call MiniDumper::Install - for example, during CWinApp initialization.
//
// Once this has been installed, all current and future threads in this process will be covered.
// This is unlike the StructuredException and CRTInvalidParameter classes, which must be installed for
// for each thread for which you wish to use their services.
//
class MiniDumper
{
public:
// install the mini dumper (and optionally, hook the unhandled exception filter chain)
// #param filename is the mini dump filename to use (please include a path)
// #return success or failure
// NOTE: we can be called more than once to change our options (unhook unhandled, change the filename)
static bool Install(bool bHookUnhandledExceptionFilter, const CFilename & filenameMiniDump, const CString & strCustomizedMessage, DWORD dwMiniDumpType = MiniDumpNormal)
{
return GetSingleton().Initialize(bHookUnhandledExceptionFilter, filenameMiniDump, strCustomizedMessage, dwMiniDumpType);
}
// returns true if we've been initialized (but doesn't indicate if we have hooked the unhandled exception filter or not)
static bool IsInitialized() { return g_bInstalled; }
// returns true if we've been setup to intercept unhandled exceptions
static bool IsUnhandledExceptionHooked() { return g_bInstalled && GetSingleton().m_bHookedUnhandledExceptionFilter; }
// returns the filename we've been configured to write to if we're requested to generate a mini dump
static CFilename GetMiniDumpFilename() { return g_bInstalled ? GetSingleton().m_filenameMiniDump : ""; }
// you may use this wherever you have a valid EXCEPTION_POINTERS in order to generate a mini dump of whatever exception just occurred
// use the GetExceptionInformation() intrinsic to obtain the EXCEPTION_POINTERS in an __except(filter) context
// returns success or failure
// DO NOT hand the result of GenerateMiniDump to your __except(filter) - instead use a proper disposition value (q.v. __except)
// NOTE: you *must* have already installed MiniDumper or this will only error
static bool GenerateMiniDump(EXCEPTION_POINTERS * pExceptionPointers);
private:
// based on dbghelp.h
typedef BOOL (WINAPI * MINIDUMPWRITEDUMP_FUNC_PTR)(
HANDLE hProcess,
DWORD dwPid,
HANDLE hFile,
MINIDUMP_TYPE DumpType,
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
// data we need to pass to our mini dump thread
struct ExceptionThreadData
{
ExceptionThreadData(EXCEPTION_POINTERS * exceptionPointers, bool bUnhandled, DWORD threadID = ::GetCurrentThreadId())
: pExceptionPointers(exceptionPointers)
, dwThreadID(threadID)
, bUnhandledException(bUnhandled)
{
}
EXCEPTION_POINTERS * pExceptionPointers;
DWORD dwThreadID;
bool bUnhandledException;
};
// our unhandled exception filter (called automatically by the run time if we've been installed to do so)
static LONG CALLBACK UnhandledExceptionFilter(EXCEPTION_POINTERS * pExceptionPointers);
// creates a new thread in which to generate our mini dump (so we don't run out of stack)
static bool ExecuteMiniDumpThread(EXCEPTION_POINTERS * pExceptionPointers, bool bUnhandledException);
// thread entry point for generating a mini dump file
static DWORD WINAPI MiniDumpThreadProc(LPVOID lpParam);
// obtains the one and only instance
static MiniDumper & GetSingleton();
// flag to indicate if we're installed or not
static bool g_bInstalled;
// create us
MiniDumper()
: m_pPreviousFilter(NULL)
, m_pWriteMiniDumpFunction(NULL)
, m_bHookedUnhandledExceptionFilter(false)
{
}
// install our unhandled exception filter
bool Initialize(bool bHookUnhandledExceptionFilter, const CFilename & filenameMiniDump, const CString & strCustomizedMessage, DWORD dwMiniDumpType);
// generates a mini dump file
bool GenerateMiniDumpFile(ExceptionThreadData * pData);
// handle an unhandled exception
bool HandleUnhandledException(ExceptionThreadData * pData);
bool m_bHookedUnhandledExceptionFilter;
CFilename m_filenameMiniDump;
CString m_strCustomizedMessage;
DWORD m_dwMiniDumpType;
MINIDUMPWRITEDUMP_FUNC_PTR m_pWriteMiniDumpFunction;
LPTOP_LEVEL_EXCEPTION_FILTER m_pPreviousFilter;
};
And its implementation:
#include "StdAfx.h"
#include "MiniDumper.h"
using namespace Toolbox;
//////////////////////////////////////////////////////////////////////////
// Static Members
bool MiniDumper::g_bInstalled = false;
// returns true if we were able to create a mini dump for this exception
bool MiniDumper::GenerateMiniDump(EXCEPTION_POINTERS * pExceptionPointers)
{
// obtain the mini dump in a new thread context (which will have its own stack)
return ExecuteMiniDumpThread(pExceptionPointers, false);
}
// this is called from the run time if we were installed to hook the unhandled exception filter
LONG CALLBACK MiniDumper::UnhandledExceptionFilter(EXCEPTION_POINTERS * pExceptionPointers)
{
// attempt to generate the mini dump (use a separate thread to ensure this one is frozen & we have a fresh stack to work with)
ExecuteMiniDumpThread(pExceptionPointers, true);
// terminate this process, now
::TerminateProcess(GetCurrentProcess(), 0xFFFFFFFF);
// carry on as normal (we should never get here due to TerminateProcess, above)
return EXCEPTION_CONTINUE_SEARCH;
}
bool MiniDumper::ExecuteMiniDumpThread(EXCEPTION_POINTERS * pExceptionPointers, bool bUnhandledException)
{
// because this may have been created by a stack overflow
// we may be very very low on stack space
// so we'll create a new, temporary stack to work with until we fix this situation
ExceptionThreadData data(pExceptionPointers, bUnhandledException);
DWORD dwScratch;
HANDLE hMiniDumpThread = ::CreateThread(NULL, 0, MiniDumpThreadProc, &data, 0, &dwScratch);
if (hMiniDumpThread)
{
VERIFY(::WaitForSingleObject(hMiniDumpThread, INFINITE) == WAIT_OBJECT_0);
VERIFY(::GetExitCodeThread(hMiniDumpThread, &dwScratch));
VERIFY(::CloseHandle(hMiniDumpThread));
return AsBool(dwScratch);
}
return false;
}
DWORD WINAPI MiniDumper::MiniDumpThreadProc(LPVOID lpParam)
{
// retrieve our exception context from our creator
ExceptionThreadData * pData = (ExceptionThreadData *)lpParam;
// generate the actual mini dump file in this thread context - with our own stack
if (pData->bUnhandledException)
return GetSingleton().HandleUnhandledException(pData);
else
return GetSingleton().GenerateMiniDumpFile(pData);
}
bool MiniDumper::HandleUnhandledException(ExceptionThreadData * pData)
{
// generate the actual mini dump file first - hopefully we get this even if the following errors
const bool bMiniDumpSucceeded = GenerateMiniDumpFile(pData);
// try to inform the user of what's happened
CString strMessage = FString("An Unhandled Exception occurred in %s\n\nUnfortunately, this requires that the application be terminated.", CFilename::GetModuleFilename());
// create the mini dump file
if (bMiniDumpSucceeded)
{
// let user know about the mini dump
strMessage.AppendFormat("\n\nOn a higher note, we have saved some diagnostic information in %s", m_filenameMiniDump.c_str());
}
// append any custom message(s)
if (!IsEmpty(m_strCustomizedMessage))
strMessage.AppendFormat("\n\n%s", m_strCustomizedMessage);
// cap it off with an apology
strMessage.Append("\n\nThis application must be terminated now. All unsaved data will be lost. We are deeply sorry for the inconvenience.");
// let the user know that things have gone terribly wrong
::MessageBox(GetAppWindow(), strMessage, "Internal Error - Unhandled Exception", MB_ICONERROR);
// indicate success or not
return bMiniDumpSucceeded;
}
//////////////////////////////////////////////////////////////////////////
// Instance Members
MiniDumper & MiniDumper::GetSingleton()
{
static std::auto_ptr<MiniDumper> g_pSingleton(new MiniDumper);
return *g_pSingleton.get();
}
bool MiniDumper::Initialize(bool bHookUnhandledExceptionFilter, const CFilename & filenameMiniDump, const CString & strCustomizedMessage, DWORD dwMiniDumpType)
{
// check if we need to link to the the mini dump function
if (!m_pWriteMiniDumpFunction)
{
try
{
// attempt to load the debug helper DLL
DynamicLinkLibrary dll("DBGHelp.dll", true);
// get the function address we need
m_pWriteMiniDumpFunction = (MINIDUMPWRITEDUMP_FUNC_PTR)dll.GetProcAddress("MiniDumpWriteDump", false);
}
catch (CCustomException &)
{
// we failed to load the dll, or the function didn't exist
// either way, m_pWriteMiniDumpFunction will be NULL
ASSERT(m_pWriteMiniDumpFunction == NULL);
// there is nothing functional about the mini dumper if we have no mini dump function pointer
return false;
}
}
// record the filename to write our mini dumps to (NOTE: we don't do error checking on the filename provided!)
if (!IsEmpty(filenameMiniDump))
m_filenameMiniDump = filenameMiniDump;
// record the custom message to tell the user on an unhandled exception
m_strCustomizedMessage = strCustomizedMessage;
// check if they're updating the unhandled filter chain
if (bHookUnhandledExceptionFilter && !m_bHookedUnhandledExceptionFilter)
{
// we need to hook the unhandled exception filter chain
m_pPreviousFilter = ::SetUnhandledExceptionFilter(&MiniDumper::UnhandledExceptionFilter);
}
else if (!bHookUnhandledExceptionFilter && m_bHookedUnhandledExceptionFilter)
{
// we need to un-hook the unhandled exception filter chain
VERIFY(&MiniDumper::UnhandledExceptionFilter == ::SetUnhandledExceptionFilter(m_pPreviousFilter));
}
// set type of mini dump to generate
m_dwMiniDumpType = dwMiniDumpType;
// record that we've been installed
g_bInstalled = true;
// if we got here, we must have been successful
return true;
}
bool MiniDumper::GenerateMiniDumpFile(ExceptionThreadData * pData)
{
// NOTE: we don't check this before now because this allows us to generate an exception in a different thread context (rather than an exception while processing an exception in the main thread)
ASSERT(g_bInstalled);
if (!g_bInstalled)
return false;
HANDLE hFile = ::CreateFile(m_filenameMiniDump.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
// indicate failure
return false;
}
else
{
// NOTE: don't use exception_info - its a #define!!!
Initialized<_MINIDUMP_EXCEPTION_INFORMATION> ex_info;
ex_info.ThreadId = pData->dwThreadID;
ex_info.ExceptionPointers = pData->pExceptionPointers;
// generate our mini dump
bool bStatus = FALSE != ((*m_pWriteMiniDumpFunction)(GetCurrentProcess(), GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)m_dwMiniDumpType, &ex_info, NULL, NULL));
// close the mini dump file
::CloseHandle(hFile);
return bStatus;
}
}
I apologize for the fact that this is not a drop-in solution. There are dependencies on other parts of my Toolbox library. But I think it would go a long way towards giving you the right idea as to how to build-in "capture a crash mini-dump" automatically from your code, which you can then combine with your .dsp files that you can make a normal part of your development cycle - so that when a .dmp comes in - you can fire up the debugger on it with your saved .pdb from your release build (which you don't distribute!) and you can debug the crash conditions quite easily.
The above code is an amalgam of many different sources - code snippets from debugging books, from MSDN documentation, etc., etc. If I have left out attribution I mean no harm. However, I do no believe that any of the above code is significantly created by anyone but myself.
Recompile just the file of interest without optimisations :)
In general:
Switch to interleaved disassembly mode. Single-stepping through the disassembly will enable you to step into function calls that would otherwise be skipped over, and make inlined code more evident.
Look for alternative ways of getting at values in variables the debugger is not able to directly show you. If they were passed in as arguments, look up the callstack - you will often find they are visible in the caller. If they were retrieved via getters from some object, examine that object; glance over the assembly generated by the code that calculates them to work out where they were stored; etc. If all else fails and disabling optimisations / adding a printf() distorts timings sufficiently to affect debugging, add a dummy global variable and set it to the value of interest on entry to the section of interest.
At least is not a IA64 dump...
There really isn't much you can do beyond having full dump and private symbols. Modern compilers have a field day with your code and is barely recognisable, specially if you add something like LTCG.
There are two things I found usefull:
Walk up the stack until you get a good anchor on what 'this' really points to. Most times when you are in an object method frame 'this' is unreliable because of registry optmizations. Usually several calls up the stack you get an object that has the correct address and you can navigate, member reference by member reference, until your crash point and have a correct value for 'this'
uf (Windbg's unassembly function command). This little helper can list a function dissasembly in a more manageable form than the normal dissasembly view. Because it follows jumps and code re-arranges, is easier to follow the logic of uf output.
The most important thing is to have the symbol files (*.pdb). You can generate them for release builds, by default they are not active.
Then you have to know that because of optimizations, code might get re-ordered, so debugging could look a bit jerky. Also some intermediate variables might have got optimized away. Generally speaking the behaviour and visibility of data might have some restrictions.
With Visual Studio C++ 2008 you can automatically debug the *.dmp files. I believe it also works for VS 2005. For older compilers I am afraid you´ll have to use WinDbg... (Also specify of course the *.pdb files for WinDbg, otherwise the info will be quite limited)