LINUX.ORG.RU

boost::asio::async_write вызывает Segmentation fault

 , ,


0

1

Приветствую.

Даже спрашивать уже опасаюсь, опять отдельные личности с большим самомнением начнут объяснять какой я тупой, но все таки попробую, вдруг кому не сложно )

Код класс ниже, теста ради из одного потока все работало, пока не решил вызвать CPush::Send из другого и все упало. Думал сначала что дело в std::stringstream request, которая была локальная - поднял ее до класса и не помогло.

Хоть намек бы к пониманию, где косяк, заранее спасибо за не равнодушие )

class CPush
{
private:
    std::stringstream request;

    boost::asio::io_service * pio_service;
    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> * psocket;

    boost::asio::streambuf response;

bool verify_certificate(bool preverified, boost::asio::ssl::verify_context & ctx);
void handle_connect(const boost::system::error_code & error);
void handle_handshake(const boost::system::error_code & error);
void handle_write(const boost::system::error_code & error);//, size_t bytes_transferred
void handle_read_status(const boost::system::error_code & error);
void handle_read_header(const boost::system::error_code & error);
void handle_read_content(const boost::system::error_code & error);

public:

CPush(void){}

void LoopStart(void);
void LoopStop(void);
void Send(const std::string tokens, const std::string cmd);
};

Реализация

bool CPush::verify_certificate(bool preverified, boost::asio::ssl::verify_context & ctx)
{
    char subject_name[256];
    X509 * cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
    X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);

    std::cout << "Verifying " << subject_name << std::endl;

    return preverified;
}

void CPush::handle_connect(const boost::system::error_code & error)
{
    if (error)
        std::cerr << "Connect failed: " << error.message() << std::endl;
    else
    {
        // Support for Server Name Indication (SNI)
        SSL_set_tlsext_host_name(psocket->native_handle(), GOOGLE_HOST);

        psocket->async_handshake(boost::asio::ssl::stream_base::client,
                                boost::bind(&CPush::handle_handshake,
                                            this,
                                            boost::asio::placeholders::error));
        std::cout << "Connection OK!" << std::endl;
    }
}

void CPush::handle_handshake(const boost::system::error_code & error)
{
    if (error)
        std::cerr << "Handshake failed: " << error.message() << std::endl;
    else
    {  }
}

void CPush::handle_write(const boost::system::error_code & error)
{
    if (error)
      std::cerr << "Write failed: " << error.message() << std::endl;
    else
    {
        boost::asio::async_read_until(*psocket,
                                response, "\r\n",
                                boost::bind(&CPush::handle_read_status,
                                            this,
                                            boost::asio::placeholders::error));
        std::cout << "Sending request OK!" << std::endl;
    }
}

void CPush::handle_read_status(const boost::system::error_code & error)
{
    if (error)
        std::cout << "Error read status: " << error.message() << std::endl;
    else
    {
        // Check that response is OK.
        std::istream response_stream(&response);
        std::string http_version;
        response_stream >> http_version;
        unsigned int status_code;
        response_stream >> status_code;
        std::string status_message;
        std::getline(response_stream, status_message);

        if (!response_stream || http_version.substr(0, 5) != "HTTP/")
        {
            std::cout << "Invalid response\n";
            return;
        }

        if (status_code != 200)
        {
            std::cout << "Response returned with status code ";
            std::cout << status_code << "\n";
//          return;
        }

        // Read the response headers, which are terminated by a blank line.
        boost::asio::async_read_until(*psocket,
                                        response, "\r\n\r\n",
                                        boost::bind(&CPush::handle_read_header,
                                                    this,
                                                    boost::asio::placeholders::error));
    }
}

void CPush::handle_read_header(const boost::system::error_code & error)
{
    if (error)
        std::cout << "Error read header: " << error.message() << std::endl;
    else
    {
        // Process the response headers.
        std::istream response_stream(&response);
        std::string header;
        while (std::getline(response_stream, header) && header != "\r")
            std::cout << header << "\n";
        std::cout << "\n";

        // Write whatever content we already have to output.
        if (response.size() > 0)
            std::cout << &response;

        // Start reading remaining data until EOF.
        boost::asio::async_read(*psocket,
                                response,
                                boost::asio::transfer_at_least(1),
                                boost::bind(&CPush::handle_read_content,
                                            this,
                                            boost::asio::placeholders::error));
    }
}

void CPush::handle_read_content(const boost::system::error_code & error)
{
    if (error)
    {
        if (error != boost::asio::error::eof)
            std::cout << "Error read content: " << error.message() << std::endl;
    }
    else
    {
        // Write all of the data that has been read so far.
        std::cout << &response;

        // Continue reading remaining data until EOF.
        boost::asio::async_read(*psocket,
                                response,
                                boost::asio::transfer_at_least(1),
                                boost::bind(&CPush::handle_read_content,
                                            this,
                                            boost::asio::placeholders::error));
    }
}

void CPush::LoopStart(void)
{
    boost::asio::io_service io_service;
    boost::asio::ip::tcp::resolver resolver(io_service);
    boost::asio::ip::tcp::resolver::query query(GOOGLE_HOST, GOOGLE_PORT);
    boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);

    boost::asio::ssl::context context(boost::asio::ssl::context::sslv23);
    context.set_default_verify_paths();

    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket(io_service, context);
    socket.set_verify_mode(boost::asio::ssl::context::verify_none);
    socket.set_verify_callback(boost::bind(&CPush::verify_certificate, this, _1, _2));

    psocket = &socket;
    pio_service = &io_service;

    boost::asio::async_connect(psocket->lowest_layer(),
                                iterator,
                                boost::bind(&CPush::handle_connect,
                                            this,
                                            boost::asio::placeholders::error));

    io_service.run();
}

void CPush::Send(const std::string tokens, const std::string cmd)
{
    std::string json("{\"registration_ids\":[" + tokens + "],"
                    "\"notification\":null,"
....
                    "\"priority\":\"high\","
                    "\"time_to_live\":15}");

    request << "POST " << GOOGLE_API << " HTTP/1.1\r\n"
            << "Host: " << GOOGLE_HOST << "\r\n" // << ":" << port
            << "Content-Type: application/json; charset=utf-8\r\n"
            << "Content-Length: " << json.size() << "\r\n"
            << "Authorization: key=" << push_key << "\r\n"
            << "\r\n"
            << json;

    std::cout << "Sending request...\n" << request.str() << std::endl;

    boost::asio::async_write(*psocket,
                            boost::asio::buffer(request.str()),
                            boost::bind(&CPush::handle_write,
                                        this,
                                        boost::asio::placeholders::error));
}

void CPush::LoopStop(void)
{
    if (!pio_service->stopped()) pio_service->stop();
}
★★★

Вот здесь:

    boost::asio::async_write(*psocket,
                            boost::asio::buffer(request.str()),
                            boost::bind(&CPush::handle_write,
                                        this,
                                        boost::asio::placeholders::error));

Вы передаете в boost::asio::buffer() временную строку. Насколько я помню, Asio-шные const_buffer и mutable_buffer хранят только указатель на исходные данные, но сами исходные данные не копируют:

he mutable_buffer class provides a safe representation of a buffer that can be modified. It does not own the underlying data, and so is cheap to copy or assign.

Так что если сохраненный в const_/mutable_buffer указатель протухнет, то у вас будет ай-ай-ай при попытке обратиться к нему (во время актуальной операции write).

Этот фрагмент, на мой взгляд, откровенно попахивает.

void CPush::Send(const std::string tokens, const std::string cmd)

У вас здесь token и cmd специально как константные объекты передаются? Ведь могло бы хватить и константной ссылки. Или, если у вас есть Boost, какого-нибудь boost::string_view.

тдельные личности с большим самомнением

Не-не-не. Не с самомнением, а сильнейшими фантомными болями от многократно отстрелянных ног.

начнут объяснять какой я тупой

Опыт показывает, что вас учить только портить.

eao197 ★★★★★
()
Ответ на: комментарий от hizel

было бы не плохо, но к сожалению ничего мне это не говорит пока что

Thread 4 "MQTTAsync_rcv" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff4c23700 (LWP 41253)]
0x00007ffff6ebff84 in SSL_write () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1

wolverin ★★★
() автор топика
Ответ на: комментарий от eao197

про boost::asio::buffer я уже прочитал, поэтому и поднял его до переменной класса, поэтому он точно жив все время существования объекта

Ведь могло бы хватить и константной ссылки.

пока для эксперимента, поэтому что там из асинхронного метода в асинхронный вызывается и чтобы не следить где объект уничтожится и везде иметь копии

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

про boost::asio::buffer я уже прочитал, поэтому и поднял его до переменной класса, поэтому он точно жив все время существования объекта

Ознакомьтесь: https://en.cppreference.com/w/cpp/io/basic_stringstream/str

eao197 ★★★★★
()
Ответ на: комментарий от eao197

переделал на вариант с объявлением в классе как std::string request и не помогло

    request = "POST " + std::string(GOOGLE_API) + " HTTP/1.1\r\n"
            "Host: " + GOOGLE_HOST + "\r\n" // << ":" << port
            "Content-Type: application/json; charset=utf-8\r\n"
            "Content-Length: " + std::to_string(json.size()) + "\r\n"
            "Authorization: key=" + push_key + "\r\n"
            "\r\n" + json;

    std::cout << "Sending request...\n" << request << std::endl;

    boost::asio::async_write(*psocket,
                            boost::asio::buffer(request),
                            boost::bind(&CPush::handle_write,
                                        this,
                                        boost::asio::placeholders::error));

wolverin ★★★
() автор топика
Ответ на: комментарий от hizel

ну там ранее ничего кроме моего стдаута и нету особо, вот если без него так целиком выглядит

Starting program: ...
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
...
[New Thread 0x7ffff6254700 (LWP 42093)]
....
[New Thread 0x7ffff5424700 (LWP 42094)]
[New Thread 0x7ffff4c23700 (LWP 42095)]
[New Thread 0x7fffeffff700 (LWP 42096)]

....

[Thread 0x7ffff6254700 (LWP 42093) exited]

.... В ЭТОТ МОМЕНТ ШЛЮ КОМАНДУ ЧЕРЕЗ МКТТ ....

Thread 4 "MQTTAsync_rcv" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff4c23700 (LWP 42095)]
0x00007ffff6ebff84 in SSL_write () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1

wolverin ★★★
() автор топика
Ответ на: комментарий от eao197

пробую

Thread 4 "MQTTAsync_rcv" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff5040700 (LWP 42731)]
0x00007ffff6ebff84 in SSL_write () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1
(gdb) bt
#0  0x00007ffff6ebff84 in SSL_write () from /usr/lib/x86_64-linux-gnu/libssl.so.1.1
#1  0x0000555555591022 in boost::asio::ssl::detail::engine::perform(int (boost::asio::ssl::detail::engine::*)(void*, unsigned long), void*, unsigned long, boost::system::error_code&, unsigned long*) ()
#2  0x000055555559ceaf in boost::asio::ssl::detail::io_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::ssl::detail::write_op<boost::asio::const_buffers_1>, boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::asio::const_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf1<void, CPush, boost::system::error_code const&>, boost::_bi::list2<boost::_bi::value<CPush*>, boost::arg<1> (*)()> > > >::operator()(boost::system::error_code, unsigned long, int) ()
#3  0x000055555559d4b9 in boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::asio::const_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf1<void, CPush, boost::system::error_code const&>, boost::_bi::list2<boost::_bi::value<CPush*>, boost::arg<1> (*)()> > >::operator()(boost::system::error_code const&, unsigned long, int) ()
#4  0x000055555558a544 in CPush::Send(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) ()
#5  0x000055555558ad44 in MQTTArrived(char const*, int, char const*, int) ()
#6  0x00005555555b4d9a in onMessageArrived ()
#7  0x00005555555c07f2 in MQTTAsync_deliverMessage (m=0x555555d099f8,
    topicName=0x7fffe4000ad8 "............", topicLen=46, mm=0x7fffe4000ee8)
    at /root/utils/paho.mqtt.c/src/MQTTAsyncUtils.c:2534
#8  0x00005555555c0b18 in Protocol_processPublication (publish=0x7fffe4000e78, client=0x555555d09fb8, allocatePayload=1)
    at /root/utils/paho.mqtt.c/src/MQTTAsyncUtils.c:2587
#9  0x00005555555c2bf6 in MQTTProtocol_handlePublishes (pack=0x7fffe4000e78, sock=5)
    at /root/utils/paho.mqtt.c/src/MQTTProtocolClient.c:339
#10 0x00005555555c186b in MQTTAsync_cycle (sock=0x7ffff503fe24, timeout=1000, rc=0x7ffff503fe28)
    at /root/utils/paho.mqtt.c/src/MQTTAsyncUtils.c:3030
#11 0x00005555555bf016 in MQTTAsync_receiveThread (n=0x555555d099f8) at /root/utils/paho.mqtt.c/src/MQTTAsyncUtils.c:2016
#12 0x00007ffff79be4a4 in start_thread (arg=0x7ffff5040700) at pthread_create.c:456
#13 0x00007ffff633dd0f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:97
wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

В SSL_write передаются всего два указателя: на ssl и на буфер. Если вы уверены, что указатель на буфер валидный, то остается ssl.

Нет ли у вас преждевременного выхода из вашего StartLoop?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Нет ли у вас преждевременного выхода из вашего StartLoop?

да в этом ошибка была, после соединения и рукопожатия в отсутствии новых команд io_service.run() завершается

хотел было извиниться, но после очередных оскорблений, скажу только спасибо за помощь.

wolverin ★★★
() автор топика