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";
}
James
  • 9,064
  • 3
  • 31
  • 49
  • Have you seen this answer: http://stackoverflow.com/questions/35225234/linking-libboost-log-so-makes-boostasioio-servicerun-exit-immediately/35241050#35241050 ? – Andrey Semashev Oct 10 '16 at 08:57
  • @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? – James Oct 10 '16 at 09:40
  • 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. – Andrey Semashev Oct 10 '16 at 17:22

1 Answers1

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
)
James
  • 9,064
  • 3
  • 31
  • 49