Use of Boost.Log and Boost.ASIO causes a crash
Asked Answered
P

1

3

I am running into an issue where the use of Boost.Log in an app causes a crash or a hang when the app loads a shared library that uses Boost.ASIO! Any insights would be appreciated; a full cmake-buildable example is below.

If the declaration of the global logger object in main.cpp is uncommented the program will either seg-fault immediately or the resolve() call will do nothing. If left commented out then the program works.

I'm using Boost 1.55, g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4

CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
project (boosttest)
add_definitions(-fPIC -pthread -std=c++11)
find_package(Boost 1.55.0 REQUIRED)
add_definitions( -DBOOST_LOG_DYN_LINK )
include_directories(${Boost_INCLUDE_DIRS})

# Build the shared lib.
add_library(testlib SHARED
    Lib
)

target_link_libraries(testlib
    pthread
)

# Build the test app.
add_executable(testapp
    main
)

target_link_libraries(testapp
    dl
    pthread
    boost_system
    boost_log
)

Main.cpp

#include <iostream>
#include <memory>
#include <dlfcn.h>
#include <boost/log/core.hpp>
#include <boost/log/sources/channel_logger.hpp>

#include "Lib.h"

using LoggerType = boost::log::sources::channel_logger_mt<>;
//LoggerType gLogger; // If this is uncommented then probably a crash.


std::unique_ptr<Lib> LoadLib(const std::string& libName) {
    typedef Lib* (*LibConstructor)();

    union FunctionLookup {
        LibConstructor entry;
        void* voidPtr;
    };

    void* handle = ::dlopen(libName.c_str(), RTLD_LAZY);
    if (!handle) {
        throw std::runtime_error(::dlerror());
    }

    FunctionLookup lookup;

    lookup.voidPtr = ::dlsym(handle, "create");
    if (!lookup.voidPtr) {
        throw std::runtime_error(::dlerror());
    }

    return std::unique_ptr<Lib>(lookup.entry());
}


int main(int argc, char* argv[]) {
    try {
        std::unique_ptr<Lib> lib = LoadLib("./libtestlib.so");
        std::cout << "successfully loaded lib\n";
        lib->resolve("www.google.com");
    }
    catch (const std::exception& e) {
        std::cerr << "*** " << e.what() << "\n";
    }

   std::cout << "Exiting" << std::endl;
   return 0;
}

Lib.h

#pragma once
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

class Lib
{
public:
    Lib();
    virtual ~Lib() {}
    virtual void resolve(const std::string& host);

private:
    void onResolve(const boost::system::error_code&, tcp::resolver::iterator);

    boost::asio::io_service m_ioService;
    tcp::resolver m_resolver;
};

Lib.cpp

#include <functional>
#include "Lib.h"

extern "C" Lib* create() { return new Lib(); }
extern "C" void destroy(Lib* lib) { delete lib; }

Lib::Lib()
:  m_resolver(m_ioService)
{
}

void Lib::resolve(const std::string& host) {
    tcp::resolver::query query(host, "http");
    auto next = std::bind(&Lib::onResolve, this, std::placeholders::_1, std::placeholders::_2);
    m_resolver.async_resolve(query, std::move(next));
    m_ioService.run(); // If it doesn't crash then this does nothing.
}


void Lib::onResolve(const boost::system::error_code& /*err*/, tcp::resolver::iterator /*iter*/)
{
    std::cout << "onResolve() called!\n";
}
Prosthodontist answered 9/10, 2016 at 22:4 Comment(3)
Have you seen this answer: stackoverflow.com/questions/35225234/… ?Corked
@AndreySemashev I have just read it. As you can see from the code above both binaries are built from the same source tree so there's no versioning issues. The shared lib uses the header-only version of ASIO. Are you saying the issue is caused by two binaries using the same lib?Prosthodontist
The compatibility problem can appear not only because of different versions of a library (e.g. from different Boost releases) but also because of using different configurations of the same library. In the referenced answer I said that Boost.ASIO has incompatible switches and one has to make sure he uses identically configured Boost.ASIO in both Boost.Log and his code.Corked
P
0

So I managed to fix this (I think) by not dynamically linking the Boost.Log libs.

New CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
project (boosttest)
add_definitions(-fPIC -pthread -std=c++11)
find_package(Boost 1.55.0 REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})

# Build the shared lib.
add_library(testlib SHARED
    Lib
)

target_link_libraries(testlib
    pthread
)

# Build the test app.
add_executable(testapp
    main
)

target_link_libraries(testapp
    dl
    pthread
    boost_system
    boost_log.a
    boost_thread
)
Prosthodontist answered 10/10, 2016 at 12:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.