I have defined a base class using std::thread. For the child class, I perform some initialization of member variables and then start the thread using m_thread.reset(new std::thread(&MyClass::ThreadMain, this)); where m_thread is a member of MyClass. The purpose of the class is to read data from a serial port and report to a parent. The posix message queue handle of the parent is passed to MyClass during initialization before the thread is created. On running I get exceptions and I see that member variables that were initialized before the thread started appear to be no longer valid using the watch in GDB.
I tried running through Valgrind and got these errors:
==10108== Syscall param msgsnd(msgp->mtext) points to uninitialised byte(s) ==10108== at 0x4A7C512: msgsnd (syscall-template.S:81) ==10108== by 0x19C3B: QxRadio::SendToParent(unsigned char*, unsigned char) (QxRadio.cpp:201) ==10108== by 0x19A9F: QxRadio::ThreadMain() (QxRadio.cpp:158) ==10108== by 0x1AB5D: void std::_Mem_fn::operator()<, void>(QxRadio*) const (in /root/ESSE/sourcecode/Firmware/QxxToolRadioDriver/Output/BIN/QXRD) ==10108== by 0x1AADF: void std::_Bind_simple (QxRadio*)>::_M_invoke<0u>(std::_Index_tuple<0u>) (functional:1700) ==10108== by 0x1A9EF: std::_Bind_simple (QxRadio*)>::operator()() (functional:1688) ==10108== by 0x1A991: std::thread::_Impl (QxRadio*)> >::_M_run() (thread:115) ==10108== by 0x4917117: ??? (in /usr/lib/arm-linux-gnueabihf/libstdc++.so.6.0.20) ==10108== Address 0x56d6bbc is on thread 2's stack ==10108== in frame #1, created by QxRadio::SendToParent(unsigned char*, unsigned char) (QxRadio.cpp:188) ==10108== Uninitialised value was created by a stack allocation ==10108== at 0x19B5E: QxRadio::SendToParent(unsigned char*, unsigned char) (QxRadio.cpp:188)
==10108== Thread 2: ==10108== Syscall param read(fd) contains uninitialised byte(s) ==10108== at 0x4864580: read (syscall-template.S:81) ==10108== by 0x1994D: QxRadio::ThreadMain() (QxRadio.cpp:113) ==10108== by 0x1AB5D: void std::_Mem_fn::operator()<, void>(QxRadio*) const (in /root/ESSE/sourcecode/Firmware/QxxToolRadioDriver/Output/BIN/QXRD) ==10108== by 0x1AADF: void std::_Bind_simple (QxRadio*)>::_M_invoke<0u>(std::_Index_tuple<0u>) (functional:1700) ==10108== by 0x1A9EF: std::_Bind_simple (QxRadio*)>::operator()() (functional:1688) ==10108== by 0x1A991: std::thread::_Impl (QxRadio*)> >::_M_run() (thread:115) ==10108== by 0x4917117: ??? (in /usr/lib/arm-linux-gnueabihf/libstdc++.so.6.0.20) ==10108== Uninitialised value was created by a stack allocation ==10108== at 0x4A0BF40: __libc_sigaction (sigaction.c:62)
==10108== ==10108== Warning: invalid file descriptor 67266232 in syscall read() ==10108== at 0x4864580: read (syscall-template.S:81) ==10108== by 0x1994D: QxRadio::ThreadMain() (QxRadio.cpp:113) ==10108== by 0x1AB5D: void std::_Mem_fn::operator()<, void>(QxRadio*) const (in /root/ESSE/sourcecode/Firmware/QxxToolRadioDriver/Output/BIN/QXRD) ==10108== by 0x1AADF: void std::_Bind_simple (QxRadio*)>::_M_invoke<0u>(std::_Index_tuple<0u>) (functional:1700) ==10108== by 0x1A9EF: std::_Bind_simple (QxRadio*)>::operator()() (functional:1688) ==10108== by 0x1A991: std::thread::_Impl (QxRadio*)> >::_M_run() (thread:115) ==10108== by 0x4917117: ??? (in /usr/lib/arm-linux-gnueabihf/libstdc++.so.6.0.20)
It appears as if the first message on the serial port is received and passed validation in order to get to the SendToParent call. At this call, it appears that I lose the stack. I tried running cppcheck to see if I have any memory leaks or buffer overflows and found nothing.
void MyClass::ThreadMain(void)
{
ssize_t bytesRead = 0;
UINT8 buffer[256];
UINT8 message[256];
BOOL partialMessage = FALSE;
UINT8 messageIndex = 0;
UINT8 payloadLength = 0;
// read data from the UART
while(1)
{
// the UART is setup to pend until data is available
bytesRead = read(m_radioFileDescriptor, buffer, sizeof(buffer));
if (FAIL == bytesRead)
{
LOG_SYSTEM_INFO("UART Read interrupted by a system call");
}
else if (bytesRead > 0)
{
// build the message
for(ssize_t i = 0 ; i < bytesRead ; i++)
{
if (FALSE == partialMessage)
{
// have we found the start of the message?
if(START_BYTE == buffer[i])
{
// start of new message
messageIndex = 0;
message[messageIndex] = buffer[i];
partialMessage = TRUE;
messageIndex++;
}
}
else
{
// keep building the message until the expected length is reached
if(LENGTH_POSITION == messageIndex)
{
// capture the expected message length
message[messageIndex] = buffer[i];
messageIndex++;
payloadLength = buffer[i];
}
else
{
message[messageIndex] = buffer[i];
messageIndex++;
// check for expected length and end byte
if((messageIndex == payloadLength) && (END_BYTE == buffer[i]))
{
// this should be a valid message but need to confirm by checking for a valid checksum
UINT8 messageChecksum = message[messageIndex - CHKSUM_POS_FROM_END];
UINT8 calculatedChecksum = RadioProtocol::Instance().GenerateRadioChecksum(message, (payloadLength - CHKSUM_POS_FROM_END));
if (messageChecksum == calculatedChecksum)
{
SendToParent(message, payloadLength);
}
else
{
LOG_SYSTEM_ERROR("Checksum FAILURE");
}
// reset for the next message
partialMessage = FALSE;
messageIndex = 0;
}
else if((messageIndex == payloadLength) && (END_BYTE != buffer[i]))
{
// malformed message - throw out and look for start of next message
LOG_SYSTEM_ERROR("Bytes read exceeded expected message length");
partialMessage = FALSE;
messageIndex = 0;
}
}
}
} // end for loop of bytes read on the port
}
else
{
LOG_SYSTEM_INFO("Read returned 0 bytes which is unexpected");
}
}
}
void MyClass::SendToParent(UINT8* pMsg, UINT8 size)
{
if ((pMsg != NULL) && (m_parentQueueHandle > 0))
{
// message is valid - pass up for processing
MsgQueueMessage msgToSend;
msgToSend.m_msgHeader = UART_MESSASGE;
bzero(msgToSend.m_msgData, sizeof(msgToSend.m_msgData));
for (UINT8 i = 0; i < size; i++)
{
msgToSend.m_msgData[i] = pMsg[i];
}
if (FAIL == msgsnd(m_parentQueueHandle, &msgToSend, sizeof(msgToSend), IPC_NOWAIT))
{
LOG_SYSTEM_ERROR("FAILED to send message on queue");
}
}
}
This acts like I am performing a buffer overflow but I just can't see it. When I set a breakpoint at the line UINT8 messageChecksum = message[messageIndex - CHKSUM_POS_FROM_END]; all data in the watch window appear valid. If I step over to the next line then the data, m_parentQueueHandle as an example, gets blown away.
This is my first time working with c++11 threads and particularly with c++. Any help or insights would be appreciated.
Aucun commentaire:
Enregistrer un commentaire