我有一个简单的函数,它使用Qt(5.5.1)QSharedMemory类将字符串(uri链接或文件路径)发送到已经运行的应用程序实例。
它似乎在大多数时候都能正常工作,但我从用户那里抓到了一个崩溃日志,它在memcpy上崩溃了。该函数如下所示:
void WindowsApp::SendData( char* uri )
{
int size = 1024;
if (!m_SharedMemory.create(size)) {
qDebug() << "Unable to create shared memory segment." << m_SharedMemory.error();
return;
}
m_SharedMemory.lock();
char *to = (char*)m_SharedMemory.data();
const char *from = uri;
memcpy(to, from, qMin(m_SharedMemory.size(), size));
m_SharedMemory.unlock();
QThread::sleep(10);
}
m_SharedMemory是该类的QSharedMemory类型静态成员。
从日志中,我看到我尝试发送的字符串是一个没有特殊字符的简单文件路径,并且不会太长,只有150个字符。
有什么不对,但是我无法用类似的参数重现它?
答案 0 :(得分:1)
代码具有未定义的行为,因为您正在读取源字符串的末尾:即使源字符串是例如,您也总是读取1024个字节。 5个字节长。正如您所指出的,UB并不是崩溃的保证。通常它会在重要演示期间崩溃。如果字符串太长而无法放入内存段,您也无法确保字符串将被终止,因此如果接收器尝试将字符串视为零终止,则接收器可能会崩溃
这些问题可能是由于缺乏设计。内存段的内容意味着发送方和接收方之间的合同。两者都必须达成一致意见。让我们来定义合同:
共享内存段的内容是以空字符结尾的C字符串。
这是一种所谓的不变性:无论如何,它总是如此。这使读者能够安全地使用C字符串API,而无需先检查是否存在空终止。
太长的uri被空字符串替换。
这是作者的后置条件:它意味着写作将在内存中放置一个完整的URI,或者是一个空字符串。
以下是解决问题的方法:
=countif($b:$e, b2)=1