c++httpboostboost-asioboost-beast

(process 7352) terminated with the code -1073741819


I am trying to make a REASON API server that will accept requests from another application, but the problem is that after the first connection to it, it shuts down with the error -1073741819. When I went through it with the debugger, I found out that the error is called buffer_ "An unhandled exception was caused: a violation of read access.this was 0xffffffffffffffffff.", but I do not know how to solve this problem

cpp.file
-------------------
#include "Server.h"

using namespace boost::asio;
namespace beast = boost::beast;
namespace http = beast::http;
using tcp = boost::asio::ip::tcp;

Server::Server(boost::asio::io_service& io_service, int port)
    : acceptor_(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
    socket_(io_service) {

    StartAccept();
}

void Server::StartAccept() {
    acceptor_.async_accept(socket_, [this](boost::system::error_code ec) {
        if (!ec) {
            std::cout << "Client connected" << std::endl;
            ReadRequest();
        }
        else {
            std::cerr << "Client error: " << ec.message() << std::endl;
        }
    });
}

void Server::ReadRequest() {
    buffer_.consume(buffer_.size());
    buffer_.prepare(1024); 
    beast::http::async_read(socket_, buffer_, request_,
        [this](boost::system::error_code ec, size_t bytes_transferred) {
            if (!ec) {
                ProcessRequest();
            }
            else {
                std::cerr << "Error ReadRequest: " << ec.message() << std::endl;
            }
        });
}

void Server::ProcessRequest(){
    if (request_.method() == http::verb::get) {
        http::response<http::string_body> response(http::status::ok, request_.version());
        response.set(http::field::server, "Boost Beast Server");
        response.set(http::field::content_type, "text/plain");
        response.keep_alive(request_.keep_alive());
        response.body() = "Hello, World";
        response.prepare_payload();
        
        WriteResponse(response);
    }
    else {
        http::response<http::string_body> response(http::status::bad_request, request_.version());
        response.set(http::field::server, "Boost Beast Server");
        response.set(http::field::content_type, "text/plain");
        response.keep_alive(request_.keep_alive());
        response.body() = "Invalide request!";
        response.prepare_payload();
        
        WriteResponse(response);
    }
}

void Server::WriteResponse(boost::beast::http::response<boost::beast::http::string_body>& response_){
    http::async_write(socket_, response_,
        [this](boost::system::error_code ec, size_t byte) {
            if (ec) {
                std::cerr << "Error WriteResponse: " << ec.message() << std::endl;
            }
            StartAccept();
        });
}
h.file
---------------
#include <iostream>
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <string>

class Server {
public:
    Server(boost::asio::io_service& io_service, int port);

private:
    void StartAccept(); 
    void ReadRequest(); 
    void ProcessRequest(); 
    void WriteResponse(boost::beast::http::response <boost::beast::http::string_body>& response_); 

    boost::asio::ip::tcp::acceptor acceptor_; 
    boost::asio::ip::tcp::socket socket_; 
    boost::beast::flat_buffer buffer_; 
    boost::beast::http::request<boost::beast::http::string_body> request_; 
};


Solution

  • The error originates in serializing the response.

    You can tell by the assert happening in debug mode:

    Client connected sotest:
    intrusive/detail/hook_traits.hpp:63: static boost::intrusive::bhtraits_b ase<T, NodePtr, Tag, Type>::pointer boost::intrusive::bhtraits_base<T, NodePtr, Tag, Type>::to_value_ptr(node_ptr) [with T = boost::beast::http::basic_fields<std::allocator<char> >::element; NodePtr = boost::intrusive::list_node<v oid*>*; Tag = boost::intrusive::dft_tag; unsigned int Type = 1; pointer = boost::beast::http::basic_fields<std::all ocator<char> >::element*; node_ptr = boost::intrusive::list_node<void*>*]: Assertion '!!p' failed.

    gdb tells us the place:

    #0  __pthread_kill_implementation (no_tid=0, signo=6, threadid=140737345820608) at ./nptl/pthread_kill.c:44
    #1  __pthread_kill_internal (signo=6, threadid=140737345820608) at ./nptl/pthread_kill.c:78
    #2  __GI___pthread_kill (threadid=140737345820608, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
    #3  0x00007ffff793f476 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
    #4  0x00007ffff79257f3 in __GI_abort () at ./stdlib/abort.c:79
    #5  0x00007ffff792571b in __assert_fail_base (fmt=0x7ffff7ada130 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0x555555598094 "!!p", file=0x55555559cd90 "/home/sehe/cu...
    #6  0x00007ffff7936e96 in __GI___assert_fail (assertion=0x555555598094 "!!p", file=0x55555559cd90 "/home/sehe/custom/superboost/boost/intrusive/detail/hook_traits.hpp", line=63...
    #7  0x0000555555563c11 in boost::intrusive::bhtraits_base<boost::beast::http::basic_fields<std::allocator<char> >::element, boost::intrusive::list_node<void*>*, boost::intrusiv...
    #8  boost::intrusive::list_iterator<boost::intrusive::bhtraits<boost::beast::http::basic_fields<std::allocator<char> >::element, boost::intrusive::list_node_traits<void*>, (boo...
    #9  boost::intrusive::list_iterator<boost::intrusive::bhtraits<boost::beast::http::basic_fields<std::allocator<char> >::element, boost::intrusive::list_node_traits<void*>, (boo...
    #10 boost::beast::http::basic_fields<std::allocator<char> >::writer::field_iterator::operator* (this=0x7fffffffd5c0) at /home/sehe/custom/superboost/boost/beast/http/impl/field...
    #11 boost::beast::buffers_cat_view<boost::asio::const_buffer, boost::asio::const_buffer, boost::asio::const_buffer, boost::beast::http::basic_fields<std::allocator<char> >::wri...
    #12 0x0000555555590cba in boost::beast::buffers_cat_view<boost::asio::const_buffer, boost::asio::const_buffer, boost::asio::const_buffer, boost::beast::http::basic_fields<std::...
    #13 boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::const_buffer, boost::asio::const_buffer, boost::asio::const_buf...
    #14 boost::mp11::detail::mp_with_index_impl_<4ul>::call<0ul, boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::const_...
    #15 boost::mp11::mp_with_index<4ul, boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::const_buffer, boost::asio::cons...
    #16 boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::const_buffer, boost::asio::const_buffer, boost::asio::const_buf...
    #17 boost::beast::buffers_suffix<boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::const_buffer, boost::asio::const_b...
    #18 boost::asio::detail::buffer_size<boost::beast::buffers_suffix<boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::c...
    #19 boost::asio::buffer_size<boost::beast::buffers_suffix<boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::const_buf...
    #20 0x0000555555593cc3 in boost::beast::detail::buffer_bytes_impl::operator()<boost::beast::buffers_suffix<boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boos...
    #21 boost::beast::http::serializer<false, boost::beast::http::basic_string_body<char, std::char_traits<char>, std::allocator<char> >, boost::beast::http::basic_fields<std::allo...
    #22 0x000055555556eec7 in boost::beast::http::detail::write_some_op<boost::beast::http::detail::write_op<boost::beast::http::detail::write_msg_op<Server::WriteResponse(boost::b...
    #23 0x000055555556f476 in boost::asio::detail::binder2<boost::beast::http::detail::write_some_op<boost::beast::http::detail::write_op<boost::beast::http::detail::write_msg_op<S...
    #24 boost::asio::detail::binder0<boost::asio::detail::binder2<boost::beast::http::detail::write_some_op<boost::beast::http::detail::write_op<boost::beast::http::detail::write_m...
    #25 boost::asio::detail::executor_function::complete<boost::asio::detail::binder0<boost::asio::detail::binder2<boost::beast::http::detail::write_some_op<boost::beast::http::det...
    #26 0x0000555555585b50 in boost::asio::detail::executor_function::operator() (this=<synthetic pointer>) at /home/sehe/custom/superboost/boost/asio/detail/executor_function.hpp:...
    #27 boost::asio::io_context::basic_executor_type<std::allocator<void>, 4ul>::execute<boost::asio::detail::executor_function> (this=0x7fffffffdd70, f=...) at /home/sehe/custom/s...
    #28 0x000055555556497a in boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::binder0<boost::asio::detail::binder2<boost::beast::http::detail::write...
    #29 boost::asio::detail::work_dispatcher<boost::asio::detail::binder2<boost::beast::http::detail::write_some_op<boost::beast::http::detail::write_op<boost::beast::http::detail:...
    #30 0x0000555555566511 in boost::asio::detail::executor_function::complete<boost::asio::detail::work_dispatcher<boost::asio::detail::binder2<boost::beast::http::detail::write_s...
    #31 0x0000555555585a60 in boost::asio::detail::executor_function::operator() (this=<synthetic pointer>) at /home/sehe/custom/superboost/boost/asio/detail/executor_function.hpp:...
    #32 boost::asio::detail::executor_op<boost::asio::detail::executor_function, std::allocator<void>, boost::asio::detail::scheduler_operation>::do_complete (owner=0x555555de6000,...
    #33 0x00005555555678d7 in boost::asio::detail::scheduler_operation::complete (bytes_transferred=0, ec=..., owner=0x555555de6000, this=0x555555df4000) at /home/sehe/custom/super...
    #34 boost::asio::detail::scheduler::do_run_one (ec=..., this_thread=..., lock=..., this=0x555555de6000) at /home/sehe/custom/superboost/boost/asio/detail/impl/scheduler.ipp:493...
    #35 boost::asio::detail::scheduler::run (this=0x555555de6000, ec=...) at /home/sehe/custom/superboost/boost/asio/detail/impl/scheduler.ipp:210
    #36 0x000055555555fe55 in boost::asio::io_context::run (this=0x7fffffffdf60) at /home/sehe/custom/superboost/boost/asio/impl/io_context.ipp:64
    #37 main () at /home/sehe/Projects/stackoverflow/test.cpp:93
    

    The reason is that the response is passed by reference to an async operation. Fix it e.g. by making it a member or using the type-erasing message_generator utility

    Showing the latter:

    Live On Coliru

    #include <boost/asio.hpp>
    #include <boost/beast.hpp>
    #include <iostream>
    #include <string>
    
    class Server {
      public:
        Server(boost::asio::io_service& io_service, int port);
    
      private:
        using Request  = boost::beast::http::request<boost::beast::http::string_body>;
        using Response = boost::beast::http::message_generator;
        void     StartAccept();
        void     ReadRequest();
        Response ProcessRequest();
        void     WriteResponse(Response);
    
        boost::asio::ip::tcp::acceptor acceptor_;
        boost::asio::ip::tcp::socket   socket_;
        boost::beast::flat_buffer      buffer_;
        Request                        request_;
    };
    
    // #include "Server.h"
    
    namespace beast = boost::beast;
    namespace http  = beast::http;
    using tcp       = boost::asio::ip::tcp;
    
    Server::Server(boost::asio::io_service& io_service, int port)
        : acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
        , socket_(io_service) {
        StartAccept();
    }
    
    void Server::StartAccept() {
        acceptor_.async_accept(socket_, [this](boost::system::error_code ec) {
            if (!ec) {
                std::cout << "Client connected" << std::endl;
                ReadRequest();
            } else {
                std::cerr << "Client error: " << ec.message() << std::endl;
            }
        });
    }
    
    void Server::ReadRequest() {
        buffer_.consume(buffer_.size());
        buffer_.prepare(1024);
        beast::http::async_read( //
            socket_, buffer_, request_, [this](boost::system::error_code ec, size_t /*bytes_transferred*/) {
                if (!ec) {
                    WriteResponse(ProcessRequest());
                } else {
                    std::cerr << "Error ReadRequest: " << ec.message() << std::endl;
                }
            });
    }
    
    Server::Response Server::ProcessRequest() {
        if (request_.method() == http::verb::get) {
            http::response<http::string_body> response(http::status::ok, request_.version());
            response.set(http::field::server, "Boost Beast Server");
            response.set(http::field::content_type, "text/plain");
            response.keep_alive(request_.keep_alive());
            response.body() = "Hello, World";
            response.prepare_payload();
    
            return response;
        } else {
            http::response<http::string_body> response(http::status::bad_request, request_.version());
            response.set(http::field::server, "Boost Beast Server");
            response.set(http::field::content_type, "text/plain");
            response.keep_alive(request_.keep_alive());
            response.body() = "Invalid request!";
            response.prepare_payload();
    
            return response;
        }
    }
    
    void Server::WriteResponse(Response res) {
        beast::async_write(socket_, std::move(res), [this](boost::system::error_code ec, size_t /*byte*/) {
            if (ec) {
                std::cerr << "Error WriteResponse: " << ec.message() << std::endl;
            }
            StartAccept();
        });
    }
    
    int main() {
        boost::asio::io_service ios;
        Server                  s(ios, 8989);
    
        ios.run();
    }
    

    The output of test:

    g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp 
    ./a.out&
    sleep 1; curl "http://127.0.0.1:8989/test"
    

    being

    Hello, World
    

    I suggest looking at the Beast async http server examples for more good practices!

    UPDATE/BONUS

    Also showing concurrent connections separating Server from Session and in the process reducing the includes in the header file:

    Live On Coliru