[Solved] PLEASE HELP... I think my QTcpSocket issue boils down to a bug in QIODevice... what do I do?
-
I have posted two unsolved threads on my issue with my application throwing an "Invalid address specified to RtlValidateHeap" triggering a User Breakpoint in dbgheap.c. The second is located "here":http://qt-project.org/forums/viewthread/47660/#195161 and it links to the first.
I now believe that this is the result of a bug in Qt. In order to substantiate my case (or appeal to someone's understanding to correct me where I am wrong) I am going to post my reasoning for believing this. Here is exactly where in dbgheap.c the crash occurs:
@
/***
*int _CrtIsValidHeapPointer() - verify pointer is from 'local' heap
*
*Purpose:-
Verify pointer is not only a valid pointer but also that it is from
-
the 'local' heap. Pointers from another copy of the C runtime (even in the
-
same process) will be caught.
*Entry:
-
const void * pUserData - pointer of interest
*Return:
-
TRUE - if valid and from local heap
-
FALSE otherwise
*******************************************************************************/
extern "C" _CRTIMP int __cdecl _CrtIsValidHeapPointer(
const void * pUserData
)
{
if (!pUserData)
return FALSE;if (!_CrtIsValidPointer(pHdr(pUserData), sizeof(_CrtMemBlockHeader), FALSE)) return FALSE; return HeapValidate( _crtheap, 0, pHdr(pUserData) ); // THIS LINE IS WHERE CRASH OCCURS
}
@Given the location of the crash, I doubt the problem is that it is a bad pointer.
I have traced these problems into the qt code as far as it would allow me (which includes qabstractsocket.cpp) without needing a visual studio debug file that is missing and have identified where the problem is occurring. I have also identified what is happening from the stack trace which I have posted below. Pay particular attention to lines 9-10.
@
ntdll.dll!77cefadc() Unknown
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!77cb272c() Unknown
ntdll.dll!77c7e1ef() Unknown
KernelBase.dll!75ca468e() Unknown
msvcr100d.dll!_CrtIsValidHeapPointer(const void * pUserData) Line 2036 C++
msvcr100d.dll!_free_dbg_nolock(void * pUserData, int nBlockUse) Line 1322 C++
msvcr100d.dll!_free_dbg(void * pUserData, int nBlockUse) Line 1265 C++
msvcr100d.dll!operator delete(void * pUserData) Line 54 C++
msvcr100d.dll!operator delete[](void * p) Line 21 C++
Qt5Cored.dll!66f80e54() Unknown
Qt5Cored.dll!66f88bc8() Unknown
Qt5Networkd.dll!QAbstractSocket::close() Line 2597 C++
Qt5Networkd.dll!QAbstractSocket::abort() Line 2301 C++
AppCore.dll!AppCore::BidirectionalTcpConnection::abortConnection() Line 184 C++
MyApp.exe!MyApp::MyMainWindow::loginFinish() Line 763 C++
@in line 10 an array is deleted. The problem occurs on the first element in the array. Here is the last line of code in qabstractsocket.cpp that gets executed before the error occurs:
@
QIODevice::close();
@Here is the method called above. Note my comments
@
void QIODevice::close()
{
Q_D(QIODevice);
if (d->openMode == NotOpen)
return;#if defined QIODEVICE_DEBUG
printf("%p QIODevice::close()\n", this);
#endif#ifndef QT_NO_QOBJECT
emit aboutToClose();
#endif
d->openMode = NotOpen;
d->errorString.clear(); // THIS SIMPLY ASSIGNS AN EMPTY STRING
d->pos = 0;
d->seqDumpPos = 0;
d->buffer.clear(); // THIS CALLS THE CODE BELOW AND IS THE ONLY ARRAY HERE
d->firstRead = true;
}
@Here is the code where the buffer is cleared. Note my comment.
@
void clear() {
len = 0;
delete [] buf; // THIS CORRESPONDS TO ARRAY DELETION CALL IN THE STACK TRACE
buf = 0;
first = buf;
capacity = 0;
}
@Please note that in the usage of my own class I explicitly did the following to avoid allocation of any data on any other heap than the dll in which the class is located. You may check "this post on stackoverflow":http://stackoverflow.com/questions/26045662/invalid-address-specified-to-rtlvalidateheap-in-cross-dll-application-when-using to confirm (where I posted updated code).
I made sure any data that was sent to the constructor was copied to the class variables.
I made sure that any QByteArray sent over the socket was copied locally within the class. (I only sent data of this type).
After posting the stackoverflow article I overloaded the new operator to make certain any instance of the class was allocated on the dll's heap. (see below).
Here are the overloaded operators:
@
void* BidirectionalTcpConnection::operator new(size_t bytes) { return ::operator new(bytes); }
void BidirectionalTcpConnection::operator delete(void* p) { ::operator delete(p); }
@In addition, I performed the following steps to make sure the crash wasn't caused by double data deletions or an unflushed buffer.,,
Made sure that any data sent over the socket was not deleted (which actually causes a memory leak).
Made sure that the data WAS sent over the socket (this was confirmed by the code in the receiving server and code that parses the received data being executed)
The only conclusion that I can currently draw is that the buffer itself is corrupted or at the very least is being allocated on a heap that is not the same as the AppCore.dll heap. This is something that is beyond my control and needs to be addressed.
*So what should I do? *FYI I am using Qt 5.2.1, 32 bit msvc2012 build.
-
-
Please file a bug report, and/ or ask on Qt development mailing list. "Link":https://qt-project.org/contribute.
You can also try with Qt 5.3.2 or 5.4 alpha.
-
Hi,
I haven't looked through your code in depth, but I noticed that your code is quite complex, and you have multiple threads and multiple DLLs.
Let's try to simplify the problem first.
What happens if you start removing functions that aren't involved in the crash? Are you able to produce a simpler example of the crash that's easier for readers to follow?
What happens if you make your program single-threaded?
What happens if you build a standalone executable from your code, rather than creating a DLL?
On the topic of multithreading,
Have you made sure that every function is run in the correct thread?
Are you accessing any data/objects from multiple threads? If so, have you ensured that it's safe to do so?
In some signal-slot connections, you have specifically asked for Qt::DirectConnection and Qt::QueuedConnection. How did you decide which one to use?
-
I can do as you ask in a separate application that tests the class and will need to anyway if I submit a bug report.
I may be able to merge the client and server engines into the main executable (and if I can do that then I can merge the class creating the problem).
However, this application is very complex by nature. I would prefer to keep the client and server separate because as explained in the previous threads (linked at the beginning) the application is meant to act as a client and/or a server depending on 1) the machine's assigned role within the network and 2) the user's login credentials. Keeping them separate keeps unneeded functionality out of memory. This is also an application that will eventually work with hundreds if not thousands of plugins on the client side so having a core.dll that contains basic functionality and interfaces is necessary. And of course plugins must have their own dlls.
FYI the plugins are of two plugin class interfaces. One interface will be inherited by a dozen or so classes and these may need to run concurrently. The other interface will be used by hundreds if not thousands of plugin classes and will only run one at a time.
I am convinced that threading is not the issue. There are no separate threads on the side that is causing the current problem (the client side). The client socket is the one crashing. The server socket is working fine (except that it hasn't reached the code yet where it disconnects because the client does the disconnecting). The server (which is multi-threaded) receives and responds to messages sent over the socket just fine (although that wasn't always the case. But "here again...":http://qt-project.org/forums/viewthread/47597/ the issue was related to the buffer... an array as I could not read the last element in the buffer). Now it is only when I try to abort/close the socket on the client side that I run into a problem.
-
Now that is what I call vindication. Qt 5.3.2 works without incident!
-
Please make sure you keep the code as it is now (i.e. make a snapshot) and, should later versions of Qt crash, create a bug report specifying your history (the kinds of crashes in versions earlier that 5.3.1, the crash in 5.3.1, and the fact that it no longer crashes in 5.3.2), this is important as regressions do occur in Qt.
If you think you can find the time for this, it would also be worth it to create a bug report to alert the developers about this issue (i.e. your code works in 5.3.2 but crashes in 5.3.1 and previous), it happens sometimes that a bug is "inadvertently" fixed when some related code changes are made, all without the developers not even knowing.
PS
There's also another possibility: you are actually doing something wrong in there, and 5.3.2 is simply no longer catching the problem which does exist in your code.