[SOLVED] QSerialPort and Invalid address specified to RtlFreeHeap
-
I have encountered a problem which is connected with QSerialPort. I am receiving a message from debugger as follows:
Invalid address specified to RtlFreeHeap
Inside function call list window I was able to identify it as a problem with QSerialPort. Furthermore, I have narrowed the problem to the read() method from QSerialPort class. Is there something that can be done about it? -
Please give simple example project that reproduce a problem. Also, what version of QtSerialPort do you use?
-
Unfortunately for me I can not reproduce this error with simple example. This does not occur with just reading the data from QSerialPort.
I think that it can be something connected to threads and simultaneous access to the memory. However, I have also excluded that because I have a wrapper class for QSerialPort and mutex which guards the access to the device. So, I think this is not the case. -
It means that most likely your problem in the your application with lot of threads and mutexes. I at all don't understand, why you to use threads (with mutexes). For me it is strange approach...
-
I am using threads and mutexes because I share memory between them.
Yes, it may seem that the problem is with all the threads. However, using QSerialPort wasn't my first shoot. Before that I have written a library which works both for Windows and Linux system. It was fine until I decided to abandon this because I wanted to focus on the application development not on the interfaces. Also I have tested serial port support from ASIO boost. It was very good solution and it worked. Once again I also decided to abandon this because of long time which is required for compilation, and as far as I know it doesn't have forward declarations to speed up the process.
As you can see this is not the problem with multiple threads and mutexes. It has something to do with the QSerialPort.
Furthermore, Invalid address specified to RtlFreeHeap isn't the only problem I have got with QSerialPort. In early Qt 5 versions when it had support for this class almost out of the box it had some problems with QStreams. Now, it has problems with memory deallocation (in debug mode) and with QList (element out of the reach in release mode).
Are there any other good alternatives which have multi platform support and are relatively light? -
[quote]
Furthermore, Invalid address specified to RtlFreeHeap isn’t the only problem I have got with QSerialPort. In early Qt 5 versions when it had support for this class almost out of the box it had some problems with QStreams.
[/quote]These are all unfounded statements which have no value. And it isn't important that you there wrote your wrappers at yourselves earlier.
You at all didn't provide any code. Therefore, most likely a problem in your code.
[quote]
Are there any other good alternatives which have multi platform support and are relatively light?
[/quote]Use boost::asio or your custom wrapper, what problem?
-
This is exactly why I have written what I had used before. Therefore, I'm pretty convenient that the error isn't because of my code. Also I've given a reason why I don't use other solutions any more.
Here is the function trace when I get the message with error:
0 ntdll!RtlpNtSetValueKey C:\Windows\SYSTEM32\ntdll.dll 0x770713f7
1 ntdll!RtlpNtSetValueKey C:\Windows\SYSTEM32\ntdll.dll 0x77070311
2 ntdll!LdrSetAppCompatDllRedirectionCallback C:\Windows\SYSTEM32\ntdll.dll 0x77024e37
3 ?? 0x1662d998
4 ntdll!RtlFreeHeap C:\Windows\SYSTEM32\ntdll.dll 0x76fcfac9
5 msvcrt!free C:\Windows\SysWOW64\msvcrt.dll 0x767b9a15
6 ?? 0x141d0000
7 QArrayData::deallocate 130 0x6b799e14
8 QTypedArrayData<char>::deallocate 234 0x6b9cb89d
9 QByteArray::resize 1448 0x6b79bc2b
10 QRingBuffer::append 383 0x6458963e
11 QSerialPortPrivate::_q_completeAsyncRead 608 0x645855af
12 QSerialPort::qt_static_metacall 348 0x64582d8e
13 QMetaObject::activate 3680 0x6b954ee9
14 QMetaObject::activate 3546 0x6b95484e
15 QWinEventNotifier::activated 134 0x6b9ad11d
16 QWinEventNotifier::event 241 0x6b976955
17 QApplicationPrivate::notify_helper 3522 0x8c1e09f
18 QApplication::notify 2975 0x8c1bb51
19 QCoreApplication::notifyInternal 935 0x6b929dde
20 QCoreApplication::sendEvent 237 0x6b9cf187
21 QEventDispatcherWin32Private::activateEventNotifier 335 0x6b978188
22 QEventDispatcherWin32::processEvents 759 0x6b979887
23 QWindowsGuiEventDispatcher::processEvents 80 0x6285cdc0
24 QEventLoop::processEvents 136 0x6b927e84
25 QEventLoop::exec 212 0x6b92811f
26 QCoreApplication::exec 1188 0x6b92a42d
27 QGuiApplication::exec 1450 0xb062e2
28 QApplication::exec 2767 0x8c1b495
29 qMain main.cpp 10 0x401653
30 WinMain@16 131 0x408a7d
31 main 0x41cccdIf you could please look at entry 8 to 12 you will see that something is going on with QSerialPort. I get this message randomly but mos often at the very beginning of the transmission.
-
It doesn't speak about anything that problem is in QtSerialPort. Once again I will repeat: most likely you do something wrong (I am sure). But without a source code I can help nothing.
UPD: The most important mistake - the QtSerialPort can't use from different threads (even if to use mutexes, etc.). Because internally the QtSerialPort works not as you think.
-
How it doesn't say nothing about QSerialPort? There are:
11 QSerialPortPrivate::_q_completeAsyncRead 608 0×645855af
12 QSerialPort::qt_static_metacall 348 0×64582d8e
which indicates that it operates on the memory and then the crash occurs.When I've used for example boost for reading from serial port nothing like that happened.
Update:
Here is the source code responsible for reading data from QSerialPort:@
int ComPort::read( char * Buffer, int Count)
{
int i;mutex.lock(); if( !_Port.isOpen()) { mutex.unlock(); return -2; } int available_bytes; available_bytes = _Port.bytesAvailable(); if( Count <= available_bytes) available_bytes = Count; qDebug() << "<- in"; i = _Port.read( Buffer, available_bytes); qDebug() << "-> out"; mutex.unlock(); return i;
}
@During debugging I can only get "<- in" string but no "-> out".
Update:
So, is there a workaround to do this? I mean using QSerialPort from another thread. -
bq. Here is the source code responsible for reading data from QSerialPort:
This is wrong. Because port.read() reads data from the internal buffer of class (QRingBuffer). Thus, this internal buffer isn't protected on write to it. This writing to the read buffer (buffer.append()) is carried out inside of the class when RX_EVENT triggered. So, it lead to data corruption in your case.
So, you all do wrong..
bq. So, is there a workaround to do this? I mean using QSerialPort from another thread.
You should move whole QtSerialPort instance to another thread (i.e. access to the all serial port's methods has to be provided always from one thread). And then use signals/slots for data transferring. In this case the mutexes do not need at all.
-
I did what you suggested with several variations.
Like before I have wrapper class for QSerialPort:@ ComPort::ComPort(QObject *parent) :
_BytesWaiting(0),
_BaudRate( QSerialPort::Baud115200),
_Parity( QSerialPort::NoParity),
_StopBits( QSerialPort::OneStop),
_FlowControl( QSerialPort::NoFlowControl),
_DataBits( QSerialPort::Data8),
QObject(parent),
Stream(Buffer)
{
ThreadCom = new QThread;
_Port = new QSerialPort();connect(_Port, SIGNAL(readyRead()), this, SLOT(handleReadyRead())); _Port->moveToThread( ThreadCom); ThreadCom->start();
}@
Also in the GUI I have:
@ ThreadForCom = new QThread;
SerialPort = new ComPort::ComPort();
SerialPort->moveToThread(ThreadForCom);ThreadForCom->start();@
However, this doesn't work. I don't get any data. But when in my wrapper class I let go of QThread:
@ ComPort::ComPort(QObject *parent) :
_BytesWaiting(0),
_BaudRate( QSerialPort::Baud115200),
_Parity( QSerialPort::NoParity),
_StopBits( QSerialPort::OneStop),
_FlowControl( QSerialPort::NoFlowControl),
_DataBits( QSerialPort::Data8),
QObject(parent),
Stream(Buffer)
{
_Port = new QSerialPort();connect(_Port, SIGNAL(readyRead()), this, SLOT(handleReadyRead()));
}@
It works but not completely. It seams that I'm loosing data and also the messages which I get are corrupted.
Edit:
Here is how I handle the oncoming data:
@ void ComPort::handleReadyRead(void)
{
mutex.lock();
Buffer.append(_Port->readAll());
mutex.unlock();
}@Here is reading procedure:
@int ComPort::read( char * Buffer, int Count)
{
mutex.lock();if( !_Port->isOpen()) { mutex.unlock(); return -2; } int available_bytes; available_bytes = this->Buffer.count(); if( Count <= available_bytes) available_bytes = Count; memcpy( Buffer, this->Buffer.data(), available_bytes); this->Buffer.remove(0, available_bytes); mutex.unlock(); return available_bytes;
}@
-
@
class Worker : public QSerialPort
{
public:
Worker(QObject *parent = 0)
: QSerialPort(parent)
{open(...); setBaudRate(...); ... setParity(...); conenct(this, SIGNAL(readyRead()), this, SLOT(handleReadyRead())); }
signals:
void dataReceived(constQByteArray &data);private slots:
void handleReadyRead()
{
const QByteArray data = readAll();
emit dataReceived(data);
}
}...
worker = new Worker();
thread = new QThread();
worker->moveToThread(thread);
thread->start();
...
@ -
I did apply your suggestions. Now, I don't have a single mutex in my application. After some changes everything is working in signal/slot spirit. However, it seems like data are being lost, actually like lots of it is corrupted. This also happened before the change. What can be responsible for this?
-
bq. However, it seems like data are being lost, actually like lots of it is corrupted.
It can't be in principle (impossible).
bq. What can be responsible for this?
Try to check for correct configuration of your serialport.
-
Problem was solved. Now everything works just fine.
The reason for the message being corrupted was the way of handling the data. It required me to remove the data from temporary buffer. Unless the algorithm would look for start sequence inside the data which has been already processed.To sum up the main problem of the Invalid address specified to RtlFreeHeap. QSerialPort can't be used between threads even the memory is protected by mutexes.