VS2008: IOCP unhandled exception 0xC0000005 (WorkerThread in Verdacht)
-
Hi!
Wahrscheinlich wieder was völlig banales, aber ich komm nicht dahinter.
Immer beim Beenden des Programmes und nachdem schon mindestens ein Client connected hatte, (und wieder disconnected, das ist scheinbar egal) kamen Fehler:Erst gab es ein "stack around the variable 'dummy' was corrupted". Da kam ich drauf, dass ich AcceptEx einen lpOutputBuffer übergeben muss, der bis zum Ende der Operation lebt (und nicht nur bis zum Ende des Aufrufs), auch wenn man nix empfangen will.
Doch dann bekam ich:
Windows has triggered a breakpoint in ...exe. This may be due to a corruption of the heap, which indicates a bug in ...exe or any of the DLLs it has loaded. ... Call Stack: _free_base _CrtIsValidHeapPointer ... doexit exit ... _WinMainCRTStartupKonnte ich nicht lösen. Deshalb Minimalbeispiel erstellt:
#include <winsock2.h> #include <mswsock.h> #include <process.h> #include <commctrl.h> #include "resource.h" #pragma comment(lib, "comctl32.lib") #pragma comment(lib, "ws2_32.lib") #pragma comment(linker, "/MANIFESTDEPENDENCY:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") struct AcceptContext { OVERLAPPED overlapped; unsigned long socket; unsigned long dummy; }; void Initialize(); unsigned int __stdcall WorkerThread(void* param); int __stdcall DialogProcess(HWND dialogHandle, unsigned int message, WPARAM wParam, LPARAM lParam); void* completionPortHandle; int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { INITCOMMONCONTROLSEX initCommonControlsEx = { sizeof(INITCOMMONCONTROLSEX), ICC_STANDARD_CLASSES }; InitCommonControlsEx(&initCommonControlsEx); HWND dialogHandle = CreateDialog(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProcess); Initialize(); MSG message; while(GetMessage(&message, 0 , 0, 0)) { if(!IsDialogMessage(dialogHandle, &message)) { TranslateMessage(&message); DispatchMessage(&message); } } } void Initialize() { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); completionPortHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 2); unsigned long dummy; unsigned int dummySocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0); GUID guidAcceptEx = WSAID_ACCEPTEX; LPFN_ACCEPTEX AcceptExPtr; WSAIoctl(dummySocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx, sizeof(GUID), &AcceptExPtr, sizeof(LPFN_ACCEPTEX), &dummy, 0, 0); closesocket(dummySocket); for(unsigned int i = 0; i < 4; ++i) _beginthreadex(0, 0, WorkerThread, 0, 0, 0); unsigned int listeningSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED); CreateIoCompletionPort(reinterpret_cast<void*>(listeningSocket), completionPortHandle, 0, 0); SOCKADDR_IN address = { }; address.sin_family = AF_INET; address.sin_port = htons(6447); address.sin_addr.s_addr = inet_addr("192.168.0.2"); bind(listeningSocket, reinterpret_cast<SOCKADDR*>(&address), sizeof(SOCKADDR_IN)); listen(listeningSocket, 10); for(unsigned int i = 0; i < 8; ++i) { AcceptContext* acceptContext = new AcceptContext(); memset(&acceptContext->overlapped, 0, sizeof(OVERLAPPED)); acceptContext->socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED); AcceptExPtr(listeningSocket, acceptContext->socket, &acceptContext->dummy, 0, sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, 0, &acceptContext->overlapped); } } unsigned int __stdcall WorkerThread(void* param) { unsigned long bytesTransferred; unsigned long key; OVERLAPPED* overlapped = 0; GetQueuedCompletionStatus(completionPortHandle, &bytesTransferred, &key, &overlapped, INFINITE); // Es piepst bei connect() eines Clienten, .. klar Beep(100, 50); // Beendet der Thread nicht, gibt es scheinbar keinen Crash //while(true) //Sleep(1); return 0; } int __stdcall DialogProcess(HWND dialogHandle, unsigned int message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_COMMAND: { switch(LOWORD(wParam)) { case IDCANCEL: { DestroyWindow(dialogHandle); return true; } } break; } case WM_CLOSE: { DestroyWindow(dialogHandle); return true; } case WM_DESTROY: { PostQuitMessage(0); return true; } } return false; }Da kommt aber nun ein Fehler, sobald ich den dritten Client connecte (Ich öffne einfach 3x hintereinander eine Testapplication, die verbindet nur):
Unhandled exception at 0x7c93abd5 in ...exe: 0xC0000005: Access violation writing location 0x00cb0e98. No symbols are loaded for any call stack frame. The source code cannot be displayed.Nehme ich im WorkerThread die Kommentare weg, gibt es keinen Crash. Also wenn die worker threads nicht beendet werden, gibt es scheinbar keine Probleme...
(Ich weiß, dass zB. der WorkerThread anders aussehen müsste, aber dies soll halt ein Minimalbeispiel sein)
Was mache ich falsch? Muss man etwa irgendetwas beachten, wenn man einen worker thread schließt? (Immerhin, das System "weiß" vom Thread, denn mit GetQueuedCompletionStatus() wird der Thread u.A. mit dem completion port assoziiert).
-
omfg... natürlich was völlig banales!
Der "dummy", den ich AcceptEx übergebe, muss wohl mindestens (sizeof(sockaddr_in) + 16) * 2 groß sein, auch wenn man nix empfangen will... siehe MSDN
Ich schreib dann wieder hier rein, wenns den nächsten Crash gibt..
