1

Yesterday I have started including spdlog into a personal project of mine to use for logging. So far I have had some problems with getting library inclusion to work but those are now solved completely.

Now everything compiles just fine, with all headers found however when I try to create loggers or simply set the pattern for logging the code crashes with a segmentation fault. More specifically no matter which function I call from the spdlog namespace for the very first time in the program causes the crash.

I have a class abstracting some parts from spdlog (based on this repo) as follows:

//Logger.hpp
#ifndef TE_LOGGER_HPP
#define TE_LOGGER_HPP

#include <spdlog/spdlog.h>

namespace te {

class Logger {
public:
    static void Init();

    inline static std::shared_ptr<spdlog::logger> &getCoreLogger() {
        return sCoreLogger;
    }
    inline static std::shared_ptr<spdlog::logger> &getClientLogger() {
        return sClientLogger;
    }

private:
    static std::shared_ptr<spdlog::logger> sCoreLogger;
    static std::shared_ptr<spdlog::logger> sClientLogger;
};

}
#endif //TE_LOGGER_HPP

//Logger.cpp
#include "Logger.hpp"
#include <spdlog/sinks/stdout_color_sinks.h>

std::shared_ptr<spdlog::logger> te::Logger::sCoreLogger;
std::shared_ptr<spdlog::logger> te::Logger::sClientLogger;

void te::Logger::Init() {
    //The first of any of the following three lines cause a crash
    //no matter the order, regardless of the pattern used in set_pattern
    spdlog::set_pattern("%v");
    sCoreLogger = spdlog::stdout_color_mt("CORE");
    sClientLogger = spdlog::stdout_color_mt("CORE");

    sCoreLogger->set_level(spdlog::level::trace);
    sClientLogger->set_level(spdlog::level::trace);
}

From the stack traces it seems that the issue is with the formatter class in spdlog being set null for some reason somewhere within the library. I am using the latest CLion, C++14 (I am aware that spdlog is C++11, but I need features from 14 later down the line, also setting -std=c++11 doesn't solve the issue) and the latest version of spdlog as of yesterday (pulled straight from their GitHub repo) on Ubuntu 18.04.

EDIT: As per the request in the comments I have created a small project (single cpp file, include spdlog the way I do in the real project, or the same code and library setup as in the real project referenced from the main.cpp file and linked to accordingly) that aims to reproduce the issue and here are my findings: * The issue is not present when I use spdlog directly in the executable * The issue is present if the Logger class is moved into a shared library and linked to from there

Here is the error message I am getting:

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

And the CMakeLists.txt files I am using (I nest the library's one into the project since as of now CLion does not support "multiple projects in the same solution" like for example VS does): #CMakeLists.txt for Library cmake_minimum_required(VERSION 3.10 FATAL_ERROR)

project(TokenEngine VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)

set(SOURCE_FILES src/Application.cpp src/Application.hpp src/EntryPoint.hpp src/Logger.cpp src/Logger.hpp)

#include_directories("${CMAKE_CURRENT_SOURCE_DIR}/libs/")
add_library(TokenEngine SHARED ${SOURCE_FILES})

target_include_directories(TokenEngine PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/libs/spdlog-1.x/include")

#Expose the public API of the engine to any project that might use it
target_include_directories(TokenEngine PUBLIC include)

#CMakeLists.txt for top level project
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")

add_definitions(-DTE_PLATFORM_LINUX)

project(Build CXX)

add_subdirectory(TokenEngine)
add_subdirectory(Sandbox)
Ofiris
  • 6,047
  • 6
  • 35
  • 58
TokenGuard
  • 29
  • 2
  • 5
  • Have you tried creating a minimal example? In this case it could be a new project, just one c++ file including spdlog, calling `spdlog::set_pattern` in the main function and thats it. Does that crash as well? – Yanick Salzmann Nov 14 '18 at 13:41
  • Could you provide the error message and if you are using your `CMakeLists.txt` file – FreshD Nov 14 '18 at 14:06

2 Answers2

1

You are using the same name for both loggers, when you run it you'll get:

$ ./logger
libc++abi.dylib: terminating with uncaught exception of type spdlog::spdlog_ex: logger with name 'CORE' already exists
Abort trap: 6

If you change the name of the client logger to something else it works fine:

sCoreLogger = spdlog::stdout_color_mt("CORE");
sClientLogger = spdlog::stdout_color_mt("CLIENT");
sergiopm
  • 194
  • 5
  • Hey, cheers for spotting that. Unfortunately it does not solve the issue as even the first call to `spdlog::stdout_color_mt()` segfaults – TokenGuard Nov 14 '18 at 15:35
1

The problem is probably that spdlog’s static objects are defined twice - from inside the shared library and from client code that includes your logger header (which incldes spdlog.h).

Try to remove the include to spdlog.h from the header file and (and use forward declaration of spdlog::logger instead), and include spdlog.h only from your Logger.cpp file.

Edit:

spdlog::logger cannot be forward declared across compilation unit boundries. The solution is to wrap the logger with some simple class defined in logger.cpp and only export it in logger.h

GabiMe
  • 18,105
  • 28
  • 76
  • 113
  • I have tried this approach however it now doesn't compile with an error saying that `spdlog::logger` is only forward declared and not defined anywhere, when quite clearly I define it in `Logger.cpp` by including `spdlog.h` It really does seem like this is the issue though as with the setup you mentioned if I include `spdlog.h` in the client code it still segfaults so +1 for that – TokenGuard Nov 15 '18 at 22:16
  • Just to clarify: it is me trying to log a message in the application that causes the project not to compile not the actual `Logger::Init()` method – TokenGuard Nov 15 '18 at 22:26
  • Right, I forgot that spdlog::logger is defined as inline, meaning its definitaion doesn't cross the compilation unit boundries. – GabiMe Nov 15 '18 at 22:31
  • Could you expand on what you mean by "wrapping it in a single class"? I'm still a relative newbie to c++ and can't quite see how I would do it. – TokenGuard Nov 16 '18 at 09:14