TL;DR: is my guess of a DLL loader lock deadlock correct in this instance and how can I be sure?
I have an intermittent deadlock (50%) in some code that involves CRT time functions and National Instruments DAQmx drivers (9.3.5f2). I'm using MSVC2008 Express to create an x86 executable (typical "release" settings, can supply if required) and I'm running on Win7 Pro x64. My code uses the time functions on the main thread and starts a new thread to handle updating an analogue output voltage (on a USB-6009):
#include <iostream>
#include <ctime>
#include <windows.h>
#include <process.h>
#include <NIDAQmx.h>
HANDLE g_TerminateEvent;
extern "C" unsigned int WINAPI DacUpdateThreadRunner(void *lpParam)
{
TaskHandle taskHandle;
DAQmxCreateTask("", &taskHandle);
DAQmxCreateAOVoltageChan(taskHandle, "Dev2/ao0", "", 0.0, 3.3, DAQmx_Val_Volts, "");
DAQmxStartTask(taskHandle);
float64 sample_value = 0.0;
bool quit = false;
while (!quit)
{
DWORD wait_result = WaitForSingleObject(g_TerminateEvent, 32);
if (wait_result == WAIT_OBJECT_0) quit = true;
else
{
DAQmxWriteAnalogScalarF64(taskHandle, 1, 1.0, sample_value, NULL);
}
}
DAQmxStopTask(taskHandle);
DAQmxClearTask(taskHandle);
return 0;
}
int main(void)
{
g_TerminateEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
unsigned int m_ThreadId;
uintptr_t m_Thread = _beginthreadex(NULL, 0, DacUpdateThreadRunner, NULL, 0, &m_ThreadId);
struct tm t;
time_t tt = time(NULL);
struct tm *temp = localtime(&tt);
memcpy(&t, temp, sizeof(struct tm));
for (int i = 0; i < 10; i++)
{
std::cout << "Main thread doing stuff " << i << std::endl;
Sleep(1000);
}
SetEvent(g_TerminateEvent);
CloseHandle((HANDLE)m_Thread);
return 0;
}
It only seems to deadlock if I have the call to localtime() in the code. Looking at the debug output in MSVS it seemed to lock while the 2nd thread was loading the (many) NI DLLs (the last DLLs to be loaded before the deadlock are National Instruments\MAX\mxs.dll, National Instruments\MAX\mxsutils.dll and SysWOW64\version.dll).
In the MSVC 2008 runtime localtime maps to localtime64() and apparently it uses thread local storage under Windows in order to be threadsafe.
I used WinDbg to get the call stacks (shown below) after the application deadlocked and used the !locks command but I cannot see why there would be a deadlock as I can't see any shared resource that both threads are locking. The locks command outputs Scanned 10 critical sections but nothing else (do I need to use a checked build of Windows?).
main thread:
ChildEBP RetAddr Args to Child
0035f078 77288df4 000001d0 00000000 00000000 ntdll_77250000!NtWaitForSingleObject+0x15
0035f0dc 77288cd8 00000000 00000000 00000000 ntdll_77250000!RtlpWaitOnCriticalSection+0x13e
0035f104 772a9520 773520c0 773271ca 0035f350 ntdll_77250000!RtlEnterCriticalSection+0x150
0035f144 751a1ee1 005e0000 0035f35c bf6b8258 ntdll_77250000!LdrGetDllHandleByMapping+0x3b
0035f304 751a1fd2 0035f350 0035f348 00000002 KERNELBASE!BasepLoadLibraryAsDataFileInternal+0x4f4
0035f324 751a2221 0035f350 0035f348 00000002 KERNELBASE!BasepLoadLibraryAsDataFile+0x19
0035f360 751993ad 0035f38c 00000000 006a7eb4 KERNELBASE!LoadLibraryExW+0x18a
0035f598 75199535 0035f630 72cbc018 00000002 KERNELBASE!ConvertTimeZoneMuiString+0xe4
0035f5bc 7519966b 0035f5d8 72cbbfc4 72cbc018 KERNELBASE!ConvertTimeZoneMuiStrings+0x155
0035f688 75199729 72cbbfc0 00000001 0035f6f0 KERNELBASE!GetTimeZoneInformationRaw+0x8c
0035f698 72c58d90 72cbbfc0 bf60abfe 0035f778 KERNELBASE!GetTimeZoneInformation+0xf
0035f6f0 72c59390 bf60aa2e 0035f778 00f625f8 MSVCR90!_set_timezone+0x168
0035f720 72c59e79 01103384 00f625f8 000001cc MSVCR90!__tzset+0x2e
0035f748 72c5a0b1 00f625f8 0035f778 00000001 MSVCR90!_localtime64_s+0x9f
0035f75c 01101107 0035f778 01103384 00000001 MSVCR90!_localtime64+0x1a
0035f784 011015e9 00000001 00f61850 00f62ba8 deadlock2!main+0x57 [c:\david\dev\nitests\deadlock2\deadlock2.cpp # 60]
0035f7c8 7509339a 7efde000 0035f814 77289ef2 deadlock2!__tmainCRTStartup+0x10f [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c # 586]
0035f7d4 77289ef2 7efde000 7732789a 00000000 KERNEL32!BaseThreadInitThunk+0xe
0035f814 77289ec5 01101731 7efde000 00000000 ntdll_77250000!__RtlUserThreadStart+0x70
0035f82c 00000000 01101731 7efde000 00000000 ntdll_77250000!_RtlUserThreadStart+0x1b
second thread:
ChildEBP RetAddr Args to Child
0276e618 77288df4 0000021c 00000000 00000000 ntdll_77250000!NtWaitForSingleObject+0x15
0276e67c 77288cd8 00000000 00000000 72c83b4e ntdll_77250000!RtlpWaitOnCriticalSection+0x13e
0276e6a4 72c42f2a 72cbbab8 0276e978 0276e6ec ntdll_77250000!RtlEnterCriticalSection+0x150
0276e6b4 72c48a70 00000007 bd23bbe2 00f69170 MSVCR90!_lock+0x30
*** ERROR: Symbol file could not be found. Defaulted to export symbols for mxsutils.dll -
0276e6ec 1b4fc523 0276e700 00000105 0276e978 MSVCR90!_getcwd+0x13
WARNING: Stack unwind information not available. Following frames may be wrong.
0276e80c 1b4fd45c 0276e81c 0276e9a4 1b5009e7 mxsutils!mxsCheckComponent+0x67c3
0276e838 1b515a05 0276e9a4 0276e978 00000000 mxsutils!mxsCheckComponent+0x76fc
0276e994 1b51542a 0276e9a4 00f619c0 0276e9b0 mxsutils!std::_Init_locks::operator=+0x1a4f
0276e9d8 1b502aa0 0276eaf0 00f69170 00f619c0 mxsutils!std::_Init_locks::operator=+0x1474
0276eb54 1b4f163f 00000001 00000001 006b0300 mxsutils!CodeProject3rdParty::mxs_mxExceptionFilter+0x320
0276eba8 1b502831 1b240000 1b529f40 00000001 mxsutils+0x163f
*** ERROR: Symbol file could not be found. Defaulted to export symbols for mxs.dll -
0276ebc8 1b2414e9 00000001 00000000 00f62540 mxsutils!CodeProject3rdParty::mxs_mxExceptionFilter+0xb1
0276edf8 1b24593c 1b240000 00000001 00000000 mxs+0x14e9
0276ee3c 1b2459f6 1b240000 0276ee68 77289950 mxs!std::_Init_locks::operator=+0x44c
0276ee48 77289950 1b240000 00000001 00000000 mxs!std::_Init_locks::operator=+0x506
0276ee68 7728d8c9 1b2459d8 1b240000 00000001 ntdll_77250000!LdrpCallInitRoutine+0x14
0276ef5c 7728d78c 00000000 75717046 00000000 ntdll_77250000!LdrpRunInitializeRoutines+0x26f
0276f0c8 7728c4d5 0276f12c 0276f0f4 00000000 ntdll_77250000!LdrpLoadDll+0x4d1
0276f100 751a2288 0276f0f4 0276f144 0276f12c ntdll_77250000!LdrLoadDll+0xaa
*** ERROR: Symbol file could not be found. Defaulted to export symbols for nidmxfu.dll -
0276f13c 6dd8b3ad 00000000 00000000 006b03fc KERNELBASE!LoadLibraryExW+0x1f1
0276f568 6dd8b4d3 0276f86c 6ded4a38 0276f92c nidmxfu!nNIMSAI100::tFilterPreferences::~tFilterPreferences+0x65cd
0276f584 6dc39d62 0276f6cc 0276f728 0276f870 nidmxfu!nNIMSAI100::tFilterPreferences::~tFilterPreferences+0x66f3
00000000 00000000 00000000 00000000 00000000 nidmxfu!nNIMS100::tAttributeDatabase::getAttributeValueForString+0x12432
My guess is that the main thread has locked an internal lock in the MSVCRT and then went to load a DLL which it cannot because thread 2 has a DLL loader lock. Thread 2 tries to use getcwd() from the MSVCRT which then results in the deadlock. Is that an accurate assessment? If not, how could I go about getting more information to make sure?
I could probably work around it by re-ordering some of the code (e.g. use wxDateTime or the NI code from the main thread to pre-load the DLLs) if I was confident that was the problem. However, I don't want to just hide it and have it re-appear and bite me later.
So is there a way for me to verify what has caused the deadlock in this case?
Your diagnosis is correct. tzset holds a lock while calling LoadLibrary. Meanwhile, _getcwd is waiting for that same lock. mxsutils is calling _getcwd from inside its DllMain. Like most functions, _getcwd is not safe to call from DllMain. A temporary workaround would be to make a dummy call to localtime from main before you create any threads. A long-term fix would be to change msxutils so it doesn't call unsafe functions from inside DllMain.
I notice that you are calling wxDateTime::Now() without doing any initialization of the wxWidgets system. My guess would be that wxDateTime::Now() is relying on something that is initialized when you do a normal wxWidgets initialization. Have you tried not even starting your other thread, but simply checking that wxDateTime::Now() works OK like this?
I also notice that you are using wxWidgets v2.9.2. Recommend you upgrade to v2.9.4. Apart from many improvements that might help your situation, these is a fix to a bug in wxDateTime. Might not help with current problem, but will fix a problem you don't yet know you have
Related
I'm currently facing an issue with a vector iterator in C++. The application runs on an ESP8266 NodeMCU microcontroller. As soon as I call the function CWebServer::getAvailableNetworks() (implementation can be found below), the program crashes and I get the following error:
User exception (panic/abort/assert)
Abort called
>>>stack>>>
ctx: cont
sp: 3ffffd10 end: 3fffffc0 offset: 0000
3ffffd10: 00000000 00000000 00000000 00000000
3ffffd20: 000000fe 00000000 00000000 00000000
3ffffd30: 00000000 00000000 00000000 b8b1aabc
3ffffd40: 3ffefd60 3fff44cc 00000000 40205e9c
3ffffd50: 3fff451c 00000001 3fff44fc 4020e7ea
3ffffd60: 00000000 00000000 00000000 4020e7fc
3ffffd70: 00000000 3ffffe0c 00000000 4020e219
3ffffd80: 3ffffe04 00000000 00000000 00000000
3ffffd90: 00000000 00000000 00000000 40226fac
3ffffda0: 00000000 40205e9c 3fff451c 40226fbd
3ffffdb0: 3fff44fc 3fff44cc 3fff44fc 402277d8
3ffffdc0: 00000000 00000000 3fff44fc 4020e224
3ffffdd0: 40000000 00000000 00000000 00000000
3ffffde0: 00000000 00000000 00000000 40226fac
3ffffdf0: 3ffefb6c 40205e9c 3fff451c 40226fbd
3ffffe00: 3fff44fc 4022770c 3fff44fc 40227783
3ffffe10: 3fff451c 00000001 3ffffe80 40209f32
3ffffe20: 3ffe90e4 3fffc200 3ffe90f1 4022f3b3
3ffffe30: 3fff43dc 3ffefa4c 3ffe8a37 4020ca74
3ffffe40: 4020ca68 3ffefa4c 3ffe8a37 40205e9c
3ffffe50: 00000001 3ffffe8c 3ffe90e5 4022f3f6
3ffffe60: 3ffffe80 00000001 3ffefa4c 40205e9c
3ffffe70: 00000001 00000001 3ffefa4c 40209915
3ffffe80: 00000000 00000000 00000000 3fff43e8
3ffffe90: 00000001 00000001 00000020 401009b7
3ffffea0: 3fff3d4c 3fffff00 3ffffee0 40205e9c
3ffffeb0: 00000001 00000001 3fff3c54 4021837a
3ffffec0: 3fffff00 3ffef94c 3fff3c54 401000e1
3ffffed0: 3fff3c54 3ffef94c 3fff3c54 40205ed8
3ffffee0: 3fff3d00 0015001f 8015001f 80fe8614
3ffffef0: 3fff3c54 3ffef94c 3ffef90c 40208526
3fffff00: 3fff3d4c 0015001f 00c6a700 00000000
3fffff10: 807a1200 3fff4400 0000005f 80007641
3fffff20: 3ffef94c 00000001 402183ac 00000001
3fffff30: 00000001 00000000 00001388 4020bb3e
3fffff40: 00000000 3fff43a4 3ffef90c 3ffefac8
3fffff50: 00000001 3ffef930 3ffef90c 402093ec
3fffff60: 40218d50 00000000 00001388 4020ca74
3fffff70: 00000000 3fff43a4 3ffe8a37 4020cd39
3fffff80: 3fffdad0 00000000 3ffefa88 402094b0
3fffff90: 3fffdad0 00000000 3ffefa88 4020a140
3fffffa0: feefeffe feefeffe 3ffefa88 4020e454
3fffffb0: feefeffe feefeffe 3ffe8614 40100cb9
<<<stack<<<
ets Jan 8 2013,rst cause:1, boot mode:(3,7)
load 0x4010f000, len 3456, room 16
tail 0
chksum 0x84
csum 0x84
va5432625
~ld
Here is the function that causes the problem ():
void CWebServer::getAvailableNetworks()
{
Serial.println("Get network scan result.");
bool statusSend = false;
try
{
std::string output = "{\"networks\":";
std::vector<sWiFi_Data*> data = CWiFiConnection::getAvailableNetworks();
if(data.size() <= 0)
{
output += "{}";
}
for(std::vector<sWiFi_Data*>::iterator it = data.begin(); it != data.end(); ++it)
{
// This line is for testing. Later on the JSON output will be calculated here from the Vector.
Serial.println(((*it)->SSID).c_str());
}
output += "}";
statusSend = true;
server.send(200, "application/json", output.c_str());
} catch(ScanException& e)
{
statusSend = true;
server.send(425);
} catch(std::exception e)
{
statusSend = true;
server.send(500);
Serial.println();
Serial.println("Unknown Exception while getting the network data:");
Serial.println(e.what());
Serial.println();
}
if(!statusSend) server.send(500);
}
This function should send the results of a network scan to the client. The network scan is simply done by calling the function WiFi.scanNetworks(true, true); which is part of the ESP8266WiFi.
The problem is caused by the line Serial.println(((*it)->SSID).c_str());
As soon as the program gets to this point, the error will show up and the program crashes. If I just delete this line and don't touch the vector at all, everything runs fine. So I assume that the vector iterator is the bad guy here.
Just for completence: as you can see the vector stores pointer to structs of type "sWiFi_Data".
This struct is defined in another class (the class that handles the WiFi connection) and it looks like this:
struct sWiFi_Data
{
std::string SSID;
std::string BSSID;
int32_t RSSI;
uint8_t channel;
uint8_t encryptionType;
bool isHidden;
};
As you may have noticed inside the CWebServer::getAvailableNetworks() function, the vector is the result of another function ( CWiFiConnection::getAvailableNetworks(); ). This function is inside the CWiFiConnection class. It looks like this:
std::vector<sWiFi_Data*> CWiFiConnection::getAvailableNetworks()
{
std::vector<sWiFi_Data*> data;
int8_t n = WiFi.scanComplete();
if(n == -1) throw ScanException("Warning: Trying to access network scan data while scan is not completed yet.");
if(n == -2) throw ScanException("Warning: Trying to access network scan, but scan was never triggered.");
if(n >= 0)
{
for(int i = 0; i < n; i++)
{
uint8_t encrytptionType = 0;
switch(WiFi.encryptionType(i)) {
case ENC_TYPE_NONE:
encrytptionType = 1; // None, Open Network
case ENC_TYPE_WEP:
encrytptionType = 2; // WEP
case ENC_TYPE_TKIP:
encrytptionType = 3; // WPA
case ENC_TYPE_CCMP:
encrytptionType = 4; // WPA 2
case ENC_TYPE_AUTO:
encrytptionType = 5; // Auto
default:
encrytptionType = 0; // Unknown
}
sWiFi_Data wifiData;
wifiData.SSID = WiFi.SSID(i).c_str();
wifiData.BSSID = WiFi.BSSIDstr(i).c_str();
wifiData.RSSI = WiFi.RSSI(i);
wifiData.channel = WiFi.channel(i);
wifiData.encryptionType = encrytptionType;
wifiData.isHidden = WiFi.isHidden(i);
data.push_back(&wifiData);
}
WiFi.scanDelete();
return data;
} else
{
throw ScanException("Warning: No networks found.");
}
}
By the way: the ScanException is just a generic exception that I wrote. Nothing fancy so I don't think that I would need to include the code here.
And just to clarify things, the procedure of communication looks like this:
Client send request to scan networks.
Server just calls the method: WiFi.scanNetworks(true, true); (Parameters: bool async, bool showHidden)
Because the scan is asynchronous, the client checks the result by sending a request to the server.
The server always responds to these requests by calling the CWebServer::getAvailableNetworks() function (our problem function).
In theory this function should reply with a code 425 ("not ready yet") if the result isn't there yet and should send the data of all available networks as a JSON if the scan is finished (this will be implemented where the line Serial.println(((*it)->SSID).c_str()); currently is.
By the way: I also tried to just output the vector's size inside the console. This works fine. So there are definitely values inside the vector.
Hope that anyone can help me out here. Thanks a lot.
Jannis
ps.: A documentation with examples for the network scan on an ESP8266 can be found here: https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/scan-examples.html
This line: data.push_back(&wifiData); stores the address of a temporary object wifiData which will be destroyed once the scope, i.e the enclosing for-loop iteration, is exited.
When you then later access any of these addresses it will (probably) cause a seg fault (if you are lucky).
Instead of having a std::vector<sWiFi_Data*> better use a std::vector<sWiFi_Data>
I noticed the EBP pointer on top of the stack frame is not quite right when a bare simple MFC's main application object is instantiated and this happens only in release build. Here is the code.
CMDIDemoApp::CMDIDemoApp()
{
// support Restart Manager
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS;
#ifdef _MANAGED
// If the application is built using Common Language Runtime support (/clr):
// 1) This additional setting is needed for Restart Manager support to work properly.
// 2) In your project, you must add a reference to System.Windows.Forms in order to build.
System::Windows::Forms::Application::SetUnhandledExceptionMode(System::Windows::Forms::UnhandledExceptionMode::ThrowException);
#endif
// breakpoint here, EBP is correct
// TODO: replace application ID string below with unique ID string; recommended
// format for string is CompanyName.ProductName.SubProduct.VersionInformation
SetAppID(_T("MDIDemo.AppID.NoVersion"));
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only CMDIDemoApp object
CMDIDemoApp theApp; // breakpoint here, EBP is not what I would expect
// CMDIDemoApp initialization
BOOL CMDIDemoApp::InitInstance()
{
// InitCommonControlsEx() is required on Windows XP if an application
// manifest specifies use of ComCtl32.dll version 6 or later to enable
// visual styles. Otherwise, any window creation will fail.
INITCOMMONCONTROLSEX InitCtrls; // breakpoint here again EBP is good
InitCtrls.dwSize = sizeof(InitCtrls);
// Set this to include all the common control classes you want to use
// in your application.
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinApp::InitInstance();
// Initialize OLE libraries
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
AfxEnableControlContainer();
EnableTaskbarInteraction(FALSE);
// AfxInitRichEdit2() is required to use RichEdit control
// AfxInitRichEdit2();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need
// Change the registry key under which our settings are stored
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(4); // Load standard INI file options (including MRU)
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_MDIDemoTYPE,
RUNTIME_CLASS(CMDIDemoDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CMDIDemoView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
{
delete pMainFrame;
return FALSE;
}
m_pMainWnd = pMainFrame;
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line. Will return FALSE if
// app was launched with /RegServer, /Register, /Unregserver or /Unregister.
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The main window has been initialized, so show and update it
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
return TRUE;
}
The stack at WinDbg is the following at breakpoint at line CMDIDemoApp theApp;
0:000> k
# ChildEBP RetAddr
00 0049fbdc 638381cd MDIDemo!`dynamic initializer for 'theApp'' [e:\projects\vs2015 projects\mdidemo\mdidemo\mdidemo.cpp # 55]
01 0049fbf8 001826c5 ucrtbase!_initterm+0x6d
02 0049fc3c 765d336a MDIDemo!__scrt_common_main_seh+0x7b [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl # 221]
03 0049fc48 76f59902 kernel32!BaseThreadInitThunk+0xe
04 0049fc88 76f598d5 ntdll!__RtlUserThreadStart+0x70
05 0049fca0 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> dc 0049fbdc
0049fbdc 00000e00 638381cd 00000000 00000000 .......c........
0049fbec 7efde000 00000005 1c53dd92 0049fc3c ...~......S.<.I.
0049fbfc 001826c5 00184604 00184618 04b2f942 .&...F...F..B...
0049fc0c 00000000 00000000 7efde000 0049fc00 ...........~..I.
0049fc1c 00000000 00000000 0049fc08 000000fd ..........I.....
0049fc2c 0049fc78 00182c2a 04e3677e 00000000 x.I.*,..~g......
0049fc3c 0049fc48 765d336a 7efde000 0049fc88 H.I.j3]v...~..I.
0049fc4c 76f59902 7efde000 6fe6f10a 00000000 ...v...~...o....
0:000> dc 0049fbf8
0049fbf8 0049fc3c 001826c5 00184604 00184618 <.I..&...F...F..
0049fc08 04b2f942 00000000 00000000 7efde000 B..............~
0049fc18 0049fc00 00000000 00000000 0049fc08 ..I...........I.
0049fc28 000000fd 0049fc78 00182c2a 04e3677e ....x.I.*,..~g..
0049fc38 00000000 0049fc48 765d336a 7efde000 ....H.I.j3]v...~
0049fc48 0049fc88 76f59902 7efde000 6fe6f10a ..I....v...~...o
0049fc58 00000000 00000000 7efde000 00000000 ...........~....
0049fc68 00000000 00000000 0049fc54 00000000 ........T.I.....
0:000> dc 0049fc3c
0049fc3c 0049fc48 765d336a 7efde000 0049fc88 H.I.j3]v...~..I.
0049fc4c 76f59902 7efde000 6fe6f10a 00000000 ...v...~...o....
0049fc5c 00000000 7efde000 00000000 00000000 .......~........
0049fc6c 00000000 0049fc54 00000000 ffffffff ....T.I.........
0049fc7c 76f958c5 195bcba2 00000000 0049fca0 .X.v..[.......I.
0049fc8c 76f598d5 001827b2 7efde000 00000000 ...v.'.....~....
0049fc9c 00000000 00000000 00000000 001827b2 .............'..
0049fcac 7efde000 00000000 00000000 00000000 ...~............
Notice that dc 0049fbdc should have yielded 0049fbf8 but instead it is 00000e00. Why does this happens and only in release build? It is indeed correct in debug build.
Also the EFP are correct when I set breakpoints in constructor (CMDIDemoApp::CMDIDemoApp()) or in any other function like CMDIDemoApp::InitInstance(). So it's like correct in any function but not quite right when the global object is declared!
This is different from my earlier question when EFP is simply incorrect even in regular functions like constructor and InitIntance() in that project. The purpose of this question is to provide this extra information because in this case we pretty know the code is not broken, it's a default mfc application without any change. This also qualifies as a separate question.
Update
The assembly code at line CMDIDemoApp theApp is:
0:000> u
MDIDemo!`dynamic initializer for 'theApp'' [e:\projects\vs2015 projects\mdidemo\mdidemo\mdidemo.cpp # 55]:
00ee1000 55 push ebp
00ee1001 8bec mov ebp,esp
00ee1003 68cc000000 push 0CCh
00ee1008 b9a892ee00 mov ecx,offset MDIDemo!theApp (00ee92a8)
00ee100d e86e0e0000 call MDIDemo!CMDIDemoApp::__autoclassinit2 (00ee1e80)
00ee1012 b9a892ee00 mov ecx,offset MDIDemo!theApp (00ee92a8)
00ee1017 e8a4050000 call MDIDemo!CMDIDemoApp::CMDIDemoApp (00ee15c0)
00ee101c 680040ee00 push offset MDIDemo!`dynamic atexit destructor for 'theApp'' (00ee4000)
The constructor assembly is the following
MDIDemo!CMDIDemoApp::CMDIDemoApp:
00ee15c0 55 push ebp
00ee15c1 8bec mov ebp,esp
00ee15c3 6aff push 0FFFFFFFFh
00ee15c5 68a83eee00 push offset MDIDemo!__scrt_stub_for_acrt_initialize+0x4c (00ee3ea8)
00ee15ca 64a100000000 mov eax,dword ptr fs:[00000000h]
00ee15d0 50 push eax
00ee15d1 51 push ecx
00ee15d2 a11490ee00 mov eax,dword ptr [MDIDemo!__security_cookie (00ee9014)]
00ee15d7 33c5 xor eax,ebp
00ee15d9 50 push eax
00ee15da 8d45f4 lea eax,[ebp-0Ch]
00ee15dd 64a300000000 mov dword ptr fs:[00000000h],eax
00ee15e3 894df0 mov dword ptr [ebp-10h],ecx
00ee15e6 6a00 push 0
00ee15e8 8b4df0 mov ecx,dword ptr [ebp-10h]
I'm in trouble with this:
I've installed Allegro5 on Ubuntu, and compiled my Helloworld project
#include <allegro5\allegro.h> #include <allegro5\allegro_native_dialog.h> int main(void) {
ALLEGRO_DISPLAY *display=NULL;
if(!al_init()) {
al_show_native_message_box(NULL, NULL, NULL, "failed to initialize allegro!", NULL, NULL);
return -1;
}
display=al_create_display(640,
480);
if(!display) {
al_show_native_message_box(NULL, NULL, NULL, "failed to initialize display!", NULL, NULL);
return -1;
}
al_destroy_display(display);
return 0;
}
with " g++ -Wall TestProgram.cc pkg-config --libs allegro-5.0 allegro_font-5.0 allegro_ttf-5.0 ".
Running it on terminal, it gives me this error (or crash?) message:
nac#NAC:~$ ./a.out
nouveau: kernel rejected pushbuf: Bad file descriptor
nouveau: ch0: krec 0 pushes 1 bufs 1 relocs 0
nouveau: ch0: buf 00000000 00000002 00000004 00000004 00000000
nouveau: ch0: psh 00000000 00000004a8 00000004bc
nouveau: 0x00107b00
nouveau: 0x00000000
nouveau: 0x20217000
nouveau: 0x00000003
nouveau: 0x1000f010
After some tests I saw that it crashes on or after "al_destroy_display(display);", in fact, after that error I must ctrl+C to end the program.
How can I do??
This question is a few months old, but it comes up as the first hit when searching for this error. I had the same error running LinuxMint 17.2 with Allegro 5.0.10, and solved it by updating my graphics card (GeForce GTX 460) driver. Hope this helps future users.
I had a similar problem with Rstudio (it is quite famous bug on rstudio)
It is proposed to run it using the following command in terminal:
QT_XCB_FORCE_SOFTWARE_OPENGL=1 rstudio
so, in your case i think:
QT_XCB_FORCE_SOFTWARE_OPENGL=1 ./a.out
I have one problem. I am trying to get stack offset range from /proc/self/maps pseudofile. But I have sometime weird things.
Here is my code
fp = fopen("/proc/self/maps", "r");
if (fp == NULL) {
perror("Error opening file");
return NULL;
}
while (fgets(line, 2048, fp) != NULL) {
if (strstr(line, "stack") != NULL) {
printf("%s", line);
}
}
If you start the programm with one or multiple thread you can view this pseudo file and get something like this
7f20423a6000-7f2042ba6000 rw-p 00000000 00:00 0 [stack:3936]
7fffbe95e000-7fffbe97f000 rw-p 00000000 00:00 0 [stack]
the first line here is stack of thread , the second line is the stack of the process.
But the problem is that sometimes I cannot get stack of thread. It can be from the first time or appear on some next execution so it is not determined. On some distos it doesn't show stack of thread at all, I don't think the problem is in different implementation of pseudo file in distros but in something other.
Please help to solve this problem
EDIT
I actually call this function inside thread , so I create thread through pthread_create(&tid, NULL, proc_stack, NULL);I have been also thinking about this. Maybe it needs some time to update this pseudofile after thread start, this is only one reason I see here.
EDIT2
I've tried to call sleep forcely , but this didn't help, but the most weird is that on one distro it shows thread stack, on another doesn't.
On my system Your program also dosn't show second stack segment, but it seems 5 segments are allocated above [heap] and one of them is used for thread stack (local variables of proc_stack() are stored in this segment).
Code I used to check for it (test.c):
#include <stdio.h>
#include <string.h>
#include <pthread.h>
void* proc_stack(void* p){
FILE *fp;
char line[2048];
fp = fopen("/proc/self/maps", "r");
if (fp == NULL) {
perror("Error opening file");
return NULL;
}
while (fgets(line, 2048, fp) != NULL) {
// if (strstr(line, "stack") != NULL) {
printf("%s", line);
// }
}
printf("addr = %p %p\n", &fp, &line);
return NULL;
}
int main(){
pthread_t tid;
void *rv;
proc_stack( NULL );
puts("main");
pthread_create( &tid, NULL, proc_stack, NULL );
pthread_join( tid, &rv );
return 0;
}
Compiled with gcc -Wall test.c -pthread. Results (some lines removed):
...
01933000-01954000 rw-p 00000000 00:00 0 [heap]
...
7fff75be3000-7fff75c04000 rw-p 00000000 00:00 0 [stack]
7fff75d97000-7fff75d98000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
addr = 0x7fff75c00e68 0x7fff75c00e70
main
...
01933000-01954000 rw-p 00000000 00:00 0 [heap]
7f3be0000000-7f3be0021000 rw-p 00000000 00:00 0
7f3be0021000-7f3be4000000 ---p 00000000 00:00 0
7f3be6b79000-7f3be6b7a000 rw-p 00000000 00:00 0
7f3be6b7a000-7f3be6b7b000 ---p 00000000 00:00 0
7f3be6b7b000-7f3be737b000 rw-p 00000000 00:00 0
...
7fff75be3000-7fff75c04000 rw-p 00000000 00:00 0 [stack]
7fff75d97000-7fff75d98000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
addr = 0x7f3be73796c8 0x7f3be73796d0
I would like to create process dump file at the moment when access violation that will not be handled occurred.
Currently, I have registered mine, unhandled exception callback with:
SetUnhandledExceptionFilter(CustomUnhandledExceptionFilter);
CustomUnhandledExceptionFilter creates dump file and prints call stack.
But this approach has one flaw - it is done when AV has already happened, AV exception is thrown and has not been handled by thread it happened in. Unhandled exception callback is called when exception is about to leave thread scope and dump created at this point has no local variables of function that exception occurred since stack pointer is lost.
Is there an way to over come this? I would like to take a look at stack of thread that got AV at the moment AV happened.
VS
#include "stdafx.h"
#include <windows.h>
#include <dbghelp.h>
LONG WINAPI MyUnhandledExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo)
{
HANDLE hFile = CreateFile(
L"proc.dmp",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
MINIDUMP_EXCEPTION_INFORMATION mei;
mei.ThreadId = GetCurrentThreadId();
mei.ClientPointers = TRUE;
mei.ExceptionPointers = ExceptionInfo;
MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hFile,
MiniDumpNormal,
&mei,
NULL,
NULL);
return EXCEPTION_EXECUTE_HANDLER;
}
int _tmain(int argc, _TCHAR* argv[])
{
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
int* p = NULL;
*p = 1;
return 0;
}
WinDbg
Microsoft (R) Windows Debugger Version 6.12.0002.633 X86
Copyright (c) Microsoft Corporation. All rights reserved.
Loading Dump File [D:\Documents\Visual Studio 2012\Projects\Test\Debug\proc.dmp]
User Mini Dump File: Only registers, stack and portions of memory are available
Symbol search path is: SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows 7 Version 7600 UP Free x86 compatible
Product: WinNt, suite: SingleUserTS
Machine Name:
Debug session time: Sat Dec 15 19:29:31.000 2012 (UTC + 4:00)
System Uptime: not available
Process Uptime: not available
......................
This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(8d8.1084): Access violation - code c0000005 (first/second chance not available)
eax=fffffffd ebx=005d0d78 ecx=0022f070 edx=778964f4 esi=005d0d38 edi=0022f110
eip=778964f4 esp=0022edd0 ebp=0022ede0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!KiFastSystemCallRet:
778964f4 c3 ret
0:000> .ecxr
eax=00000000 ebx=7ffdf000 ecx=0022fa30 edx=778964f4 esi=0022fcf4 edi=0022fdcc
eip=0124157c esp=0022fcf4 ebp=0022fdcc iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
*** WARNING: Unable to verify checksum for dump.exe
dump!wmain+0x3c:
0124157c c70001000000 mov dword ptr [eax],1 ds:0023:00000000=????????
0:000> dv
argc = 0n1
argv = 0x00280e38
p = 0x00000000
0:000> kb
*** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr Args to Child
0022fdcc 01241b19 00000001 00280e38 0027f9c8 dump!wmain+0x3c [d:\documents\visual studio 2012\projects\test\dump\dump.cpp # 35]
0022fe1c 01241d0d 0022fe30 76051194 7ffdf000 dump!__tmainCRTStartup+0x199 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c # 533]
0022fe24 76051194 7ffdf000 0022fe70 778ab495 dump!wmainCRTStartup+0xd [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c # 377]
0022fe30 778ab495 7ffdf000 7676831a 00000000 kernel32!BaseThreadInitThunk+0xe
0022fe70 778ab468 0124107d 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x70
0022fe88 00000000 0124107d 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> u .
dump!wmain+0x3c [d:\documents\visual studio 2012\projects\test\dump\dump.cpp # 35]:
0124157c c70001000000 mov dword ptr [eax],1
01241582 33c0 xor eax,eax
01241584 5f pop edi
01241585 5e pop esi
01241586 5b pop ebx
01241587 81c4cc000000 add esp,0CCh
0124158d 3bec cmp ebp,esp
0124158f e8c0fbffff call dump!ILT+335(__RTC_CheckEsp) (01241154)
0:000> !analyze -v
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
GetPageUrlData failed, server returned HTTP status 404
URL requested: http://watson.microsoft.com/StageOne/dump_exe/0_0_0_0/50cc9743/dump_exe/0_0_0_0/50cc9743/c0000005/0001157c.htm?Retriage=1
FAULTING_IP:
dump!wmain+3c [d:\documents\visual studio 2012\projects\test\dump\dump.cpp # 35]
0124157c c70001000000 mov dword ptr [eax],1
EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 0124157c (dump!wmain+0x0000003c)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000001
Parameter[1]: 00000000
Attempt to write to address 00000000
DEFAULT_BUCKET_ID: NULL_POINTER_WRITE
PROCESS_NAME: dump.exe
ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.
EXCEPTION_PARAMETER1: 00000001
EXCEPTION_PARAMETER2: 00000000
WRITE_ADDRESS: 00000000
FOLLOWUP_IP:
dump!wmain+3c [d:\documents\visual studio 2012\projects\test\dump\dump.cpp # 35]
0124157c c70001000000 mov dword ptr [eax],1
MOD_LIST: <ANALYSIS/>
FAULTING_THREAD: 00001084
PRIMARY_PROBLEM_CLASS: NULL_POINTER_WRITE
BUGCHECK_STR: APPLICATION_FAULT_NULL_POINTER_WRITE
LAST_CONTROL_TRANSFER: from 01241b19 to 0124157c
STACK_TEXT:
0022fdcc 01241b19 00000001 00280e38 0027f9c8 dump!wmain+0x3c [d:\documents\visual studio 2012\projects\test\dump\dump.cpp # 35]
0022fe1c 01241d0d 0022fe30 76051194 7ffdf000 dump!__tmainCRTStartup+0x199 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c # 533]
0022fe24 76051194 7ffdf000 0022fe70 778ab495 dump!wmainCRTStartup+0xd [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c # 377]
0022fe30 778ab495 7ffdf000 7676831a 00000000 kernel32!BaseThreadInitThunk+0xe
0022fe70 778ab468 0124107d 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x70
0022fe88 00000000 0124107d 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b
STACK_COMMAND: ~0s; .ecxr ; kb
FAULTING_SOURCE_CODE:
31: int _tmain(int argc, _TCHAR* argv[])
32: {
33: SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
34: int* p = NULL;
> 35: *p = 1;
36: return 0;
37: }
38:
SYMBOL_STACK_INDEX: 0
SYMBOL_NAME: dump!wmain+3c
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: dump
IMAGE_NAME: dump.exe
DEBUG_FLR_IMAGE_TIMESTAMP: 50cc9743
FAILURE_BUCKET_ID: NULL_POINTER_WRITE_c0000005_dump.exe!wmain
BUCKET_ID: APPLICATION_FAULT_NULL_POINTER_WRITE_dump!wmain+3c
WATSON_STAGEONE_URL: http://watson.microsoft.com/StageOne/dump_exe/0_0_0_0/50cc9743/dump_exe/0_0_0_0/50cc9743/c0000005/0001157c.htm?Retriage=1
Followup: MachineOwner
---------
Try using AddVectoredExceptionHandler. The thread context of the moment of exception is passed as an argument to the callback proc of this method.
To keep the exception context intact you can create the minidump from an outer process, which debugs the process of interest with DebugActiveProcess API and receives exception events as a part of debugging. Minidump creation preceding release of the debugee with ContinueDebugEvent preserves call stack and exception context.