mercredi 26 août 2015

Acceptor refusing to open socket only for -O0 build

Hi dear stackoverflow community,

I have a problem only in certain compilation settings (which indicates some kind of UB, but I decided to tag this question as boost-asio since it might involve knowledge about asio specifics). Note that I use the current git version of the standalone asio library.

First let me drop some snippets - the complete code is here: http://ift.tt/1K14ssb (note that the CMakeLists.txt is very hacky and might need fixing in case you would want to compile it).

I have a test echo server (tcp, async) in examples/echo_server.cpp:

[snip...]
int main (int argc, char const* argv[]) {
    try {
        if (argc != 2) {
            std::cerr << "Usage: echo_server <port>\n";
            return 1;
        }

        asio::io_context io_context;
        magellan::server server;
        server.accept<echo_session>(io_context, 9003);
        io_context.run();
    } catch (std::exception& e) {
        std::cerr << e.what() << "\n";
    }
}

Obviously the interesting parts are the server and echo_session classes; however the latter seems to work correctly, so I am gonna drop the server class here. The include/server.hpp:

#ifndef MAGELLAN_SERVER_HPP_
#define MAGELLAN_SERVER_HPP_

#include "session.hpp"

namespace magellan {

class server {
    public:
        [snip typedefs...]

    public:
        server();

        virtual ~server();

        template <typename Session>
        void accept(asio::io_context& io_context, short port);

        [snip comments...]
};

} // magellan

#include "server.ipp"

#endif /* MAGELLAN_SERVER_HPP_ */

... and the include/server.ipp:

#include <iostream>
namespace magellan {

template <typename Session>
inline void
server::accept(asio::io_context& io_context, short port) {
    using asio::ip::tcp;
    asio::spawn(io_context, [&](asio::yield_context yield) {
        tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port));

        for (;;) {
            asio::error_code ec;
            tcp::socket socket(io_context);
            acceptor.async_accept(socket, yield[ec]);
            if (!ec) {
                auto session = std::make_shared<Session>(std::move(socket));
                session->start();
            }
        }
    });
}

[snip comments...]

} // magellan

Now the interesting thing is that the async_accept opens a tcp socket iff I compile with -O1, -O2 and -O3, but not with -O0. I checked this via:

> ss -a | grep 9003
296:tcp    LISTEN     0      128     *:9003                  *:*  

When compiled with -O0 the socket is never opened. I also checked that the service is still running via an io_context::work instance.

My best guess (admittedly lacking confidence) is that boost coroutine does something different with -O0. It may also be worth mentioning that if I use the commented out code in server.ipp it also won't open sockets (no matter what compilation settings):

template <typename Session>
inline void
server::accept(asio::io_context& io_context, short port) {
    using asio::ip::tcp;
    accept<Session>(io_context, port, [](tcp::socket s) {
        return std::make_shared<Session>(std::move(s));
    });
}

template <typename Session, typename Func>
void
server::accept(asio::io_context& io_context, short port, Func&& factory) {
    using asio::ip::tcp;
    asio::spawn(io_context, [&](asio::yield_context yield) {
        tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port));

        for (;;) {
            asio::error_code ec;
            tcp::socket socket(io_context);
            acceptor.async_accept(socket, yield[ec]);
            if (!ec) {
                auto session = factory(std::move(socket));
                session->start();
            } else {
                std::cout << "failed accept" << "\n";
            }
        }
    });
}

This was my initial problem and I attributed it to a copied instead of moved socket until I arrived at the -O0 flag problem.

I am pretty lost at this point as I have no idea how to debug these async processes in general but am still confident the actual answer to my question will be in some way embarassing ;)

Hope you have a hint for me.

Best, Richard

Aucun commentaire:

Enregistrer un commentaire