none
How to debug an "Access violation reading location 0" not from a trivial error

    Question

  • I'm looking for some helpful suggestions about how to debug this problem.
    
    I get "First-chance exception at 0x01376e31 in InitUtil.exe: 0xC0000005: Access violation reading location 0x00000000."
    
    
    Some background on the situation:
    1) The code in the immediate area of the crash does work when called in very simple context, it only fails in a more complex situation.
    2) It will fail every time, in exactly the same place.
    3) The additional complexity has nested dialogs, lambda code, inheritance, and some use of pointers in classes.
    4) The last user interaction was to press OK on a dialog which should start a process of reading the double string from a text box, and convert it
       into a double member variable.
    
    
    One function higher in the call stack, text is "2.71": 
    
    	double getDouble( int id ) 
    	{
    		std::string text= getText( id );
    		std::stringstream ss ( text );
    		double retv;
    		ss >> retv;
    ===>	return retv;
    	}
    
    
    -		this	0x01414068 {dialogHwnd=0x00260552 controls=[12]({nextId=1002 classOfItem=Static textForItem="elevation" ...},{nextId=1002 classOfItem=Edit textForItem="20" ...},{nextId=1002 classOfItem=Static textForItem="height" ...},{nextId=1002 classOfItem=Edit textForItem="20" ...},{nextId=1002 classOfItem=Static textForItem="ratio" ...},{nextId=1002 classOfItem=Edit textForItem="2.71" ...},{nextId=1002 classOfItem=Static textForItem="fireplace" ...},{nextId=1002 classOfItem=Button textForItem="" ...},{nextId=1002 classOfItem=Static textForItem="description" ...},{nextId=1002 classOfItem=Edit textForItem="Covered with ice, overlooking the bay." ...},{nextId=1002 classOfItem=Button textForItem="Cancel" ...},{nextId=1002 classOfItem=Button textForItem="OK" ...}) }	ZX::Dialog * const
    +		dialogHwnd	0x00260552 {unused=??? }	HWND__ *
    +		controls	[12]({nextId=1002 classOfItem=Static textForItem="elevation" ...},{nextId=1002 classOfItem=Edit textForItem="20" ...},{nextId=1002 classOfItem=Static textForItem="height" ...},{nextId=1002 classOfItem=Edit textForItem="20" ...},{nextId=1002 classOfItem=Static textForItem="ratio" ...},{nextId=1002 classOfItem=Edit textForItem="2.71" ...},{nextId=1002 classOfItem=Static textForItem="fireplace" ...},{nextId=1002 classOfItem=Button textForItem="" ...},{nextId=1002 classOfItem=Static textForItem="description" ...},{nextId=1002 classOfItem=Edit textForItem="Covered with ice, overlooking the bay." ...},{nextId=1002 classOfItem=Button textForItem="Cancel" ...},{nextId=1002 classOfItem=Button textForItem="OK" ...})	std::vector<ZX::DialogControlBase,std::allocator<ZX::DialogControlBase> >
    		id	1005	int
    -		ss	{_Stringbuffer={...} }	std::basic_stringstream<char,std::char_traits<char>,std::allocator<char> >
    -		std::basic_iostream<char,std::char_traits<char> >	{...}	std::basic_iostream<char,std::char_traits<char> >
    +		std::basic_istream<char,std::char_traits<char> >	{_Chcount=0 }	std::basic_istream<char,std::char_traits<char> >
    +		std::basic_ostream<char,std::char_traits<char> >	{...}	std::basic_ostream<char,std::char_traits<char> >
    -		_Stringbuffer	{_Seekhigh=0x00b94dd4 "ýýýý««««««««" _Mystate=1 _Al={...} }	std::basic_stringbuf<char,std::char_traits<char>,std::allocator<char> >
    +		std::basic_streambuf<char,std::char_traits<char> >	{_Mylock={...} _Gfirst=0x00b94dd0 "2.71ýýýý««««««««" _Pfirst=0x00b94dd0 "2.71ýýýý««««««««" ...}	std::basic_streambuf<char,std::char_traits<char> >
    +		_Seekhigh	0x00b94dd4 "ýýýý««««««««"	char *
    		_Mystate	1	int
    +		_Al	{...}	std::allocator<char>
    		retv	-9.2559631349317831e+061	double
    +		text	"2.71"	std::basic_string<char,std::char_traits<char>,std::allocator<char> >
    
    
    
    
    And then the exception occurs on this code at the "====>"
    
    			_Myt& __CLR_OR_THIS_CALL operator>>(double& _Val)
    				{	// extract a double
    		01376DC0  push        ebp  
    		01376DC1  mov         ebp,esp  
    		01376DC3  push        0FFFFFFFFh  
    		01376DC5  push        offset __ehhandler$??5?$basic_istream@DU?$char_traits@D@std@@@std@@QAEAAV01@AAN@Z (13E6923h)  
    		01376DCA  mov         eax,dword ptr fs:[00000000h]  
    		01376DD0  push        eax  
    		01376DD1  push        ecx  
    		01376DD2  sub         esp,180h  
    		01376DD8  push        ebx  
    		01376DD9  push        esi  
    		01376DDA  push        edi  
    		01376DDB  push        ecx  
    		01376DDC  lea         edi,[ebp-190h]  
    		01376DE2  mov         ecx,60h  
    		01376DE7  mov         eax,0CCCCCCCCh  
    		01376DEC  rep stos    dword ptr es:[edi]  
    		01376DEE  pop         ecx  
    		01376DEF  mov         eax,dword ptr [___security_cookie (14124E8h)]  
    		01376DF4  xor         eax,ebp  
    		01376DF6  push        eax  
    		01376DF7  lea         eax,[ebp-0Ch]  
    		01376DFA  mov         dword ptr fs:[00000000h],eax  
    		01376E00  mov         dword ptr [ebp-10h],esp  
    		01376E03  mov         dword ptr [ebp-18h],ecx  
    				ios_base::iostate _State = ios_base::goodbit;
    		01376E06  mov         dword ptr [ebp-24h],0  
    				const sentry _Ok(*this);
    		01376E0D  push        0  
    		01376E0F  mov         eax,dword ptr [ebp-18h]  
    		01376E12  push        eax  
    		01376E13  lea         ecx,[ebp-34h]  
    		01376E16  call        std::basic_istream<char,std::char_traits<char> >::sentry::sentry (12F7FE0h)  
    		01376E1B  mov         dword ptr [ebp-4],0  
    				if (_Ok)
    		01376E22  lea         eax,[ebp-170h]  
    		01376E28  push        eax  
    		01376E29  lea         ecx,[ebp-34h]  
    		01376E2C  call        std::basic_istream<char,std::char_traits<char> >::sentry::operator int std::_Bool_struct::* (12F84CCh)  
    ====>	01376E31  mov         ecx,dword ptr [eax]  
    		01376E33  mov         dword ptr [ebp-184h],ecx  
    		etc
    
    The registers are:
    EAX = 00000000 EBX = 00000001 ECX = 0037D60C EDX = 0037D60C ESI = 0037DAB8 EDI = 0037D630 EIP = 01376E31 ESP = 0037D49C EBP = 0037D640 EFL = 00010246 
    
    so it is no surprise that I get an error from reading from address 0.
    
    
    The debugger shows these variables:
    
    -		this	0x0037d740 {_Chcount=0 }	std::basic_istream<char,std::char_traits<char> > * const
    -		std::basic_ios<char,std::char_traits<char> >	{_Mystrbuf=0x0037d758 _Tiestr=0x00000000 _Fillch=' ' }	std::basic_ios<char,std::char_traits<char> >
    +		std::ios_base	{_Stdstr=0 _Mystate=0 _Except=0 ...}	std::ios_base
    +		_Mystrbuf	0x0037d758 {_Seekhigh=0x00b94dd4 "ýýýý««««««««" _Mystate=1 _Al={...} }	std::basic_streambuf<char,std::char_traits<char> > *
    +		_Tiestr	0x00000000	std::basic_ostream<char,std::char_traits<char> > *
    		_Fillch	32 ' '	char
    		_Chcount	0	__int64
    		_Val	-9.2559631349317831e+061	double &
    +		_Ok	{_Ok=true }	std::basic_istream<char,std::char_traits<char> >::sentry
    		_State	0	int
    
    
    So I'm perplexed.  Is this a stack or heap corruption problem?  If so how does a local stringstream get into trouble?
    Any debugging hints are welcome.
    
    
    

    Monday, September 12, 2011 8:30 PM

Answers

  • The problem almost certainly was that my static library used    /vmg           

    http://msdn.microsoft.com/en-us/library/aa243604(v=VS.60).aspx

     and my main program did not do so.

    Evidence: The problem went away after I removed the /vmg from my static library, and returned when I put it back.

    I was using a static library that had a .props file I had forgotten about.  I remembered it only when preparing a shrunk version to submit, and VS10 mentioned the path to the .props file was incorrect in the shrunk version.  I actually made the same mistake 18 months ago and Lawrence Joel of Microsoft explained:

    Crt headers contain some PTM (Pointers to Members) type functions, in our case ostream file has a few instances of this. One source file (stream_err.cpp) includes a .h with /vmg which later also includes CRT headers like ostream. The code generated for stream_err will have PTM implemented in the general representation. Another source file (application.cpp) does not include the pragma but has similar CRT headers. The code generated for application.cpp will have PTM implemented based on the compiler decisions (if compiler can find enough info on PTM then it will choose the best case, else choose general case).

    The linker will take the obj files and will choose one of the PTM implementations (since their names and signature are the same). The Access Violation occurs because a routine will call the PTM routine assuming to have a return value represented in one way but it is represented in another way.

     

    Thursday, September 15, 2011 4:27 PM

All replies

  • On 9/12/2011 4:30 PM, Andrew7Webb wrote:

    I'm looking for some helpful suggestions about how to debug this problem.

    I get "First-chance exception at 0x01376e31 in InitUtil.exe: 0xC0000005: Access violation reading location 0x00000000."


    Some background on the situation:
    1) The code in the immediate area of the crash does work when called in very simple context, it only fails in a more complex situation.

    Look for heap corruption, likely in a seemingly unrelated piece of code.

    So I'm perplexed.  Is this a stack or heap corruption problem?

    Heap corruption would be my guess.

    If so how does a local stringstream get into trouble?

    It allocates its own internal data structures on the heap.


    Igor Tandetnik

    Monday, September 12, 2011 8:59 PM
  • Thanks for pointing me towards heaps.  I'll try some more debugging.
    
    I added this at the start of the program. 
    
    _CrtSetDbgFlag( _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_CHECK_CRT_DF | _CRTDBG_DELAY_FREE_MEM_DF );
    _ASSERTE( _CrtCheckMemory( ) );
    
    

    and also one call in:

    	double getDouble( int id ) 
    	{
    		_ASSERTE( _CrtCheckMemory( ) );
    
    		std::string text= getText( id );
    		std::stringstream ss ( text );
    		double retv;
    		ss >> retv;
    		return retv;
    	}
    
    

    But it did not result in any additional information.  

     

    Monday, September 12, 2011 9:25 PM

  • But it did not result in any additional information.  

    Debugging access violations, heap corruption and memory leaks is a bit of an art form. The problem with access violations and heap corruption is that the faulty code may permit the program to run for a considerable period of time until it crashes in some innocent section.

    My personal opinion is that a good code review, preferably with eyes other than your own, tends to be the most fruitful approach (and may uncover other unrelated problems to boot). Some material listed below may provide some help. If you come across other articles that are useful, I'd really like to hear from you so I can add it to my list.

    Native Code: Heap Corruption/Memory Leaks
    Enable the Page Heap
    How to use the PageHeap utility to detect memory errors in a Microsoft Visual C++ project
    How to use Pageheap.exe in Windows XP, Windows 2000, and Windows Server 2003
    Using Application Verifier to Troubleshoot Programs in Windows XP
    It is recommended to replace all occurrences of the unsafe buffer-copy APIs such as strcat, strcpy, or wcscpy with the secure ones like StringCchCopy, strcpy_s, and wcscpy_s, _mbscpy_s. You can use PREFast to find all unsafe uses of buffer-copy APIs, and replace them one by one.
    Memory Leak Detection Enabling
    Heap State Reporting Functions
    How can I Debug an Access Violation?
    Debugging Heap Corruption in Visual C++ Using Microsoft Debugging Tools For Windows
    Avoiding Buffer Overruns
    Debug Tutorial Part 3: The Heap
    Tuesday, September 13, 2011 2:27 AM
  • Looks like the problem was in the area of message loops with nested dialogs.  I have to program around it for now.

    This code

    	// Implement Win32 TRACE(...)
    	//
    	static void tracef( LPCTSTR lpszFormat, ... )
    	{
    #ifdef _DEBUG
    		static const int BUFFERSIZE =  0x800;
    		TCHAR    lpszBuffer[BUFFERSIZE];
    		va_list  fmtList;
     
    		va_start( fmtList, lpszFormat );
    		_vstprintf_s( lpszBuffer, lpszFormat, fmtList );
    		va_end( fmtList );
      
    		::OutputDebugString( lpszBuffer );
    #endif
    	}
    

    helped me understand when things went wrong with sanity check variables.

     

    tracef( "promptedInputDialog: sanityCheck= %x\n", sanityCheck );
    _ASSERTE( 0x123456 == sanityCheck );
    
    

     

     

     

     

     

     

     

    Wednesday, September 14, 2011 9:50 PM
  • Hello,

     

    Would you please upload a sample codes to skydriver? I think the codes your post here is no problem, maybe other codes cause this issue.

     

    It is not necessary that you send out the whole of your project. We just need a simplest sample to reproduce the problem. You can remove any confidential information or business details from it.

     

    Best regards,

    Jesse


    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, September 15, 2011 8:31 AM
    Moderator
  • The problem almost certainly was that my static library used    /vmg           

    http://msdn.microsoft.com/en-us/library/aa243604(v=VS.60).aspx

     and my main program did not do so.

    Evidence: The problem went away after I removed the /vmg from my static library, and returned when I put it back.

    I was using a static library that had a .props file I had forgotten about.  I remembered it only when preparing a shrunk version to submit, and VS10 mentioned the path to the .props file was incorrect in the shrunk version.  I actually made the same mistake 18 months ago and Lawrence Joel of Microsoft explained:

    Crt headers contain some PTM (Pointers to Members) type functions, in our case ostream file has a few instances of this. One source file (stream_err.cpp) includes a .h with /vmg which later also includes CRT headers like ostream. The code generated for stream_err will have PTM implemented in the general representation. Another source file (application.cpp) does not include the pragma but has similar CRT headers. The code generated for application.cpp will have PTM implemented based on the compiler decisions (if compiler can find enough info on PTM then it will choose the best case, else choose general case).

    The linker will take the obj files and will choose one of the PTM implementations (since their names and signature are the same). The Access Violation occurs because a routine will call the PTM routine assuming to have a return value represented in one way but it is represented in another way.

     

    Thursday, September 15, 2011 4:27 PM
  • Thanks for sharing the solution.

     

    Best regards,

    Jesse


    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, September 16, 2011 6:45 AM
    Moderator
  • Hi Andrew,

    I am also facing a similar access violation in following function : 

    static string CUtility::ConvHexString(const unsigned char* pData, int nLen)
    {
    stringstream ss;
    ss << hex << uppercase;
    for (int i = 0; i < nLen; i++)
    {
    ==> ss <<setfill('0') << setw(2) << (int)pData[i] << " ";
    }
    return ss.str();
    }

    The problem is reproducable at some complex scenario.

    But everytime its pointing the the line when we try to write on stringstream object ss.

    Files:

    Above function is defined in Utility.cpp(includes sstream) which includes Utility.h

    and Utility.h includes Log.h(includes sstream with #pragma once)

     

    I am using : 

    OS = WINDOWS 2008 R2

    VS2008 for develeopment : It doesn't have any PTM macros defined as of now. 

    Can you guide me more towards PTM usage in VS2008?

    Saturday, September 20, 2014 10:36 AM
  • If your error is trying to read location 0, it usually means that value of pData as passed from the calling functions is NULL.

    Since the problem is reproducible, you might add an assert before the for loop to confirm this.  Then you need to go back to the calling function and determine why it is passing a bad pointer value.

    Saturday, September 20, 2014 7:13 PM
  • Hi Barry..

    Thanks for your reply.

    Yes I tried and found that there is not a problem with pData , it has the valid value which is passed.

    setfill() and setw() also works fine,there comes a problem at final << operation when entire stream is ready to write on ss.

    Same code worked fine on a 32 bit OS.

    Now it suddenly gives problem when we run the same 32-bit(actually WOW64) application on 64-bit OS

    Saturday, September 20, 2014 8:41 PM