Странная ошибка сегментации в сборке Linux C++ Boost Asio ServerC++

Программы на C++. Форум разработчиков
Ответить Пред. темаСлед. тема
Anonymous
 Странная ошибка сегментации в сборке Linux C++ Boost Asio Server

Сообщение Anonymous »

Ошибка сегментации в Boost Asio Server в Linux во время вызова Flat_buffer::prepare()
Описание проблемы:
У меня C++ 20, использующее Boost.Asio 1.85, которое отлично работает в Windows, но аварийно завершает работу в Ubuntu Linux из-за ошибки сегментации. Сбой происходит при обработке HTTP-запроса, особенно внутри функции Flat_buffer::prepare() Boost.Beast. Я подозреваю, что это как-то связано с распределением памяти или доступом, возможно, связано с оптимизацией привязки NUMA/CPU или обработкой потоков в Linux.

Код: Выделить всё

#include 
#include 
#include 
#include 
#include 
#include 
#include 
namespace asio  = boost::asio;
namespace beast = boost::beast;
namespace http  = beast::http;
using tcp       = asio::ip::tcp;
static constexpr uint16_t SERVERPORT = 7878;

class JsonEchoServer final : public std::enable_shared_from_this {
public:
explicit JsonEchoServer(asio::io_context& io_context, asio::ip::port_type port)
: io_context_(io_context)
, acceptor_(io_context, {tcp::v4(), port})
, thread_pool_(std::max(1u, std::thread::hardware_concurrency())) {
assert(acceptor_.is_open() && "Acceptor must be open.");
}

JsonEchoServer() = delete;

void run_server() {
co_spawn(io_context_, listener(), asio::detached);

std::size_t              num_threads = std::max(1, std::thread::hardware_concurrency());
std::vector threads;
threads.reserve(num_threads);

for (std::size_t i = 0; i < num_threads; ++i) {
threads.emplace_back([this]() {
optimize_for_platform();
io_context_.run();
});
}

for (auto& th : threads) {
if (th.joinable())
th.join();
}
}

private:
asio::io_context& io_context_;
tcp::acceptor     acceptor_;

class ThreadPool {
public:
explicit ThreadPool(std::size_t num_threads) : stop_(false) {
workers_.reserve(num_threads);
for (std::size_t i = 0; i < num_threads; ++i) {
workers_.emplace_back([this]() {
optimize_for_platform();
worker_thread();
});
}
}

~ThreadPool() {
stop_.store(true, std::memory_order_release);
condition_.notify_all();
for (auto& worker : workers_) {
if (worker.joinable())
worker.join();
}
}

void enqueue(std::function task) {
tasks_.enqueue(std::move(task));
condition_.notify_one();
}

private:
moodycamel::ConcurrentQueue tasks_;
std::vector                           workers_;
std::atomic                                  stop_;
std::condition_variable                            condition_;
std::mutex                                         mutex_;

void worker_thread() {
optimize_for_platform();
while (!stop_.load(std::memory_order_acquire)) {
std::function task;
if (tasks_.try_dequeue(task)) {
task();
} else {
std::unique_lock lock(mutex_);
condition_.wait_for(lock, std::chrono::milliseconds(1));
}
}
}

static void optimize_for_platform() {
#ifdef linux
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
int cpu = sched_getcpu();
assert(cpu >= 0 && "sched_getcpu() failed on Linux.");
CPU_SET(cpu, &cpuset);
int set_res = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
assert(set_res == 0 && "pthread_setaffinity_np() failed.");
int node = numa_node_of_cpu(cpu);
numa_run_on_node(node);
numa_set_preferred(node);
#endif
}
};

ThreadPool thread_pool_;

asio::awaitable handle_resultaten_endpoint(                     //
[[maybe_unused]] tcp::socket                              socket, //
[[maybe_unused]] http::request const& req) {
// ...  implementation ...
co_return;
}

asio::awaitable handle_bestand_other_generator_endpoint(        //
[[maybe_unused]] tcp::socket                              socket, //
[[maybe_unused]] http::request const& req) {
// ...  implementation ...
co_return;
}

asio::awaitable handle_request(tcp::socket socket) {
socket.set_option(tcp::no_delay(true));
beast::flat_buffer                       buffer;
http::request_parser req_parser;
req_parser.body_limit(std::numeric_limits::max());

co_await http::async_read(socket, buffer, req_parser, asio::deferred);
http::request req(std::move(req_parser.get()));

static constexpr std::string_view resultaten_sv    = "/resultaten";
static constexpr std::string_view bestand_other_sv = "/bestand_other";
std::string_view                  target_sv        = req.target();

if (target_sv.starts_with(bestand_other_sv)) {
co_await handle_bestand_other_generator_endpoint(std::move(socket), std::move(req));
} else if (target_sv.starts_with(resultaten_sv)) {
co_await handle_resultaten_endpoint(std::move(socket), std::move(req));
} else {
http::response res;
res.version(req.version());
res.result(http::status::not_found);
res.set(http::field::content_type, "application/json");
res.body() = R"({"Status":"Fataal","Omschrijving":"Endpoint niet gevonden"})";
res.prepare_payload();
co_await http::async_write(socket, res, asio::deferred);
boost::beast::error_code shutdown_ec;
socket.shutdown(tcp::socket::shutdown_send, shutdown_ec);
}
co_return;
}

template  auto offload_to_threadpool(Func&& func) -> asio::awaitable {
using result_type = decltype(func());
auto token        = asio::use_awaitable;
co_return co_await asio::async_initiate(
[this, f = std::forward(func)](auto handler) mutable {
using handler_type = std::decay_t;
auto handler_ptr   = std::make_shared(std::move(handler));
thread_pool_.enqueue([f = std::move(f), handler_ptr, this]() mutable {
try {
result_type result = f();
asio::post(io_context_, [handler_ptr, r = std::move(result)]() mutable {
(*handler_ptr)(boost::system::error_code(), std::move(r));
});
} catch (...) {
assert(false && "Caught unexpected exception in offload_to_threadpool.");
asio::post(io_context_, [handler_ptr]() {
(*handler_ptr)(asio::error::operation_aborted, result_type{});
});
}
});
},
token);
}

asio::awaitable listener() {
while (true) {
tcp::socket socket = co_await acceptor_.async_accept(asio::use_awaitable);
auto        self   = shared_from_this();
asio::co_spawn(
io_context_,
[this, self, s = std::move(socket)]() mutable { return handle_request(std::move(s)); },
asio::detached);
}
}

static void optimize_for_platform() {
#ifdef linux
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
int cpu = sched_getcpu();
assert(cpu >= 0 && "sched_getcpu() failed on Linux.");
CPU_SET(cpu, &cpuset);
int set_res = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
assert(set_res == 0 &&  "pthread_setaffinity_np() failed.");
int node = numa_node_of_cpu(cpu);
numa_run_on_node(node);
numa_set_preferred(node);
#endif
}
};

inline static void launch_server_process() {
asio::io_context io_context;
auto             server = std::make_shared(io_context, SERVERPORT);
server->run_server();
}

int main() {
launch_server_process();
return 0;
}
Сведения о проблеме:
Сервер работает нормально в Windows, но вызывает ошибку сегментации в Linux при поступлении запроса.
Сбой происходит в вызове Flat_buffer::prepare() Boost.Beast во время асинхронного чтения HTTP-запроса.
Это предполагает возможное повреждение памяти или неправильное использование Flat_buffer — возможно, из-за неправильное использование ниток или конфигурация для конкретной платформы в Linux.
Вопрос:
Что именно вызывает ошибку сегментации в Flat_buffer::prepare() в Linux, и как я могу решить эту проблему?
Я тщательно просмотрел код, исследуя его на предмет возможного повреждения памяти и проблем с безопасностью потоков, связанных с использованием Flat_buffer. Я проверил, что не было одновременных обращений без надлежащей синхронизации и что все объекты буфера управлялись правильно.
Я также исследовал оптимизацию для конкретной платформы, такую ​​как привязка ЦП и вызовы NUMA в оптимизации_for_platform( ), учитывая, что эти специфичные для Linux вызовы могут вызвать неожиданное поведение или сбои, если, например, необходимые библиотеки NUMA не были связаны или оборудование не поддерживало определенные функции.
Чтобы получить больше информации в ошибку сегментации, я использовал инструменты отладки, такие как GDB, Valgrind и AddressSanitizer. Я попытался получить подробную информацию с помощью этих инструментов, но, несмотря на все эти усилия, трассировки стека и сообщения об ошибках не указали мне прямо на основную причину сбоя внутри Flat_buffer::prepare(). Это вывод bt при запуске gdb: https://drive.google.com/file/d/1MjXw_n ... sp=sharing

Код: Выделить всё

Thread 23 "ServerExecutable" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fff83f6d6c0 (LWP 9305)]
0x000055555587ea05 in boost::beast::basic_flat_buffer >::prepare (this=0x7fff70001298, n=512) at ISA_Software/ServerExecutable/../Kernel/boost/beast/core/impl/flat_buffer.hpp:322
#1  0x000055555587ca1f in boost::beast::detail::dynamic_buffer_prepare, boost::beast::basic_flat_buffer, true>::operator(), boost::beast::basic_flat_buffer, true, detail::composed_op >(boost::asio::basic_stream_socket&, boost::beast::basic_flat_buffer, detail::composed_work, detail::awaitable_handler, void (error_code, unsigned long)>&&) (stream=..., buffer=..., parser=..., handler=...) at ISA_Software/ServerExecutable/../Kernel/boost/beast/http/impl/read.hpp:463
...
#16 0x0000555555863759 in detail::awaitable_frame_base::resume (this=0x7fff70001660) at ISA_Software/ServerExecutable/../Kernel/boost/asio/impl/awaitable.hpp:503
...
#39 0x00005555557b352a in boost::asio::co_spawn(boost::asio::io_context&, JsonEchoServer::listener()::{lambda()#1}&&, boost::asio::detached_t const&, boost::asio::constraint

Подробнее здесь: [url]https://stackoverflow.com/questions/79363261/weird-sigmentation-fault-on-linux-c-boost-asio-server-build[/url]
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Ошибка сегментации в сборке Linux C++ Boost Asio Server
    Anonymous » » в форуме C++
    0 Ответы
    10 Просмотры
    Последнее сообщение Anonymous
  • Boost :: Asio Asynchronous Daytime Server Пример с использованием C ++ 23
    Anonymous » » в форуме C++
    0 Ответы
    21 Просмотры
    Последнее сообщение Anonymous
  • Соединение не может быть завершено в Linux boost::asio::spawn
    Anonymous » » в форуме Linux
    0 Ответы
    43 Просмотры
    Последнее сообщение Anonymous
  • API API API API Server Server Server Call возвращает HTTP 500 на машине Server Windows, но работает правильно на клиентс
    Anonymous » » в форуме C#
    0 Ответы
    35 Просмотры
    Последнее сообщение Anonymous
  • API API API API Server Server Server Call возвращает HTTP 500 на машине Server Windows, но работает правильно на клиентс
    Anonymous » » в форуме C#
    0 Ответы
    27 Просмотры
    Последнее сообщение Anonymous

Вернуться в «C++»