Win32 API vector problem in callback
In the WndProc callback of my program I'm doing this to store a mouse click in a vector:
case WM_LBUTTONDOWN:
point = new POINT();
point->x = LOWORD (lParam);
point->y = HIWORD (lParam);
point_vector.push_back(point);
InvalidateRect(hWnd, NULL, TRUE);
break;
It compiles fine but when this runs, I get an access violation on the "push_back". Both "point" and "point_vector" are declared globally and seem valid in the debugger. If I declare them locally, no access violation. Why would this happen?
This is on VS10.
@Martyn Lovell Here is the call stack
msvcr100d.dll!operator delete(void * pUserData=0xfefefefe) Line 52 + 0x3 bytes C++ my_app.exe!std::allocator::deallocate(tagPOINT * * _Ptr=0xfefefefe, unsigned int formal=0) Line 182 + 0x9 bytes C++ my_app.exe!std::vector >::reserve(unsigned int _Count=1) Line 768 C++ my_app.exe!std::vector >::_Reserve(unsigned int _Count=1) Line 1298 C++ my_app.exe!std::vector >::push_back(tagPOINT * const & _Val=0x008e9d58) Line 992 C++ my_app.exe!WndProc(HWND * hWnd=0x000b060a, unsigned int message=513, unsigned int wParam=1, long lParam=19857987) Line 241 C++ user32.dll!774662fa()
[Frames below may be incorrect and/or missing, no symbols loaded for user32.dll] user32.dll!77466d3a() user32.dll!77466ce9() user32.dll!77466e44() user32.dll!774677c4() user32.dll!7746788a() my_app.exe!wWinMain(HINSTANCE__ * hInstance=0x00c80000, HINSTANCE__ * hPrevInstance=0x00000000, wchar_t * lpCmdLine=0x006c35d2, int nC开发者_JAVA百科mdShow=1) Line 62 + 0xc bytes C++ my_app.exe!__tmainCRTStartup() Line 547 + 0x2c bytes C my_app.exe!wWinMainCRTStartup() Line 371 C kernel32.dll!764c33ca() ntdll.dll!77e79ed2() ntdll.dll!77e79ea5()
And this is the line where it crashes in dbgdel.cpp (not sure if this is helpful) /* verify block type */ _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
@CoreyStup Doesn't seem to make any difference if the vars are local or global
Also this happens if I call other vector functions like resize(), clear() or reserve(), but not size().
Both "point" and "point_vector" ... seem valid in the debugger.
- By what measure do you think they are valid? The callstack implies the opposite.
- What does it look like before you try to push_back the first time?
This is the top of the callstack:
6. msvcr100d.dll!operator delete(void * pUserData=0xfefefefe) Line 52 + 0x3 bytes C++
5. my_app.exe!std::allocator::deallocate(tagPOINT * * _Ptr=0xfefefefe, unsigned int formal=0) Line 182 + 0x9 bytes C++
4. my_app.exe!std::vector >::reserve(unsigned int _Count=1) Line 768 C++
3. my_app.exe!std::vector >::_Reserve(unsigned int _Count=1) Line 1298 C++
2. my_app.exe!std::vector >::push_back(tagPOINT * const & _Val=0x008e9d58) Line 992 C++
1. my_app.exe!WndProc(HWND * hWnd=0x000b060a, unsigned int message=513, unsigned int wParam=1, long lParam=19857987) Line 241 C++
Let's examine it from the beginning:
1. my_app.exe!WndProc(HWND * hWnd=0x000b060a, unsigned int message=513, unsigned int wParam=1, long lParam=19857987) Line 241 C++
In 1 above, WM_LBUTTONDOWN arrives at WndProc.
2. my_app.exe!std::vector >::push_back(tagPOINT * const & _Val=0x008e9d58) Line 992 C++
In 2 above, you call push_back with a pointer to a newly created POINT instance on the heap.
3. my_app.exe!std::vector >::_Reserve(unsigned int _Count=1) Line 1298 C++
In 3 above, push_back calls the internal function _Reserve with a count of 1 to allocate memory for 1 POINT*
. This is because the vector is empty, since no element has been added yet, and the exponential growth scheme of this particular vector instance allocator starts with 1. (Adding another element would re-allocate new memory and copy the first element plus the new one there.)
4. my_app.exe!std::vector >::reserve(unsigned int _Count=1) Line 768 C++
In 4 above, _Reserve forwards its call to the reserve function.
5. my_app.exe!std::allocator::deallocate(tagPOINT * * _Ptr=0xfefefefe, unsigned int formal=0) Line 182 + 0x9 bytes C++
In 5 above, after having allocated space for the first POINT*
, reserve sees that the internal vector data pointer (in VS 2010 it's name is _Myfirst
) is non-null (see _Ptr=0xfefefefe above), so before pointing it at the new space just allocated, the old space of 0 (!) POINT*
elements must be freed.
Unfortunately, allocator::deallocate ignores that 0 elements are to be deallocated (could be a no-op) and happily tries to delete 0xfefefefe.
6. msvcr100d.dll!operator delete(void * pUserData=0xfefefefe) Line 52 + 0x3 bytes C++
In 6 above, the 0xfefefefe is unfortunately the VS debug representation of already freed memory, so delete chokes. What else can it do?
- But why is the internal vector data pointer 0xfefefefe?
- What did you really do to the vector before trying push_back?
- Exactly how did you declare the vector?
Strange it is.
OK, solved it. In a different part of my program I was calling:
_stprintf_s(msgbuf, 1024, _T("Mouse coordinates: %d %d\0"), mouse.x, mouse.y);
Should have been
_stprintf_s(msgbuf, sizeof(msgbuf), _T("Mouse coordinates: %d %d\0"), mouse.x, mouse.y);
This caused some sort of memory corruption because msgbuf length != 1024
I am such an ass. Apologies to everyone
精彩评论