C++ boost beast websocket crash after running a while - c++

I am using boost beast to connect to a server's websocket.
I only rewrite the on_read function in order to make the websocket never disconnect, the other parts are just copied from beast example code.
Here is my code:
void
on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type ep){
beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(10));
if(! SSL_set_tlsext_host_name(
ws_.next_layer().native_handle(),
host_.c_str())){
ec = beast::error_code(static_cast<int>(::ERR_get_error()),
net::error::get_ssl_category());
return fail(ec, "connect");
}
ws_.next_layer().async_handshake(
ssl::stream_base::client,
beast::bind_front_handler(
&session::on_ssl_handshake,
shared_from_this()));
}
void
on_ssl_handshake(beast::error_code ec){
beast::get_lowest_layer(ws_).expires_never();
ws_.set_option(
websocket::stream_base::timeout::suggested(
beast::role_type::client));
ws_.set_option(websocket::stream_base::decorator(
[](websocket::request_type& req){
req.set(http::field::user_agent,
std::string(BOOST_BEAST_VERSION_STRING) +
" websocket-client-async-ssl");
}));
ws_.async_handshake(host_, "/mix/v1/stream",
beast::bind_front_handler(
&session::on_handshake,
shared_from_this()));
}
void
on_handshake(beast::error_code ec){
// Send the message
ws_.async_write(
net::buffer("{\"op\": \"subscribe\",\"args\": [{\"instType\":\"mc\",\"channel\":\"books1\",\"instId\":\"BTCUSDT\"}]}"),
beast::bind_front_handler(
&session::on_write,
shared_from_this()));
}
void
on_write(
beast::error_code ec,
std::size_t bytes_transferred){
boost::ignore_unused(bytes_transferred);
ws_.async_read(
buffer_,
beast::bind_front_handler(
&session::on_read,
shared_from_this()));
}
void
on_read(
beast::error_code ec,
std::size_t bytes_transferred){
boost::ignore_unused(bytes_transferred);
if(ec)
return fail(ec, "read");
auto j = json::parse(beast::buffers_to_string(buffer_.data()));
if (j.contains(std::string{ "data" })){
asks = std::stof(std::string(j["data"][0]["asks"][0][0]));
bids = std::stof(std::string(j["data"][0]["bids"][0][0]));
}
buffer_.clear();
ws_.async_read(
buffer_,
beast::bind_front_handler(
&session::on_read,
shared_from_this()));
}
void
on_close(beast::error_code ec){
if(ec)
return fail(ec, "close");
std::cout << beast::make_printable(buffer_.data()) << std::endl;
}
/*************************************************************************************************/
int main(int argc, char **argv) {
net::io_context ioc;
ssl::context ctx{ssl::context::tlsv12_client};
ctx.set_verify_mode(ssl::verify_peer);
ctx.set_default_verify_paths();
auto const host = "ws.bitget.com";
auto const port = "443";
std::make_shared<session>(ioc, ctx)->run(host, port, "");
ioc.run();
return 0;
}
The websocket connect successfully and can get the correct data from the server. But it can only run for few seconds, the following error will occur:
read: stream truncated
==12771==ERROR: AddressSanitizer: heap-use-after-free on address 0x000109e02da0 at pc 0x00010302a8e4 bp 0x00016d78d2f0 sp 0x00016d78d2e8
READ of size 8 at 0x000109e02da0 thread T0
#0 0x10302a8e0 in boost::intrusive::rbtree_node<void*>* boost::intrusive::bstree_algorithms<boost::intrusive::rbtree_node_traits<void*, false> >::find<void const*, boost::intrusive::detail::key_nodeptr_comp<std::__1::less<void const*>, boost::intrusive::mhtraits<binapi::ws::websocket, boost::intrusive::set_member_hook<>, &(binapi::ws::websocket::m_intrusive_set_hook)>, binapi::ws::websocket_id_getter> >(boost::intrusive::rbtree_node<void*> const*, void const* const&, boost::intrusive::detail::key_nodeptr_comp<std::__1::less<void const*>, boost::intrusive::mhtraits<binapi::ws::websocket, boost::intrusive::set_member_hook<>, &(binapi::ws::websocket::m_intrusive_set_hook)>, binapi::ws::websocket_id_getter>) bstree_algorithms.hpp:759
#1 0x10302a42c in boost::intrusive::tree_iterator<boost::intrusive::mhtraits<binapi::ws::websocket, boost::intrusive::set_member_hook<>, &(binapi::ws::websocket::m_intrusive_set_hook)>, false> boost::intrusive::bstbase2<boost::intrusive::mhtraits<binapi::ws::websocket, boost::intrusive::set_member_hook<>, &(binapi::ws::websocket::m_intrusive_set_hook)>, binapi::ws::websocket_id_getter, void, (boost::intrusive::algo_types)5, void>::find<void const*, std::__1::less<void const*> >(void const* const&, std::__1::less<void const*>) bstree.hpp:383
#2 0x1032c4260 in void* binapi::ws::websockets::impl::start_channel<std::__1::function<bool (char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, binapi::ws::book_ticker_t)> >(char const*, char const*, std::__1::function<bool (char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, binapi::ws::book_ticker_t)>)::'lambda'(binapi::ws::websocket*)::operator()(binapi::ws::websocket*) const websocket.cpp:276
#3 0x1032c4cbc in std::__1::__shared_ptr_pointer<binapi::ws::websocket*, void* binapi::ws::websockets::impl::start_channel<std::__1::function<bool (char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, binapi::ws::book_ticker_t)> >(char const*, char const*, std::__1::function<bool (char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, binapi::ws::book_ticker_t)>)::'lambda'(binapi::ws::websocket*), std::__1::allocator<binapi::ws::websocket> >::__on_zero_shared() shared_ptr.h:267
#4 0x1026a05ac in std::__1::__shared_count::__release_shared() shared_ptr.h:177
#5 0x1026a04ec in std::__1::__shared_weak_count::__release_shared() shared_ptr.h:219
#6 0x1026a04bc in std::__1::shared_ptr<boost::beast::http::detail::chunk_size::sequence>::~shared_ptr() shared_ptr.h:959
#7 0x102677b5c in std::__1::shared_ptr<std::__1::vector<boost::asio::ip::basic_resolver_entry<boost::asio::ip::tcp>, std::__1::allocator<boost::asio::ip::basic_resolver_entry<boost::asio::ip::tcp> > > >::~shared_ptr() shared_ptr.h:957
#8 0x103196b18 in binapi::ws::websocket::on_async_ssl_handshake(std::__1::function<bool (char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, char const*, unsigned long)>, std::__1::shared_ptr<binapi::ws::websocket>)::'lambda'(boost::system::error_code)::~() websocket.cpp:187
#9 0x1030c8a8c in binapi::ws::websocket::async_connect(boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>, std::__1::function<bool (char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, char const*, unsigned long)>, std::__1::shared_ptr<binapi::ws::websocket>)::'lambda'(boost::system::error_code, boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp>)::~() websocket.cpp:102
#10 0x103263850 in boost::asio::detail::binder2<binapi::ws::websocket::async_start(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::function<bool (char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, char const*, unsigned long)>, std::__1::shared_ptr<binapi::ws::websocket>)::'lambda'(boost::system::error_code, boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>), boost::system::error_code, boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp> >::~binder2() bind_handler.hpp:252
#11 0x1030cb2a8 in boost::asio::detail::binder2<binapi::ws::websocket::async_start(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::function<bool (char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, char const*, unsigned long)>, std::__1::shared_ptr<binapi::ws::websocket>)::'lambda'(boost::system::error_code, boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>), boost::system::error_code, boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp> >::~binder2() bind_handler.hpp:252
#12 0x1030cab70 in boost::asio::detail::resolve_query_op<boost::asio::ip::tcp, binapi::ws::websocket::async_start(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::function<bool (char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, char const*, unsigned long)>, std::__1::shared_ptr<binapi::ws::websocket>)::'lambda'(boost::system::error_code, boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>), boost::asio::any_io_executor>::do_complete(void*, boost::asio::detail::scheduler_operation*, boost::system::error_code const&, unsigned long) resolve_query_op.hpp:134
#13 0x102687c14 in boost::asio::detail::scheduler_operation::destroy() scheduler_operation.hpp:45
#14 0x10268badc in boost::asio::detail::scheduler::shutdown() scheduler.ipp:176
#15 0x102691a50 in boost::asio::detail::service_registry::shutdown_services() service_registry.ipp:44
#16 0x102691920 in boost::asio::execution_context::shutdown() execution_context.ipp:41
#17 0x10267b0b4 in boost::asio::execution_context::~execution_context() execution_context.ipp:34
#18 0x102c67788 in boost::asio::io_context::~io_context() io_context.ipp:58
#19 0x102677bb4 in boost::asio::io_context::~io_context() io_context.ipp:57
#20 0x1026758e4 in main main.cpp:508
#21 0x1072d5084 in start+0x200 (dyld:arm64e+0x5084)
0x000109e02da0 is located 96 bytes inside of 128-byte region [0x000109e02d40,0x000109e02dc0)
freed by thread T0 here:
#0 0x107ad5018 in wrap__ZdlPv+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x4d018)
#1 0x1030b3580 in std::__1::default_delete<binapi::ws::websockets::impl>::operator()(binapi::ws::websockets::impl*) const unique_ptr.h:57
#2 0x1030b34f4 in std::__1::unique_ptr<binapi::ws::websockets::impl, std::__1::default_delete<binapi::ws::websockets::impl> >::reset(binapi::ws::websockets::impl*) unique_ptr.h:318
#3 0x1030b3428 in std::__1::unique_ptr<binapi::ws::websockets::impl, std::__1::default_delete<binapi::ws::websockets::impl> >::~unique_ptr() unique_ptr.h:272
#4 0x103020750 in std::__1::unique_ptr<binapi::ws::websockets::impl, std::__1::default_delete<binapi::ws::websockets::impl> >::~unique_ptr() unique_ptr.h:272
#5 0x103020724 in binapi::ws::websockets::~websockets() websocket.cpp:408
#6 0x10302077c in binapi::ws::websockets::~websockets() websocket.cpp:408
#7 0x1026758cc in main main.cpp:508
#8 0x1072d5084 in start+0x200 (dyld:arm64e+0x5084)
previously allocated by thread T0 here:
#0 0x107ad4bd8 in wrap__Znwm+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x4cbd8)
#1 0x103020464 in std::__1::__unique_if<binapi::ws::websockets::impl>::__unique_single std::__1::make_unique<binapi::ws::websockets::impl, boost::asio::io_context&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::function<void (char const*, char const*, unsigned long)> >(boost::asio::io_context&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&, std::__1::function<void (char const*, char const*, unsigned long)>&&) unique_ptr.h:728
#2 0x1030202e8 in binapi::ws::websockets::websockets(boost::asio::io_context&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::function<void (char const*, char const*, unsigned long)>) websocket.cpp:404
#3 0x1030206f8 in binapi::ws::websockets::websockets(boost::asio::io_context&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::function<void (char const*, char const*, unsigned long)>) websocket.cpp:405
#4 0x102674fd8 in main main.cpp:326
#5 0x1072d5084 in start+0x200 (dyld:arm64e+0x5084)
SUMMARY: AddressSanitizer: heap-use-after-free bstree_algorithms.hpp:759 in boost::intrusive::rbtree_node<void*>* boost::intrusive::bstree_algorithms<boost::intrusive::rbtree_node_traits<void*, false> >::find<void const*, boost::intrusive::detail::key_nodeptr_comp<std::__1::less<void const*>, boost::intrusive::mhtraits<binapi::ws::websocket, boost::intrusive::set_member_hook<>, &(binapi::ws::websocket::m_intrusive_set_hook)>, binapi::ws::websocket_id_getter> >(boost::intrusive::rbtree_node<void*> const*, void const* const&, boost::intrusive::detail::key_nodeptr_comp<std::__1::less<void const*>, boost::intrusive::mhtraits<binapi::ws::websocket, boost::intrusive::set_member_hook<>, &(binapi::ws::websocket::m_intrusive_set_hook)>, binapi::ws::websocket_id_getter>)
Shadow bytes around the buggy address:
0x0070213e0560: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0070213e0570: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x0070213e0580: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa
0x0070213e0590: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0070213e05a0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
=>0x0070213e05b0: fd fd fd fd[fd]fd fd fd fa fa fa fa fa fa fa fa
0x0070213e05c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0070213e05d0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x0070213e05e0: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
0x0070213e05f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0070213e0600: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==12771==ABORTING
zsh: abort
I can confirm that the server is not disconnected or sending abnormal messages.
And my message buffer also clears after each read.
I've also checked the websocket code written by others, it seems to be similar to mine.

Related

MQTT AND Web Server connections within same sketch on NodeMCU

I am unable to establish a http server connection and MQTT connection at the same time on an ESP8266 (Nodemcu) using libraries ESPAsyncWebServer and PubSubClient. My intention is to push over the air updates using the library AsyncElegantOTA while at the same time using MQTT for something else. Everything works great until I attempt to establish the HTTP server connection using the method below: setup_http(). I have tried establishing the connection within setup but that fails immediately and the connection cycles repeatedly. So, I have attempted to establish the connection within the loop function but that is failing as well. Is it possible to run both in the same sketch?
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <time.h>
#include "Secrets.h"
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>
#define IOT_PUBLISH_TOPIC "pubout"
#define IOT_SUBSCRIBE_TOPIC "subin"
bool isServerStarted = false;
time_t now;
time_t nowish = 1510592825;
BearSSL::X509List cert(cacert);
BearSSL::X509List client_crt(client_cert);
BearSSL::PrivateKey key(privkey);
WiFiClientSecure net;
PubSubClient client(net);
void NTPConnect(void)
{
Serial.print("Setting time using SNTP");
configTime(TIME_ZONE * 3600, 0 * 3600, "pool.ntp.org", "time.nist.gov");
now = time(nullptr);
while (now < nowish)
{
delay(500);
Serial.print(".");
now = time(nullptr);
}
Serial.println("done!");
struct tm timeinfo;
gmtime_r(&now, &timeinfo);
Serial.print("Current time: ");
Serial.print(asctime(&timeinfo));
}
String get_wifi_status()
{
switch (WiFi.status())
{
case WL_IDLE_STATUS:
return String("Wifi is changing modes.");
break;
case WL_NO_SSID_AVAIL:
return String("SSID: '") + WIFI_SSID + " is not available.";
break;
case WL_CONNECTED:
return String("Connected to ") + WIFI_SSID;
break;
case WL_CONNECT_FAILED:
return String("Could not connect to ") + WIFI_SSID;
break;
case WL_DISCONNECTED:
return String("Wifi not in station mode.");
break;
default:
return String("Wifi status error");
}
}
void setup_network()
{
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
WiFi.mode(WIFI_STA);
Serial.println("");
while (WiFi.status() != WL_CONNECTED)
{
Serial.print("Connecting to ");
Serial.print(WIFI_SSID);
Serial.println("...");
delay(1000);
}
Serial.println(get_wifi_status());
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void messageReceived(char *topic, byte *payload, unsigned int length)
{
//handle messages
}
void setup_mqtt()
{
delay(3000);
NTPConnect();
net.setTrustAnchors(&cert);
net.setClientRSACert(&client_crt, &key);
client.setServer(MQTT_HOST, 8883);
client.setCallback(messageReceived);
Serial.println("Connecting to IOT");
while (!client.connect(THINGNAME))
{
Serial.print(".");
delay(1000);
}
if (!client.connected())
{
Serial.println("IoT Timeout!");
return;
}
// Subscribe to a topic
client.subscribe(IOT_SUBSCRIBE_TOPIC);
Serial.println("IoT Connected!");
}
void setup_http()
{
AsyncWebServer server(80);
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(200, "text/plain", "Hi! I am a http server."); });
server.begin();
AsyncElegantOTA.begin(&server); // Start ElegantOTA
Serial.println("HTTP server started");
}
void setup()
{
Serial.begin(115200);
setup_network();
setup_mqtt();
// setup_http(); //Does not work here and crashes before MQTT connects. So, I moved to loop but that doesn't work either.
}
void loop()
{
now = time(nullptr);
if (!client.connected())
{
setup_mqtt();
}
if (isServerStarted == false)
{
Serial.println("Attempting to start http server");
delay(3000);
setup_http();
isServerStarted = true;
Serial.println("It crashes before we get here");
}
else
{
client.loop();
// BEGIN Loop code
}
}
Exception:
User exception (panic/abort/assert)
--------------- CUT HERE FOR EXCEPTION DECODER ---------------
Unhandled C++ exception: OOM
>>>stack>>>
ctx: cont
sp: 3ffffd20 end: 3fffffc0 offset: 0000
3ffffd20: 3fff199c 3fff169c 000000ff 00000000
3ffffd30: 000000fe 00000000 00000000 00000000
3ffffd40: 00000000 00000000 00000000 00000001
3ffffd50: 3fff3198 00000000 3fff31a4 00000000
3ffffd60: 00000000 402089c6 00000c08 4021f12e
3ffffd70: 00000000 00000020 00000c08 4021f14d
3ffffd80: 3fff63ec 402089c6 00000c08 4021e832
3ffffd90: 3ffffda0 3ffffdec 3ffffde4 402089c6
3ffffda0: cca8cca9 00000000 3fff4554 40208bd6
3ffffdb0: c0afc0ae c027c023 c028c024 c013c009
3ffffdc0: c014c00a c031c02d c032c02e 00000000
3ffffdd0: c02ac026 c00ec004 c00fc005 009d009c
3ffffde0: c09dc09c c0a1c0a0 003d003c 0035002f
3ffffdf0: c012c008 c00dc003 0000000a 4021e813
3ffffe00: 00000000 3ffffe9c 3ffffe94 3fff6804
3ffffe10: 00000000 00000000 3fff4554 40209108
3ffffe20: 3fff1698 00000000 00000000 4025ebd3
3ffffe30: 007a1200 3fff4554 00000040 4025a222
3ffffe40: 007a1200 32087824 00000000 00000000
3ffffe50: 00000000 00000000 00000000 00000000
3ffffe60: 40106105 002da5e3 3fff13d8 00000000
3ffffe70: 3fff0af0 3fff13d8 00000001 00000000
3ffffe80: 00000000 00000000 00000000 00000000
3ffffe90: 00000000 3ffffe9c 00000000 4021f24a
3ffffea0: 3ffe8ff8 3fff4554 3fff61ec 402074f2
3ffffeb0: 3ffffee0 00000000 3fff1ac0 00000001
3ffffec0: 000022b3 3fff4554 3ffe8ff8 00000001
3ffffed0: 000022b3 3fff4554 3ffe8ff8 402093b4
3ffffee0: 40224b24 b781db12 40224b24 b781db12
3ffffef0: 00000000 00000000 3fff0ff8 40222932
3fffff00: 00004b4f 3fff4554 3fff0ff8 4020426c
3fffff10: 00000002 3fff1218 3fff610c 40220395
3fffff20: 00000000 00000000 3ffe8e9c 00000000
3fffff30: 00000000 3fff1218 3ffe967c 4021bce0
3fffff40: 4021bcd4 3fff1218 3ffe967c 3fff1370
3fffff50: 3fffdad0 3fff4554 3fff1044 40204518
3fffff60: 00000000 00000000 00000001 4021c200
3fffff70: 40224b24 3fff4554 3fff1044 40201e97
3fffff80: 402039cc feefeffe 40222b18 40222afc
3fffff90: 3fffdad0 00000000 3ffe88e4 40201f15
3fffffa0: feefeffe feefeffe feefeffe 4021ebb7
3fffffb0: feefeffe feefeffe feefeffe 40101225
<<<stack<<<
0x402089c6 in std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> > >::__allocated_ptr(std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> >&, std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0>*) at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/allocated_ptr.h:53
(inlined by) std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> > > std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> > >(std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> >&) at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/allocated_ptr.h:97
0x4021f12e in raise_exception at core_esp8266_postmortem.cpp:?
0x4021f14d in __unhandled_exception at ??:?
0x402089c6 in std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> > >::__allocated_ptr(std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> >&, std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0>*) at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/allocated_ptr.h:53
(inlined by) std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> > > std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> > >(std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> >&) at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/allocated_ptr.h:97
0x4021e832 in operator new(unsigned int) at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\cores\esp8266/abi.cpp:47
0x402089c6 in std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> > >::__allocated_ptr(std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> >&, std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0>*) at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/allocated_ptr.h:53
(inlined by) std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> > > std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> > >(std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> >&) at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/allocated_ptr.h:97
0x40208bd6 in std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<br_x509_minimal_context, std::allocator<br_x509_minimal_context>, (__gnu_cxx::_Lock_policy)0> > >::get() at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/allocated_ptr.h:85
(inlined by) std::__shared_count<(__gnu_cxx::_Lock_policy)0>::__shared_count<br_x509_minimal_context, std::allocator<br_x509_minimal_context>>(br_x509_minimal_context*&, std::_Sp_alloc_shared_tag<std::allocator<br_x509_minimal_context> >) at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/shared_ptr_base.h:681
(inlined by) std::__shared_ptr<br_x509_minimal_context, (__gnu_cxx::_Lock_policy)0>::__shared_ptr<std::allocator<br_x509_minimal_context>>(std::_Sp_alloc_shared_tag<std::allocator<br_x509_minimal_context> >) at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/shared_ptr_base.h:1371
(inlined by) std::shared_ptr<br_x509_minimal_context>::shared_ptr<std::allocator<br_x509_minimal_context>>(std::_Sp_alloc_shared_tag<std::allocator<br_x509_minimal_context> >) at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/shared_ptr.h:408
(inlined by) std::shared_ptr<br_x509_minimal_context> std::allocate_shared<br_x509_minimal_context, std::allocator<br_x509_minimal_context>>(std::allocator<br_x509_minimal_context> const&) at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/shared_ptr.h:860
(inlined by) std::shared_ptr<br_x509_minimal_context> std::make_shared<br_x509_minimal_context>() at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/shared_ptr.h:876
(inlined by) BearSSL::WiFiClientSecureCtx::_installClientX509Validator() at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\libraries\ESP8266WiFi\src/WiFiClientSecureBearSSL.cpp:1063
0x4021e813 in operator new(unsigned int) at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\cores\esp8266/abi.cpp:41
0x40209108 in BearSSL::WiFiClientSecureCtx::_connectSSL(char const*) at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\libraries\ESP8266WiFi\src/WiFiClientSecureBearSSL.cpp:1134
0x4025ebd3 in ip_chksum_pseudo at /home/earle/src/esp-quick-toolchain/arduino/tools/sdk/lwip2/builder/lwip2-src/src/core/inet_chksum.c:395
0x4025a222 in tcp_output at /home/earle/src/esp-quick-toolchain/arduino/tools/sdk/lwip2/builder/lwip2-src/src/core/tcp_out.c:1361
0x40106105 in ets_timer_arm_new at ??:?
0x4021f24a in delay at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\cores\esp8266/core_esp8266_wiring.cpp:54
0x402074f2 in ClientContext::connect(ip4_addr*, unsigned short) at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\libraries\ESP8266WiFi\src/include/ClientContext.h:148
(inlined by) WiFiClient::connect(IPAddress, unsigned short) at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\libraries\ESP8266WiFi\src/WiFiClient.cpp:162
0x402093b4 in BearSSL::WiFiClientSecureCtx::connect(char const*, unsigned short) at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\libraries\ESP8266WiFi\src/WiFiClientSecureBearSSL.cpp:232
0x40224b24 in DhcpServer::add_end(unsigned char*) at ??:?
0x40224b24 in DhcpServer::add_end(unsigned char*) at ??:?
0x40222932 in BearSSL::WiFiClientSecure::connect(char const*, unsigned short) at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\libraries\ESP8266WiFi\src/WiFiClientSecureBearSSL.h:245
0x4020426c in PubSubClient::connect(char const*, char const*, char const*, char const*, unsigned char, bool, char const*, bool) at .pio\libdeps\nodemcu\PubSubClient\src/PubSubClient.cpp:190
0x40220395 in uart_write at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\cores\esp8266/uart.cpp:544
0x4021bce0 in HardwareSerial::write(unsigned char const*, unsigned int) at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\cores\esp8266/HardwareSerial.h:194
0x4021bcd4 in HardwareSerial::write(unsigned char const*, unsigned int) at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\cores\esp8266/HardwareSerial.h:191
0x40204518 in PubSubClient::connect(char const*) at .pio\libdeps\nodemcu\PubSubClient\src/PubSubClient.cpp:167
0x4021c200 in Print::println(char const*) at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\cores\esp8266/Print.cpp:194
0x40224b24 in DhcpServer::add_end(unsigned char*) at ??:?
0x40201e97 in setup_mqtt() at src/main.cpp:133
0x402039cc in messageReceived(char*, unsigned char*, unsigned int) at src/main.cpp:114
0x40222b18 in std::_Function_handler<void (char*, unsigned char*, unsigned int), void (*)(char*, unsigned char*, unsigned int)>::_M_manager(std::_Any_data&, std::_Any_data const&, std::_Manager_operation) at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/std_function.h:271
0x40222afc in std::_Function_handler<void (char*, unsigned char*, unsigned int), void (*)(char*, unsigned char*, unsigned int)>::_M_invoke(std::_Any_data const&, char*&&, unsigned char*&&, unsigned int&&) at c:\users\myusername\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/std_function.h:289
0x40201f15 in setup at src/main.cpp:171
0x4021ebb7 in loop_wrapper() at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\cores\esp8266/core_esp8266_main.cpp:198
0x40101225 in cont_wrapper at C:\Users\myusername\.platformio\packages\framework-arduinoespressif8266\cores\esp8266/cont.S:81
last failed alloc call: 402089C6(3080)
--------------- CUT HERE FOR EXCEPTION DECODER ---------------
last failed alloc caller: 0x402089c6
ets Jan 8 2013,rst cause:2, boot mode:(3,6)
load 0x4010f000, len 3460, room 16
tail 4
chksum 0xcc
load 0x3fff20b8, len 40, room 4
tail 4
chksum 0xc9
csum 0xc9
v000b9e90
~ld
In setup_http(), you declared server as a variable local to the function. That means when the function returns, the variable (and web server) will be destroyed, which will lead to some seriously undefined behavior, like a crash.
You need to make sure that server exists and is valid for the lifetime of the web server, so you should declare it outside of the function, as a global or static variable.
For instance,
AsyncWebServer server(80);
void setup_http()
{
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(200, "text/plain", "Hi! I am a http server."); });
server.begin();
...
This will ensure that server isn't destroyed while you're still using it.

Boost deadline_timer causes stack-buffer-overflow

I have been stuck on a really wierd bug with Boost Deadline_timer for the last days.
Desktop: Ubuntu 18.04
Boost: v1.65.01
When I create a new deadline_timer within the constructor of my class AddressSanitizer catches a stack-buffer-overflow coming from inside the Boost libraries.
I have a few observations:
I also notice that something is wrong without AddressSanitizer by that either the timer timeouts all the time becauce expiry_time is negative, or never expires. So it seems as if someplace someone is changing that memory region.
The class I am working with is quite big and is using the same Boost io_service to send data over UDP.
I am not able to reproduce the bug in just a standalone source file.
When I remove code to isolate the issue the issue remains no matter how much code I remove. I have gone down to a just a main filecreate a io_service and a deadline_timer and it stills throws that error. If I duplicate that in another file and duplicate the CMakeLists entry I am still not able to reproduce it.
The structure of the class is not very complicated and here is an example class which essentially does the same
udp_timer.hpp
#include "boost/asio.hpp"
class UdpTimer {
public:
UdpTimer();
~UdpTimer();
void run();
void timer_callback(const boost::system::error_code &e);
void udp_callback(const boost::system::error_code &e, size_t bytes_recvd);
boost::asio::io_service io;
private:
boost::asio::ip::udp::socket *socket;
boost::asio::ip::udp::endpoint *ep;
boost::asio::deadline_timer *timer;
char recv_buf[2048];
unsigned int tot_bytes_recved;
};
udp_timer.cpp
#include "udp_timer.hpp"
#include "boost/bind.hpp"
#include <iostream>
UdpTimer::UdpTimer() {
// Set up UDP part
ep = new boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30042);
socket = new boost::asio::ip::udp::socket(io, *ep);
socket->async_receive_from(
boost::asio::buffer(recv_buf, 2048), *ep,
boost::bind(&UdpTimer::udp_callback, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)
);
tot_bytes_recved = 0;
timer = new boost::asio::deadline_timer(io, boost::posix_time::seconds(1));
timer->async_wait(boost::bind(&UdpTimer::timer_callback, this, boost::asio::placeholders::error));
}
UdpTimer::~UdpTimer() {
delete ep;
delete socket;
delete timer;
}
void UdpTimer::run() {
io.run(); // Never returns
}
// Timer callback. Print info and reset timer
void UdpTimer::timer_callback(const boost::system::error_code &e) {
if (e) return;
static int count = 0;
std::cout <<"Timer Callback #" <<count++ <<"Bytes received = " <<tot_bytes_recved <<std::endl;
std::cout <<recv_buf <<std::endl;
timer->expires_from_now(boost::posix_time::seconds(1));
timer->async_wait(boost::bind(&UdpTimer::timer_callback, this, boost::asio::placeholders::error));
}
// Udp callback. Update bytes received count
void UdpTimer::udp_callback(const boost::system::error_code &e, size_t bytes_recvd) {
if (e) return;
tot_bytes_recved += bytes_recvd;
socket->async_receive_from(
boost::asio::buffer(recv_buf, 2048), *ep,
boost::bind(&UdpTimer::udp_callback, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)
);
}
int main(void) {
UdpTimer udp_timer;
udp_timer.run();
}
This placed inside the program is enough to generate that error.
=================================================================
==20441==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe4a7621d0 at pc 0x55d73239950c bp 0x7ffe4a761f50 sp 0x7ffe4a761f40
WRITE of size 16 at 0x7ffe4a7621d0 thread T0
#0 0x55d73239950b in boost::date_time::base_time<boost::posix_time::ptime, boost::date_time::split_timedate_system<boost::posix_time::posix_time_system_config> >::base_time(boost::gregorian::date const&, boost::posix_time::time_duration const&, boost::date_time::dst_flags) (/home/erl/dev/test/build/prog_ins+0x61950b)
#1 0x55d732396495 in boost::posix_time::ptime::ptime(boost::gregorian::date, boost::posix_time::time_duration) /usr/include/boost/date_time/posix_time/ptime.hpp:40
#2 0x55d7323d4855 in boost::date_time::microsec_clock<boost::posix_time::ptime>::create_time(tm* (*)(long const*, tm*)) /usr/include/boost/date_time/microsec_time_clock.hpp:116
#3 0x55d7323d12f6 in boost::date_time::microsec_clock<boost::posix_time::ptime>::universal_time() /usr/include/boost/date_time/microsec_time_clock.hpp:76
#4 0x55d7323cb501 in boost::asio::time_traits<boost::posix_time::ptime>::now() /usr/include/boost/asio/time_traits.hpp:48
#5 0x55d7323db197 in boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime> >::expires_from_now(boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime> >::implementation_type&, boost::posix_time::time_duration const&, boost::system::error_code&) (/home/erl/dev/test/build/prog_ins+0x65b197)
#6 0x55d7323d6a25 in boost::asio::deadline_timer_service<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime> >::expires_from_now(boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime> >::implementation_type&, boost::posix_time::time_duration const&, boost::system::error_code&) /usr/include/boost/asio/deadline_timer_service.hpp:129
#7 0x55d7323d2ca8 in boost::asio::basic_deadline_timer<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime>, boost::asio::deadline_timer_service<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime> > >::basic_deadline_timer(boost::asio::io_service&, boost::posix_time::time_duration const&) /usr/include/boost/asio/basic_deadline_timer.hpp:187
#8 0x55d7323b7f22 in InsHandler::InsHandler(InsConfig*, spdlog::logger*) /home/erl/dev/test/src/InsHandler.cpp:57
#9 0x55d7323a3fb0 in main /home/erl/dev/test/src/prog_ins.cpp:74
#10 0x7f369ed89bf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
#11 0x55d7322894d9 in _start (/home/erl/dev/test/build/prog_ins+0x5094d9)
Address 0x7ffe4a7621d0 is located in stack of thread T0 at offset 480 in frame
#0 0x55d7323d426f in boost::date_time::microsec_clock<boost::posix_time::ptime>::create_time(tm* (*)(long const*, tm*)) /usr/include/boost/date_time/microsec_time_clock.hpp:80
This frame has 10 object(s):
[32, 34) '<unknown>'
[96, 98) '<unknown>'
[160, 162) '<unknown>'
[224, 228) 'd'
[288, 296) 't'
[352, 360) 'td'
[416, 424) '<unknown>'
[480, 488) '<unknown>' <== Memory access at offset 480 partially overflows this variable
[544, 560) 'tv'
[608, 664) 'curr'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/home/erl/dev/test/build/prog_ins+0x61950b) in boost::date_time::base_time<boost::posix_time::ptime, boost::date_time::split_timedate_system<boost::posix_time::posix_time_system_config> >::base_time(boost::gregorian::date const&, boost::posix_time::time_duration const&, boost::date_time::dst_flags)
Shadow bytes around the buggy address:
0x1000494e43e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000494e43f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
0x1000494e4400: f1 f1 f8 f2 f2 f2 f2 f2 f2 f2 f8 f2 f2 f2 f2 f2
0x1000494e4410: f2 f2 f8 f2 f2 f2 f2 f2 f2 f2 04 f2 f2 f2 f2 f2
0x1000494e4420: f2 f2 00 f2 f2 f2 f2 f2 f2 f2 00 f2 f2 f2 f2 f2
=>0x1000494e4430: f2 f2 00 f2 f2 f2 f2 f2 f2 f2[00]f2 f2 f2 f2 f2
0x1000494e4440: f2 f2 00 00 f2 f2 f2 f2 f2 f2 00 00 00 00 00 00
0x1000494e4450: 00 f2 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000494e4460: 00 00 00 00 f1 f1 f1 f1 00 f2 f2 f2 f2 f2 f2 f2
0x1000494e4470: 00 f2 f2 f2 00 00 00 00 00 00 00 00 00 00 00 00
0x1000494e4480: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00 f2 f2
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==20441==ABORTING
From this error printout it seems as if there is a bug in the Boost library that writes 16 bytes to something that only 8 bytes were allocated to. But why should that surface so intermittently? Also I notice that we have a few words that are marked as stack-use-after-scope which is f8. Could that mean that we have another part of the program is using a pointer to a stack-allocated object after its out of scope?
Running with valgrind gives me this
==27251== Conditional jump or move depends on uninitialised value(s)
==27251== at 0x578FA1: boost::date_time::int_adapter<long>::is_infinity() const (int_adapter.hpp:114)
==27251== by 0x5772A9: boost::date_time::int_adapter<long>::is_special() const (int_adapter.hpp:131)
==27251== by 0x5A1069: boost::date_time::counted_time_rep<boost::posix_time::millisec_posix_time_system_config>::is_special() const (time_system_counted.hpp:108)
==27251== by 0x59FCD3: boost::date_time::counted_time_system<boost::date_time::counted_time_rep<boost::posix_time::millisec_posix_time_system_config> >::add_time_duration(boost::date_time::counted_time_rep<boost::posix_time::millisec_posix_time_system_config> const&, boost::posix_time::time_duration) (time_system_counted.hpp:226)
==27251== by 0x59EA90: boost::date_time::base_time<boost::posix_time::ptime, boost::date_time::counted_time_system<boost::date_time::counted_time_rep<boost::posix_time::millisec_posix_time_system_config> > >::operator+(boost::posix_time::time_duration const&) const (time.hpp:163)
==27251== by 0x59E46B: boost::asio::time_traits<boost::posix_time::ptime>::add(boost::posix_time::ptime const&, boost::posix_time::time_duration const&) (time_traits.hpp:57)
==27251== by 0x5A1BEC: boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime> >::expires_from_now(boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime> >::implementation_type&, boost::posix_time::time_duration const&, boost::system::error_code&) (deadline_timer_service.hpp:161)
==27251== by 0x5A0811: boost::asio::deadline_timer_service<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime> >::expires_from_now(boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime> >::implementation_type&, boost::posix_time::time_duration const&, boost::system::error_code&) (deadline_timer_service.hpp:129)
==27251== by 0x59F20B: boost::asio::basic_deadline_timer<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime>, boost::asio::deadline_timer_service<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime> > >::basic_deadline_timer(boost::asio::io_service&, boost::posix_time::time_duration const&) (basic_deadline_timer.hpp:187)
==27251== by 0x59DA57: OutputTimer::OutputTimer(boost::asio::io_service*, unsigned int, boost::function<OutputStates ()>) (output_timer.cpp:5)
==27251== by 0x5877D5: InsHandler::InsHandler(InsConfig*, spdlog::logger*) (InsHandler.cpp:57)
==27251== by 0x57B149: main (senti_ins.cpp:74)
==27251== Uninitialised value was created by a stack allocation
==27251== at 0x59FB3C: boost::date_time::microsec_clock<boost::posix_time::ptime>::create_time(tm* (*)(long const*, tm*)) (microsec_time_clock.hpp:80)
I am really lost here. There is really no connection between the changes I make to the source code and the resulting behaviour. I am able to remove the error by removing an inclusion of a totally unrelated header file. But the error surfaces again when including a mock_header with some function definitions and enums. So it really seems to be random when this error surfaces.
I would be extremely happy for any advice on how to attack such a problem.
I am very grateful for any advice on this
UDPATE to the edited question
I see loads of dynamic allocation (Why should C++ programmers minimize use of 'new'?).
I see repeated magic constants (1s, 2048), failure to NUL-terminate the recv_buf and then treating it as a C string, swallowing errors.
Removing all these:
Live On Coliru
Live On Wandbox
udp_timer.h
//#define BOOST_BIND_NO_PLACEHOLDERS
#include <boost/asio.hpp>
using boost::asio::ip::udp;
using namespace std::chrono_literals;
class UdpTimer {
public:
UdpTimer();
void run();
private:
using error_code = boost::system::error_code;
void timer_callback(error_code e);
void udp_callback(error_code e, size_t bytes_recvd);
void do_recv();
void do_timer();
boost::asio::io_service io;
udp::endpoint ep { {}, 30042 };
udp::socket socket { io, ep };
boost::asio::steady_timer timer { io };
std::array<char, 2048> recv_buf{};
unsigned int tot_bytes_recved = 0;
};
udp_timer.cpp
#include "udp_timer.hpp"
using namespace boost::asio::placeholders;
#include <boost/bind/bind.hpp>
#include <iostream>
#include <iomanip>
UdpTimer::UdpTimer() {
do_recv();
do_timer();
}
void UdpTimer::do_recv() {
socket.async_receive_from(boost::asio::buffer(recv_buf), ep,
boost::bind(&UdpTimer::udp_callback, this, error, bytes_transferred));
}
void UdpTimer::do_timer() {
timer.expires_from_now(1s);
timer.async_wait(boost::bind(&UdpTimer::timer_callback, this, error));
}
void UdpTimer::run() {
io.run(); // Never returns
}
// Timer callback. Print info and reset timer
void UdpTimer::timer_callback(error_code e)
{
if (e) {
std::cout << "timer_callback: " << e.message() << std::endl;
return;
}
static int count = 0;
std::cout << "Timer Callback #" << count++
<< " Bytes received = " << tot_bytes_recved << std::endl
<< " Last received: " << std::quoted(recv_buf.data()) << std::endl;
do_timer();
}
// Udp callback. Update bytes received count
void UdpTimer::udp_callback(error_code e, size_t bytes_recvd) {
if (e) {
std::cout << "timer_callback: " << e.message() << std::endl;
recv_buf[0] = '\0';
return;
}
// because you want to print the buffer, you will also want to make sure it
// is actually NUL terminated
assert(bytes_recvd < recv_buf.size());
recv_buf[bytes_recvd] = '\0';
tot_bytes_recved += bytes_recvd;
do_recv();
}
main.cpp
int main()
{
UdpTimer udp_timer;
udp_timer.run();
}
Running Demo, with ASAN+UBSAN enabled
OLD ANSWER:
boost::asio::io_service io2;
boost::asio::deadline_timer* t = new boost::asio::deadline_timer(io2, boost::posix_time::seconds(1));
This is merely a memory leak, but in the absence of other code it cannot possibly lead to any symptom, simply because no more code is generated: Live On Compiler Explorer
Now all the other observations make you suspicious. And rightfully so!
I am not able to reproduce the bug in just a standalone source file.
This is the key. There is Undefined Behaviour in your code. It may or may not have something to do with the timer, but it certainly isn't caused by this instantiation.
One obvious problem with the code is the memory leak, and the fact that you're doing manual allocation in the first place. This opens up the door for lifetime issues.
E.g. it is conceivable that
you have these lines in a function, the io2 goes out of scope and the time holds a stale reference to it.
In fact this directly corresponds to the "stack-use-after-scope" detection
many other scenarios assuming that you also t->async_wait() somehwere
Side observations are that io2 implies that you use two io services (why?). Besides all of this I hope you use better names in your real code, because it's really easy to get lost in a sea of io2, i, m3, t etc :)

Boost ASIO segfault in release mode

I have made this small illustrative code that exhibits the same issues the program I'm writing does: namely, it works fine in debug mode, segfaults in release. The problem seems to be that the ui_context, in release mode, when being called to run the work it has assigned, is nullptr.
Running in Fedora 33, with g++ (GCC) 10.2.1 20201125 (Red Hat 10.2.1-9) and clang version 11.0.0 (Fedora 11.0.0-2.fc33) . Both compilers behave in the same way. Boost version is 1.75 .
Code:
#include <iostream>
#include <vector>
#include <memory>
#include <chrono>
#include <thread>
#include <boost/asio.hpp>
#include <boost/signals2.hpp>
constexpr auto MAX_LOOP_COUNT = 100;
class network_client : public std::enable_shared_from_this<network_client>
{
private:
using Signal = boost::signals2::signal<void(int)>;
public:
network_client(boost::asio::io_context &context) :
strand(boost::asio::make_strand(context))
{
std::cout << "network client created" << std::endl;
}
void doNetworkWork()
{
std::cout << "doing network work" << std::endl;
boost::asio::post(strand,std::bind(&network_client::onWorkComplete,shared_from_this()));
}
void onWorkComplete()
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::cout << "signalling completion" << " from thread id:" << std::this_thread::get_id() << std::endl;
signal(42);
}
void workCompleteHandler(const typename Signal::slot_type &slot)
{
signal.connect(slot);
}
private :
boost::asio::strand<boost::asio::io_context::executor_type> strand;
Signal signal;
};
class network_client_producer
{
public :
network_client_producer() : work(boost::asio::make_work_guard(context))
{
using run_function = boost::asio::io_context::count_type (boost::asio::io_context::*)();
for (int i = 0; i < 2; i++)
{
context_threads.emplace_back(std::bind(static_cast<run_function>(&boost::asio::io_context::run), std::ref(context)));
}
}
~network_client_producer()
{
context.stop();
for(auto&& thread : context_threads)
{
if(thread.joinable())
{
thread.join();
}
}
}
using NetworkClientPtr = std::shared_ptr<network_client>;
NetworkClientPtr makeNetworkClient()
{
return std::make_shared<network_client>(context);
}
private :
boost::asio::io_context context;
std::vector<std::thread> context_threads;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work;
};
class desktop : public std::enable_shared_from_this<desktop>
{
public:
desktop(const boost::asio::io_context::executor_type &executor):executor(executor)
{
}
void doSomeNetworkWork()
{
auto client = client_producer.makeNetworkClient();
client->workCompleteHandler([self = shared_from_this()](int i){
//post work into the UI thread
std::cout << "calling into the uiThreadWork with index " << i << " from thread id:" << std::this_thread::get_id() << std::endl;
boost::asio::post(self->executor, std::bind(&desktop::uiThreadWorkComplete, self, i));
});
client->doNetworkWork();
}
void showDesktop()
{
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
public:
void uiThreadWorkComplete(int i)
{
std::cout << "Called in the UI thread with index:" << i << ", on thread id:" << std::this_thread::get_id() << std::endl;
}
private:
const boost::asio::io_context::executor_type& executor;
network_client_producer client_producer;
};
int main()
{
std::cout << "Starting application. Main thread id:"<<std::this_thread::get_id() << std::endl;
int count = 0;
boost::asio::io_context ui_context;
auto work = boost::asio::make_work_guard(ui_context);
/*auto work = boost::asio::require(ui_context.get_executor(),
boost::asio::execution::outstanding_work.tracked);*/
auto ui_desktop = std::make_shared<desktop>(ui_context.get_executor());
ui_desktop->doSomeNetworkWork();
while(true)
{
ui_context.poll_one();
ui_desktop->showDesktop();
if (count >= MAX_LOOP_COUNT)
break;
count++;
}
ui_context.stop();
std::cout << "Stopping application" << std::endl;
return 0;
}
Compiling it with g++ -std=c++17 -g -o main -pthread -O3 main.cpp and
running it in gdb I get this:
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Starting application. Main thread id:140737348183872
[New Thread 0x7ffff7a51640 (LWP 27082)]
[New Thread 0x7ffff7250640 (LWP 27083)]
network client created
doing network work
signalling completion from thread id:140737348179520
calling into the uiThreadWork with index 42 from thread id:140737348179520
Thread 2 "main" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff7a51640 (LWP 27082)]
0x000000000040b7b8 in boost::asio::io_context::basic_executor_type<std::allocator<void>, 0u>::execute<std::_Bind<void (desktop::*(std::shared_ptr<desktop>, int))(int)> >(std::_Bind<void (desktop::*(std::shared_ptr<desktop>, int))(int)>&&) const (this=<optimized out>, f=...) at /usr/local/include/boost/asio/impl/io_context.hpp:309
309 io_context_->impl_.post_immediate_completion(p.p,
While compiling without any optimizations g++ -std=c++17 -g -o main -pthread -O0 main.cpp works as expected.
I tried to keep it as close as I can to the real program that actually does network IO, which is why I have that strand in there.
It's obvious that I'm doing something horribly wrong here. The question is: what is the problem?
Thank you for any pointers.
Add the sanitizers -fsanitize=undefined,address:
Starting application. Main thread id:139902898299968
network client created
doing network work
signalling completion from thread id:139902399940352
calling into the uiThreadWork with index 42 from thread id:139902399940352
=================================================================
==29084==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffc8393d7c0 at pc 0x000000507ce0 bp 0x7f3d90d9e3d0 sp 0x7f3d90d9e3c8
READ of size 8 at 0x7ffc8393d7c0 thread T1
#0 0x507cdf in boost::asio::io_context::basic_executor_type<std::allocator<void>, ...
#1 0x507cdf in boost::asio::detail::initiate_post_with_executor<boost::asio::io_co...
#2 0x507cdf in auto boost::asio::post<boost::asio::io_context::basic_executor_type...
#3 0x5077cf in desktop::doSomeNetworkWork()::'lambda'(int)::operator()(int) const ...
#4 0x518ce2 in boost::function1<void, int>::operator()(int) const /home/sehe/custo...
#5 0x518481 in boost::signals2::detail::void_type boost::signals2::detail::call_wi...
#6 0x518481 in boost::signals2::detail::void_type boost::signals2::detail::variadi...
#7 0x517f43 in boost::signals2::detail::slot_call_iterator_t<boost::signals2::deta...
#8 0x516397 in void boost::signals2::optional_last_value<void>::operator()<boost::...
#9 0x516397 in void boost::signals2::detail::combiner_invoker<void>::operator()<bo...
#10 0x516397 in boost::signals2::detail::signal_impl<void (int), boost::signals2::...
#11 0x50d9d4 in network_client::onWorkComplete() /home/sehe/Projects/stackoverflow...
#12 0x51021d in void std::_Bind<void (network_client::* (std::shared_ptr<network_c...
#13 0x51021d in void boost::asio::asio_handler_invoke<std::_Bind<void (network_cli...
#14 0x51021d in void boost_asio_handler_invoke_helpers::invoke<std::_Bind<void (ne...
#15 0x51021d in boost::asio::detail::executor_op<std::_Bind<void (network_client::...
#16 0x51188e in boost::asio::detail::strand_executor_service::invoker<boost::asio:...
#17 0x514311 in void boost::asio::asio_handler_invoke<boost::asio::detail::strand_...
#18 0x514311 in void boost_asio_handler_invoke_helpers::invoke<boost::asio::detail...
#19 0x514311 in boost::asio::detail::executor_op<boost::asio::detail::strand_execu...
#20 0x4d8704 in boost::asio::detail::scheduler::do_run_one(boost::asio::detail::co...
#21 0x4d70dc in boost::asio::detail::scheduler::run(boost::system::error_code&) /h...
#22 0x523a6e in boost::asio::io_context::run() /home/sehe/custom/boost_1_75_0/boos...
#23 0x5258ef in unsigned long std::_Bind<unsigned long (boost::asio::io_context::*...
#24 0x5258ef in unsigned long std::__invoke_impl<unsigned long, std::_Bind<unsigne...
#25 0x5258ef in std::__invoke_result<std::_Bind<unsigned long (boost::asio::io_con...
#26 0x5258ef in unsigned long std::thread::_Invoker<std::tuple<std::_Bind<unsigned...
#27 0x7f3da660bd7f (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd0d7f)
#28 0x7f3da5f856da in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x76da)
#29 0x7f3da5a9671e in clone /build/glibc-S7xCS9/glibc-2.27/misc/../sysdeps/unix/sy...
Address 0x7ffc8393d7c0 is located in stack of thread T0 at offset 224 in frame
#0 0x4cb30f in main /home/sehe/Projects/stackoverflow/test.cpp:109
This frame has 6 object(s):
[32, 40) 'ref.tmp.i85' (line 96)
[64, 80) 'ref.tmp.i'
[96, 112) 'ui_context' (line 113)
[128, 152) 'work' (line 114)
[192, 208) 'ui_desktop' (line 117)
[224, 240) 'ref.tmp' (line 117) <== Memory access at offset 224 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope /home/sehe/custom/boost_1_75_0/boost/asio/io_context.hpp:678:25 in boost::asio::io_context::basic_executor_type<std::allocator<void>, 0u>::basic_executor_type(boost::asio::io_context::basic_executor_type<std::allocator<void>, 0u> const&)
Shadow bytes around the buggy address:
0x10001071faa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001071fab0: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 f8 f2 f2 f2
0x10001071fac0: f8 f2 f2 f2 00 f2 f2 f2 00 00 f3 f3 00 00 00 00
0x10001071fad0: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
0x10001071fae0: 00 f2 f2 f2 f8 f8 f2 f2 00 00 f2 f2 00 00 00 f2
=>0x10001071faf0: f2 f2 f2 f2 00 00 f2 f2[f8]f8 f3 f3 00 00 00 00
0x10001071fb00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001071fb10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001071fb20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001071fb30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001071fb40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
Thread T1 created by T0 here:
#0 0x483a6a in pthread_create (/home/sehe/Projects/stackoverflow/sotest+0x483a6a)
#1 0x7f3da660c014 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std...
#2 0x5241d4 in void std::vector<std::thread, std::allocator<std::thread> >::_M_realloc_ins...
#3 0x523517 in std::thread& std::vector<std::thread, std::allocator<std::thread> >::emplac...
==29084==ABORTING
There's your culprit.
Searching The Culprit
This frame has 6 object(s):
[32, 40) 'ref.tmp.i85' (line 96)
[64, 80) 'ref.tmp.i'
[96, 112) 'ui_context' (line 113)
[128, 152) 'work' (line 114)
[192, 208) 'ui_desktop' (line 117)
[224, 240) 'ref.tmp' (line 117) <== Memory access at offset 224 is inside this variable
What variable is that? Apparently in the line
auto ui_desktop = std::make_shared<desktop>(ui_context.get_executor());
there's a temporary that is being kept a reference to. It must be ui_context.get_executor() because ui_desktop is named and has "obvious" lifetime.
Sure enough, desktop declares its executor member by reference:
const boost::asio::io_context::executor_type& executor;
This is a clear error. Executors are not services nor execution contexts, and are designed to be cheaply copyable and passed by value. The fix is trivial:
boost::asio::io_context::executor_type executor;
BONUS
As a bonus, here's a simplified version that runs the demo for half a second. Notes:
using a thread_pool instead of hand-rolling a flawed one
consider not using .stop() on execution contexts, or forgetting about the redundant word guards?
Live On Compiler Explorer
#include <iostream>
#include <chrono>
#include <iomanip>
#include <memory>
#include <thread>
#include <boost/asio.hpp>
#include <boost/signals2.hpp>
namespace {
using namespace std::chrono_literals;
auto now = std::chrono::high_resolution_clock::now;
auto elapsed = [start=now()] { return (now()-start)/1ms; };
inline std::string thread_hash() {
static constexpr std::hash<std::thread::id> h{};
std::ostringstream oss;
oss << std::hex << std::setw(2) << std::setfill('0')
<< h(std::this_thread::get_id()) % 0xff;
return oss.str();
}
auto trace = [](auto const&... args) {
std::cout << "thread #" << thread_hash() << " at t+" << std::setw(3) << elapsed() << "ms\t";
(std::cout << ... << args) << std::endl;
};
} // namespace
struct network_client : std::enable_shared_from_this<network_client> {
explicit network_client(const boost::asio::any_io_executor& context) : strand(make_strand(context)) {
trace("network client created");
}
void doNetworkWork() {
trace("doing network work");
post(strand, std::bind(&network_client::onWorkComplete, shared_from_this()));
}
void onWorkComplete() {
std::this_thread::sleep_for(10ms);
trace("signalling completion");
signal(42);
}
template <typename F> void workCompleteHandler(F slot) {
signal.connect(std::move(slot));
}
private:
boost::asio::strand<boost::asio::any_io_executor> strand;
using Signal = boost::signals2::signal<void(int)>;
Signal signal;
};
struct network_client_producer {
auto makeNetworkClient() {
return std::make_shared<network_client>(context_threads.get_executor());
}
private :
boost::asio::thread_pool context_threads {2};
};
struct desktop : std::enable_shared_from_this<desktop> {
explicit desktop(boost::asio::io_context::executor_type executor) : executor(std::move(executor)) {}
void doSomeNetworkWork() {
auto client = client_producer.makeNetworkClient();
client->workCompleteHandler([this, self = shared_from_this()](int i) {
// post work into the UI thread
trace("calling into the uiThreadWork with index ", i);
post(executor, std::bind(&desktop::uiThreadWorkComplete, self, i));
});
client->doNetworkWork();
}
static void showDesktop() {
trace("showDesktop");
std::this_thread::sleep_for(20ms);
}
void uiThreadWorkComplete(int i) const {
trace("Called in the UI thread with index:", i);
}
private:
boost::asio::io_context::executor_type executor;
network_client_producer client_producer;
};
int main() {
trace("Starting application. Main thread is #", thread_hash());
boost::asio::io_context ui_context;
auto work = boost::asio::make_work_guard(ui_context);
/*auto work = boost::asio::require(ui_context.get_executor(),
boost::asio::execution::outstanding_work.tracked);*/
auto ui_desktop = std::make_shared<desktop>(ui_context.get_executor());
ui_desktop->doSomeNetworkWork();
for (auto deadline = now() + 0.5s; now() < deadline;) {
ui_context.poll_one();
ui_desktop->showDesktop();
}
trace("Stopping application");
work.reset();
ui_context.run();
// ui_context.stop();
trace("Bye\n");
}
Prints
thread #97 at t+ 0ms Starting application. Main thread is #97
thread #97 at t+ 0ms network client created
thread #97 at t+ 1ms doing network work
thread #97 at t+ 1ms showDesktop
thread #2d at t+ 11ms signalling completion
thread #2d at t+ 11ms calling into the uiThreadWork with index 42
thread #97 at t+ 21ms Called in the UI thread with index:42
thread #97 at t+ 21ms showDesktop
thread #97 at t+ 41ms showDesktop
thread #97 at t+ 61ms showDesktop
thread #97 at t+ 81ms showDesktop
thread #97 at t+101ms showDesktop
thread #97 at t+122ms showDesktop
thread #97 at t+142ms showDesktop
thread #97 at t+162ms showDesktop
thread #97 at t+182ms showDesktop
thread #97 at t+202ms showDesktop
thread #97 at t+222ms showDesktop
thread #97 at t+242ms showDesktop
thread #97 at t+262ms showDesktop
thread #97 at t+282ms showDesktop
thread #97 at t+302ms showDesktop
thread #97 at t+323ms showDesktop
thread #97 at t+343ms showDesktop
thread #97 at t+363ms showDesktop
thread #97 at t+383ms showDesktop
thread #97 at t+403ms showDesktop
thread #97 at t+423ms showDesktop
thread #97 at t+443ms showDesktop
thread #97 at t+463ms showDesktop
thread #97 at t+483ms showDesktop
thread #97 at t+503ms Stopping application
thread #97 at t+504ms Bye
The problem is that your executor is a reference to a temporary object. In your main method, you call ui_context.get_executor(), which returns a temporary object. You pass the temporary to the desktop constructor, which stores a reference to this object in the member variable executor. After the auto ui_desktop = ... line in main has completed, the temporary goes out-of-scope and the reference held by executor becomes invalid.
This problem is also detected when compiling your program with address sanitization enabled (-fsanitize=address):
==24629==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffe8bee0270 at pc 0x5584b2d89b0c bp 0x7f3ac42fd970 sp 0x7f3ac42fd960
READ of size 8 at 0x7ffe8bee0270 thread T1
#0 0x5584b2d89b0b in boost::asio::io_context::basic_executor_type<std::allocator<void>, 0u>::basic_executor_type(boost::asio::io_context::basic_executor_type<std::allocator<void>, 0u> const&) /usr/include/boost/asio/io_context.hpp:678
...
I would suspect that in your debug build, the temporary object gets to live slightly longer, i.e. the stack memory that was occupied by the temporary object is not reclaimed immediately after the temporary goes out-of-scope. Whereas in the release build, more aggressive optimizations are applied, which results in the memory being reclaimed sooner, thereby invalidating the reference sooner, and then crashing your program once the reference is accessed.
To fix this, you have to ensure that the executor returned by get_executor does not go out-of-scope, so that the reference held by the ui_desktop object remains valid. For example, you could assign the result of get_executor to a variable in your main:
auto executor{ui_context.get_executor()};
auto ui_desktop = std::make_shared<desktop>(executor);

FATAL Signal 11 while accessing SQLiteDatabase getReadableDatabase method - NDK

I am working on 32 to 64bit migration part.
Now Application is working in few devices like One Plus 5(8xx processor) or One plus 7 pro (8xx processor) but the application crashing in Redmi, Realme, Samsung M40 which are 6xx processor
I am getting below stack trace
#01 0x0000000000398b10 /system/lib64/libart.so (art::MemMap::MapInternal(void*, unsigned long, int, int, int, long, bool)+88)
#02 0x00000000003987ac /system/lib64/libart.so (art::MemMap::MapAnonymous(char const*, unsigned char*, unsigned long, int, bool, bool, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*, bool)+484)
#03 0x0000000000263520 /system/lib64/libart.so (art::IndirectReferenceTable::IndirectReferenceTable(unsigned long, art::IndirectRefKind, art::IndirectReferenceTable::ResizableCapacity, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*)+140)
#04 0x0000000000319d50 /system/lib64/libart.so (art::JNIEnvExt::JNIEnvExt(art::Thread*, art::JavaVMExt*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*)+52)
#05 0x0000000000319c74 /system/lib64/libart.so (art::JNIEnvExt::Create(art::Thread*, art::JavaVMExt*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*)+52)
#06 0x000000000049b170 /system/lib64/libart.so (art::Thread::CreateNativeThread(_JNIEnv*, _jobject*, unsigned long, bool)+440)
#07 0x00000000003e3cbc /system/lib64/libart.so (art::Thread_nativeCreate(_JNIEnv*, _jclass*, _jobject*, long, unsigned char)+156)
#08 0x0000000071cd4a7c /data/dalvik-cache/arm64/system#framework#boot.oat (offset 0xa1a000)
#00 0x0000000002ecc990 /dev/ashmem/dalvik-non moving space (deleted) (offset 0x7000)
#01 0x00000000000212e8 /system/lib64/libopenjdk.so (Java_java_io_UnixFileSystem_checkAccess0+128)
#02 0x0000000071d26e10 /data/dalvik-cache/arm64/system#framework#boot.oat (offset 0xa1a000)
Fatal signal 11 (SIGSEGV), code 2, fault addr 0x7697e760 in tid 31901 (firebase-iid-ex), pid 31879 (docs.android)

Boost.Asio: Segmentation fault when sending too big message

My program saves some internal logs to a .txt file.
If you connect to it via TCP (SSL encrypted), the program will send the contents of the log file.
This is the code that is sending the data:
void NIUserSession::write(std::string message)
{
std::cout << "Writing message" << std::endl;
message.append("<EOF>");
boost::system::error_code ec;
boost::asio::async_write(this->socket_, boost::asio::buffer(message),
boost::asio::transfer_all(), boost::bind(&NIUserSession::writeHandler,
this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred()));
}
void NIUserSession::writeHandler(const boost::system::error_code &error, std::size_t bytes_transferred)
{
std::cout << "Write Handler" << std::endl;
if(error)
{
std::cout << "Write handler error: " << error.message() << std::endl;
this->disconnect();
}
}
So NIUserSession::write gets passed the logfile contents as string.
If the program is not running for a very long time the logfile is short and everything works fine. However, if it runs for a while and the log file gets longer and longer, the program will receive a SIGSEGV when it tries to send the data. This is the gdb log:
Writing message
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff4fe1700 (LWP 21047)]
__memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:33
33 ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S: No such file or directory.
(gdb) where
#0 __memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:33
#1 0x00007ffff7998454 in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.0.0
#2 0x00007ffff79985c3 in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.0.0
#3 0x00000000004b7eca 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::mf2<void, NIUserSession, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<NIUserSession*>, boost::arg<1> (*)(), boost::arg<2> > > > >::operator()(boost::system::error_code, unsigned long, int) ()
#4 0x00000000004b8bf8 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::mf2<void, NIUserSession, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<NIUserSession*>, boost::arg<1> (*)(), boost::arg<2> > > >::operator()(boost::system::error_code const&, unsigned long, int) ()
#5 0x00000000004b7e6c 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::mf2<void, NIUserSession, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<NIUserSession*>, boost::arg<1> (*)(), boost::arg<2> > > > >::operator()(boost::system::error_code, unsigned long, int) ()
#6 0x00000000004b965c in boost::asio::detail::reactive_socket_send_op<boost::asio::mutable_buffers_1, boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, 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::mf2<void, NIUserSession, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<NIUserSession*>, boost::arg<1> (*)(), boost::arg<2> > > > > > >::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) ()
#7 0x00000000004add59 in boost::asio::detail::epoll_reactor::descriptor_state::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) ()
#8 0x00000000004ad911 in boost::asio::detail::task_io_service::run(boost::system::error_code&) ()
#9 0x00000000004a9c1f in NetInterface::init() ()
#10 0x00007ffff641aa60 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#11 0x00007ffff566e184 in start_thread (arg=0x7ffff4fe1700) at pthread_create.c:312
#12 0x00007ffff5b8237d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
I don't understand why it is happening. Do I maybe have to give a size to boost::asio::buffer?
Also, io_service::run() is running in its own detached thread. Could this be a problem?
This is the common issue with asio usage. You are sending buffer using boost::asio::buffer(message), which does not copy the data. It just creating a reference for the data and you are responsible for this object (your message) lifetime until operation ends. But when you exit function NIUserSession::write all stack variables are destroyed, including your message.
To fix this you should place your data into a object with longer lifetime, for example into shared_ptr. Valid example can be something like this:
void NIUserSession::write(std::string &message_orig)
{
std::cout << "Writing message" << std::endl;
std::shared_ptr message = std::make_shared<std::string>( message_orig );
message->append("<EOF>");
boost::system::error_code ec;
boost::asio::async_write(this->socket_, boost::asio::buffer(*message),
boost::asio::transfer_all(), boost::bind(&NIUserSession::writeHandler,
this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred(),
message /* <- capture it into callback to guarantee lifetime */
));
}