【问题标题】:free() causing stack overflowfree() 导致堆栈溢出
【发布时间】:2014-07-28 15:59:49
【问题描述】:

我正在尝试使用 Visual Studio C++ 使用一些通信 DLLs 来开发应用程序。 在其中一个 DLL 中,我遇到了堆栈溢出异常。

我有两个函数,一个接收数据包,另一个函数对数据包做一些操作。

static EEcpError RxMessage(unsigned char SrcAddr, unsigned char SrcPort, unsigned char DestAddr, unsigned char DestPort, unsigned char* pMessage, unsigned long MessageLength)
{
    EEcpError Error = ERROR_MAX;
    TEcpChannel* Ch = NULL;
    TDevlinkMessage* RxMsg = NULL;

    // Check the packet is sent to an existing port
    if (DestPort < UC_ECP_CHANNEL_NB)
    {
        Ch = &tEcpChannel[DestPort];
        RxMsg = &Ch->tRxMsgFifo.tDevlinkMessage[Ch->tRxMsgFifo.ucWrIdx];

        // Check the packet is not empty
        if ((0UL != MessageLength)
            && (NULL != pMessage))
        {
            if (NULL == RxMsg->pucDataBuffer)
            {
                // Copy the packet
                RxMsg->SrcAddr = SrcAddr;
                RxMsg->SrcPort = SrcPort;
                RxMsg->DestAddr =DestAddr;
                RxMsg->DestPort = DestPort;
                RxMsg->ulDataBufferSize = MessageLength;
                RxMsg->pucDataBuffer = (unsigned char*)malloc(RxMsg->ulDataBufferSize);
                if (NULL != RxMsg->pucDataBuffer)
                {
                    memcpy(RxMsg->pucDataBuffer, pMessage, RxMsg->ulDataBufferSize);

                    // Prepare for next message
                    if ((UC_ECP_FIFO_DEPTH - 1) <= Ch->tRxMsgFifo.ucWrIdx)
                    {
                        Ch->tRxMsgFifo.ucWrIdx = 0U;
                    }
                    else
                    {
                        Ch->tRxMsgFifo.ucWrIdx += 1U;
                    }

                    // Synchronize the application
                    if (0 != OS_MbxPost(Ch->hEcpMbx))
                    {
                        Error = ERROR_NONE;
                    }
                    else
                    {
                        Error = ERROR_WINDOWS;
                    }
                }
                else
                {
                    Error = ERROR_WINDOWS;
                }
            }
            else
            {
                // That should never happen. In case it happens, that means the FIFO
                // is full. Either the FIFO size should be increased, or the listening thread 
                // does no more process the messages.
                // In that case, the last received message is lost (until the messages are processed, or forever...)
                Error = ERROR_FIFO_FULL;
            }
        }
        else
        {
            Error = ERROR_INVALID_PARAMETER;
        }
    }
    else
    {
        // Trash the packet, nothing else to do
        Error = ERROR_NONE;
    }

    return Error;
}

static EEcpError ProcessNextRxMsg(unsigned char Port, unsigned char* SrcAddr, unsigned char* SrcPort, unsigned char* DestAddr, unsigned char* Packet, unsigned long* PacketSize)
{
    EEcpError Error = ERROR_MAX;
    TEcpChannel* Ch = &tEcpChannel[Port];
    TDevlinkMessage* RxMsg = &Ch->tRxMsgFifo.tDevlinkMessage[Ch->tRxMsgFifo.ucRdIdx];

    if (NULL != RxMsg->pucDataBuffer)
    {
        *SrcAddr = RxMsg->ucSrcAddr;
        *SrcPort = RxMsg->ucSrcPort;
        *DestAddr = RxMsg->ucDestAddr;
        *PacketSize = RxMsg->ulDataBufferSize;
        memcpy(Packet, RxMsg->pucDataBuffer, RxMsg->ulDataBufferSize);

        // Cleanup the processed message
        free(RxMsg->pucDataBuffer);   // <= Exception stack overflow after 40 min
        RxMsg->pucDataBuffer = NULL;
        RxMsg->ulDataBufferSize = 0UL;
        RxMsg->ucSrcAddr = 0U;
        RxMsg->ucSrcPort = 0U;
        RxMsg->ucDestAddr = 0U;
        RxMsg->ucDestPort = 0U;

        // Prepare for next message
        if ((UC_ECP_FIFO_DEPTH - 1) <= Ch->tRxMsgFifo.ucRdIdx)
        {
            Ch->tRxMsgFifo.ucRdIdx = 0U;
        }
        else
        {
            Ch->tRxMsgFifo.ucRdIdx += 1U;
        }

        Error =ERROR_NONE;
    }
    else
    {
        Error = ERROR_NULL_POINTER;
    }

    return Error;
}

问题在 40 分钟后出现,在此期间我收到了很多数据包,一切都很顺利。 40 分钟后,free 发生堆栈溢出异常。 我不知道出了什么问题。

谁能帮帮我?

谢谢。

【问题讨论】:

  • 该问题很可能与free 的特定调用无关 - 它发生在此之前的一段时间。例如,如果您覆盖正在释放的块的“簿记”信息,则可能会发生问题。使用 valgrind 运行以查看实际的内存错误。
  • 关于 stackoverflow 的问题应该在这里还是在 meta 上?
  • @user93353 哈哈哈不错(希望)
  • 试试enabling CodeGuard看看有没有发现。

标签: c++ stack-overflow


【解决方案1】:

一些建议:

  1. 线

     memcpy(Packet, RxMsg->pucDataBuffer, RxMsg->ulDataBufferSize);
    

    有点可疑,因为它发生在 free() 调用崩溃之前。 Packet 是如何分配的,你如何确保这里不会发生缓冲区溢出?

  2. 如果这是一个异步/多线程程序,您是否有必要的锁来防止同时写入/读取数据?
  3. 如果您仍然需要查找问题,最好的办法是运行 Valgrind 之类的工具来帮助更准确地诊断和缩小内存问题。正如 dasblinklight 在 cmets 中提到的那样,问题很可能源自其他地方,只是碰巧出现在 free() 电话中。

【讨论】:

  • 感谢您的回答。关于您的评论 uesp,ProcessNextRxMsg 函数在线程中的另一个 DLL 中被调用。以下是 Packet 的分配方式: unsigned char Packet[ US_ECP_MESSAGE_LENGTH_MAX ];然后,在线程中的 While 循环中: memset( Packet, 0, US_ECP_MESSAGE_LENGTH_MAX );// 准备下一个数据包。我注意到一些奇怪的事情:在调用方 DLL 中创建 Packet 的大小是 20240,但是当我检查第二个 DLL(问题所在)中 Packet 的大小时,值是 4。有人知道为什么会这样吗?
  • 我假设您检查了RxMsg-&gt;ulDataBufferSize 永远不会超过US_ECP_MESSAGE_LENGTH_MAX 的地方?不可能说是什么改变了数据包的大小,但缓冲区溢出可能会导致它。仔细检查所有缓冲区是否都分配了正确的大小,并且对它们的写入不会溢出。
  • 我没有检查RxMsg-&gt;ulDataBufferSize 永远不会超过US_ECP_MESSAGE_LENGTH_MAX。当memcpy被调用时,RxMsg-&gt;ulDataBufferSize的值是8,Packet size是4。奇怪的是Packet的大小发生了变化。调用者DLL是在C++ Builder中开发的,有问题的DLL是在Visual Studio中开发的。我所做的只是在 C++ builder 开发的 DLL 中调用包大小为 20240 的函数,但是当我在 Visual Studio 中检查被调用函数的大小时,包大小为4. 正如你所说,这可能会导致缓冲区溢出
猜你喜欢
  • 2015-05-21
  • 2014-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-11
  • 2015-12-21
  • 2018-11-27
  • 2017-06-04
相关资源
最近更新 更多