c++pocopoco-libraries

Memory leak in Poco::Net::POP3ClientSession when server is unreachable


I’ve written a class designed to poll an email server. Everything works fine when the server is reachable. However, the problem arises when the server is unreachable. In that case, Valgrind reports the following memory leak to the POP3ClientSession instance:

==32313== by 0x18F541: std::__cxx11::basic_string<char, std::char_traits, std::allocator >::_M_is_local() const (basic_string.h:230)

Here’s the relevant code:

#include <Poco/Net/POP3ClientSession.h>
#include <Poco/Exception.h>
#include <Poco/Net/NetException.h>
#include <Poco/Timespan.h>
#include <memory>
#include <iostream>
#include <string>

struct EmailStoreConfiguration {
    std::string mailServerName;
    Poco::UInt16 mailServerPort;
    std::string emailAccount;
    std::string emailPassword;
};

class EmailStoreProcessor {
public:
    EmailStoreProcessor(EmailStoreConfiguration config)
        : m_emailStoreConfiguration(std::move(config)), m_sessionPtr(nullptr) {}

    bool initialize() {
        try {
            Poco::Net::POP3ClientSession pop3ClientSession(
                m_emailStoreConfiguration.mailServerName,
                m_emailStoreConfiguration.mailServerPort
            );
            pop3ClientSession.setTimeout(Poco::Timespan(30, 0));

            if (m_emailStoreConfiguration.emailAccount.empty() || m_emailStoreConfiguration.emailPassword.empty()) {
                return false;
            }

            pop3ClientSession.login(
                m_emailStoreConfiguration.emailAccount,
                m_emailStoreConfiguration.emailPassword
            );

            m_sessionPtr = std::make_unique<Poco::Net::POP3ClientSession>(std::move(pop3ClientSession));

        } catch (const Poco::Exception& e) {
            std::cerr << "Poco Exception: " << e.displayText() << "\n";
            return false;
        } catch (const std::exception& e) {
            std::cerr << "Std Exception: " << e.what() << "\n";
            return false;
        } catch (...) {
            std::cerr << "Unknown Exception\n";
            return false;
        }

        std::cout << "Successfully initialized connection to " << m_emailStoreConfiguration.mailServerName << "\n";
        return true;
    }

private:
    EmailStoreConfiguration m_emailStoreConfiguration;
    std::unique_ptr<Poco::Net::POP3ClientSession> m_sessionPtr;
};

int main() {

    EmailStoreConfiguration config{
        "pop.yourserver.com",  // Server name
        110,                   // POP3 port (non-SSL)
        "your_email",          // Username
        "your_password"        // Password
    };

    auto processor = std::make_unique<EmailStoreProcessor>(std::move(config));
    if (processor->initialize()) {
        std::cout << "Processor initialized successfully.\n";
    } else {
        std::cerr << "Processor initialization failed.\n";
    }

    return 0;
}

The issue seems to originate from the line where the POP3ClientSession is created:

Poco::Net::POP3ClientSession pop3ClientSessionInstance(
  m_emailStoreConfiguration.mailServerName, 
  m_emailStoreConfiguration.mailServerPort
);

And Valgrind gives this additional trace:

==32313== Invalid read of size 8
==32313== at 0x5001C2C: _Ux86_64_setcontext (in /usr/lib/libunwind.so.8.0.1)
==32313== by 0xCD48904876A4005B: ???
==32313== by 0xC: ???
==32313== by 0x1FFEFFFC8F: ???
==32313== by 0x1FFEFFFC2F: ???
==32313== by 0x13BFDC: EmailStoreProcessor::initialize( (email_store_processor.hpp:17)
==32313== by 0x1B: ??? 
==32313== by 0xCD48904876A4005B: ???
==32313== Address 0x1ffeffef60 is on thread 1's stack
==32313== 2120 bytes below stack pointer

These appear to be serious errors, although my flow and logic otherwise work correctly.

Using GCC: 11.2.1 POCO: 1.12.4-r0 (specific build for Alpine) SO: Alpine 3.16


Solution

  • After a lot of digging, I figured out that the Valgrind memory leak I was seeing wasn't actually caused by POCO or my code, but happened because I was linking libunwind manually in my CMake file. Once I removed that line, the leak completely disappeared and Valgrind reported no issues anymore. I guess libunwind altered the output of Valgrind, and it ended up interpreting some stack activity as memory leaks or invalid reads, even though they weren't real issues.