c++ - Valgrind 在说 new 的行中看到 delete

标签 c++ valgrind poco-libraries

当我检查我的应用程序是否存在内存泄漏时,我遇到了 valgrind 的一个非常特殊的行为。据我了解,他看到了以下代码

virtual ServiceHandler* createServiceHandler(StreamSocket& socket)
    /// Create and initialize a new ServiceHandler instance.
    ///
    /// Subclasses can override this method.
{
    return new ServiceHandler(socket, *_pReactor);
}

作为我分配和释放内存的地方。此代码是 POCO 库的一部分,可以找到 here .下面是来自 valgrind 的日志示例,说明提供的 return 语句同时产生了 new 和 delete。

Invalid read of size 8
==9764==    at 0x1C63DC: Poco::Net::Socket::operator!=(Poco::Net::Socket const&) const (Socket.h:340)
==9764==    by 0x1C2A5C: SocketHandler::onReadableNotification(Poco::AutoPtr<Poco::Net::ReadableNotification> const&) (SocketHandler.cpp:67)
==9764==    by 0x1CA0DF: Poco::NObserver<SocketHandler, Poco::Net::ReadableNotification>::notify(Poco::Notification*) const (NObserver.h:88)
==9764==    by 0x5C04077: Poco::NotificationCenter::postNotification(Poco::AutoPtr<Poco::Notification>) (NotificationCenter.cpp:78)
==9764==    by 0x579F422: Poco::Net::SocketNotifier::dispatch(Poco::Net::SocketNotification*) (SocketNotifier.cpp:80)
==9764==    by 0x579C0DC: Poco::Net::SocketReactor::dispatch(Poco::AutoPtr<Poco::Net::SocketNotifier>&, Poco::Net::SocketNotification*) (SocketReactor.cpp:282)
==9764==    by 0x579BEE1: Poco::Net::SocketReactor::dispatch(Poco::Net::Socket const&, Poco::Net::SocketNotification*) (SocketReactor.cpp:258)
==9764==    by 0x579B5F4: Poco::Net::SocketReactor::run() (SocketReactor.cpp:114)
==9764==    by 0x5C50406: Poco::(anonymous namespace)::RunnableHolder::run() (Thread.cpp:57)
==9764==    by 0x5C500E0: Poco::ThreadImpl::runnableEntry(void*) (Thread_POSIX.cpp:349)
==9764==    by 0x6D20493: start_thread (pthread_create.c:333)
==9764==    by 0x78BBAFE: clone (clone.S:97)
==9764==  Address 0x10c8f908 is 40 bytes inside a block of size 352 free'd
==9764==    at 0x4C2D2DB: operator delete(void*) (vg_replace_malloc.c:576)
==9764==    --> by 0x19D1CD: Poco::Net::SocketAcceptor<SocketHandler>::createServiceHandler(Poco::Net::StreamSocket&) (SocketAcceptor.h:166) 
==9764==    by 0x19B3E3: Poco::Net::SocketAcceptor<SocketHandler>::onAccept(Poco::Net::ReadableNotification*) (SocketAcceptor.h:157)
==9764==    by 0x1A1385: Poco::Observer<Poco::Net::SocketAcceptor<SocketHandler>, Poco::Net::ReadableNotification>::notify(Poco::Notification*) const (Observer.h:86)
==9764==    by 0x5C04077: Poco::NotificationCenter::postNotification(Poco::AutoPtr<Poco::Notification>) (NotificationCenter.cpp:78)
==9764==    by 0x579F422: Poco::Net::SocketNotifier::dispatch(Poco::Net::SocketNotification*) (SocketNotifier.cpp:80)
==9764==    by 0x579C0DC: Poco::Net::SocketReactor::dispatch(Poco::AutoPtr<Poco::Net::SocketNotifier>&, Poco::Net::SocketNotification*) (SocketReactor.cpp:282)
==9764==    by 0x579BEE1: Poco::Net::SocketReactor::dispatch(Poco::Net::Socket const&, Poco::Net::SocketNotification*) (SocketReactor.cpp:258)
==9764==    by 0x579B5F4: Poco::Net::SocketReactor::run() (SocketReactor.cpp:114)
==9764==    by 0x5C50406: Poco::(anonymous namespace)::RunnableHolder::run() (Thread.cpp:57)
==9764==    by 0x5C500E0: Poco::ThreadImpl::runnableEntry(void*) (Thread_POSIX.cpp:349)
==9764==    by 0x6D20493: start_thread (pthread_create.c:333)
==9764==  Block was alloc'd at
==9764==    at 0x4C2C21F: operator new(unsigned long) (vg_replace_malloc.c:334)
==9764==    --> by 0x19D19E: Poco::Net::SocketAcceptor<SocketHandler>::createServiceHandler(Poco::Net::StreamSocket&) (SocketAcceptor.h:166)
==9764==    by 0x19B3E3: Poco::Net::SocketAcceptor<SocketHandler>::onAccept(Poco::Net::ReadableNotification*) (SocketAcceptor.h:157)
==9764==    by 0x1A1385: Poco::Observer<Poco::Net::SocketAcceptor<SocketHandler>, Poco::Net::ReadableNotification>::notify(Poco::Notification*) const (Observer.h:86)
==9764==    by 0x5C04077: Poco::NotificationCenter::postNotification(Poco::AutoPtr<Poco::Notification>) (NotificationCenter.cpp:78)
==9764==    by 0x579F422: Poco::Net::SocketNotifier::dispatch(Poco::Net::SocketNotification*) (SocketNotifier.cpp:80)
==9764==    by 0x579C0DC: Poco::Net::SocketReactor::dispatch(Poco::AutoPtr<Poco::Net::SocketNotifier>&, Poco::Net::SocketNotification*) (SocketReactor.cpp:282)
==9764==    by 0x579BEE1: Poco::Net::SocketReactor::dispatch(Poco::Net::Socket const&, Poco::Net::SocketNotification*) (SocketReactor.cpp:258)
==9764==    by 0x579B5F4: Poco::Net::SocketReactor::run() (SocketReactor.cpp:114)
==9764==    by 0x5C50406: Poco::(anonymous namespace)::RunnableHolder::run() (Thread.cpp:57)
==9764==    by 0x5C500E0: Poco::ThreadImpl::runnableEntry(void*) (Thread_POSIX.cpp:349)
==9764==    by 0x6D20493: start_thread (pthread_create.c:333)

我在有趣的部分添加了-->

一旦发生这种情况,我会观察到更多类似的日志,因为对象似乎没有被分配。在我看到此错误之前,该应用程序正常运行了一段时间,这是第一个发生的错误。我认为当套接字表现不佳时可能会发生此错误。

我使用以下命令验证应用程序

valgrind --vgdb=yes --vgdb-error=0 app

并使用 gdb 进一步检查代码。

我的问题是:

  • 为什么 valgrind 告诉我所提供的代码同时调用了 new 和 delete?
  • 此行为是由此代码在本地引起的,还是我应该在其他地方寻找问题?

@编辑

负责人

SocketHandler::SocketHandler(StreamSocket &socket, SocketReactor &reactor) :
    _socket(socket) /* copy */, _reactor(reactor) /* reference */ {

    _socket.setBlocking(false);

    _reactor.addEventHandler(_socket, NObserver<SocketHandler, ReadableNotification>(*this,
                                                                                 &SocketHandler::onReadableNotification));
    _reactor.addEventHandler(_socket,
                         NObserver<SocketHandler, ErrorNotification>(*this, &SocketHandler::onErrorNotification));
    _reactor.addEventHandler(_socket, NObserver<SocketHandler, ShutdownNotification>(*this,
                                                                                 &SocketHandler::onShutdownNotification));

    _addr = _socket.peerAddress().toString();
}

最佳答案

Valgrind 消息并不表示您在同一行代码中有一个新的和一个删除。

valgrind 错误消息包含 3 个堆栈跟踪。

第一个堆栈跟踪是检测到错误的地方。此错误在于读取一 block 已释放的内存。

然后 Valgrind 会尝试为您提供有关这 block 内存的更多信息。 为此,它向您显示了 2 个额外的堆栈跟踪:

第二个堆栈跟踪指示释放这 block 内存的位置。 第三个堆栈跟踪指示这 block 内存的分配位置。

换句话说就是:你的代码首先分配了一 block 内存(在 堆栈跟踪 nr 3)。然后您的代码释放了这 block 内存(在堆栈跟踪 nr 2 处)。 然后您的代码错误地访问了这 block 内存(在堆栈跟踪 nr 1)。

所以,这一切看起来就像你有一个真正的错误:你正在使用一个悬空指针,指向已释放的内存。

您可能需要查看生成的代码以准确了解为 createServiceHandler 调用生成了哪些对 new/delete 的调用。 显然,在“新建”和“删除”堆栈跟踪中有 2 条不同的指令(0x19D1CD 和 0x19D19E)。

关于c++ - Valgrind 在说 new 的行中看到 delete,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47034938/

相关文章:

c++ - 使用 POCO C++ 的非阻塞 WebSocket 服务器

c++ - 清除任意二维数组

C++:问题 vector STL

c++ - 为另一种模板类型声明模板特化的正确方法是什么?

c - Invalid write/read valgrind错误,其他问题未找到解决方案

c++ - valgrind 未处理的指令字节 : 0xF 0xB 0xFF 0x85

c++ - 指针和整数模板的内存泄漏。我究竟做错了什么?

C++ 跨平台进程 : is POCO lib good? 其他选择?

c++ - 如何将 Poco::SharedPtr 传递给 TimerCallback 函数?

c++ - Qt C++初始化一个QStringList类成员