{"action":"closed","issue":{"url":"https://api.github.com/repos/gabime/spdlog/issues/183","repository_url":"https://api.github.com/repos/gabime/spdlog","labels_url":"https://api.github.com/repos/gabime/spdlog/issues/183/labels{/name}","comments_url":"https://api.github.com/repos/gabime/spdlog/issues/183/comments","events_url":"https://api.github.com/repos/gabime/spdlog/issues/183/events","html_url":"https://github.com/gabime/spdlog/issues/183","id":137902440,"number":183,"title":"EXC_BAD_ACCESS (code: 1, addr: 0x0)","user":{"login":"HerbertKoelman","id":2906905,"avatar_url":"https://avatars.githubusercontent.com/u/2906905?v=3","gravatar_id":"","url":"https://api.github.com/users/HerbertKoelman","html_url":"https://github.com/HerbertKoelman","followers_url":"https://api.github.com/users/HerbertKoelman/followers","following_url":"https://api.github.com/users/HerbertKoelman/following{/other_user}","gists_url":"https://api.github.com/users/HerbertKoelman/gists{/gist_id}","starred_url":"https://api.github.com/users/HerbertKoelman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HerbertKoelman/subscriptions","organizations_url":"https://api.github.com/users/HerbertKoelman/orgs","repos_url":"https://api.github.com/users/HerbertKoelman/repos","events_url":"https://api.github.com/users/HerbertKoelman/events{/privacy}","received_events_url":"https://api.github.com/users/HerbertKoelman/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":24,"created_at":"2016-03-02T15:17:37Z","updated_at":"2016-03-31T16:36:22Z","closed_at":"2016-03-31T16:36:22Z","body":"First of all I'm quite impressed by SPDLOG. It's doing a very good job. \r\n\r\nI had initially wrapped another implementation with my `pmu::logger` class, but I decided to adapt my wrapper so that it now uses SPDLOG instead.\r\n\r\nTo give access to the logger instance created by `pmu::logger`constructor, I overloaded the *operator->()*. \r\n\r\nEverything is running fine, but from time to time my code ends up with this runtime exception.\r\n\r\nIt seems that when this happens it is handling some SPDLOG formatting operation, so I wondered if it was possible that something was going wrong in SPDLOG.\r\n\r\n## description\r\n\r\nWhen using spdlog in multi-threaded application, I frequently end up with EXC_BAD_ACCESS runtime error.\r\n\r\nAny idea of what is going wrong ? Why do we end up with a null pointer ?\r\n\r\nAccording to the stack trace destructor is called twice (item 4 et 5).\r\n\r\n## stack trace Xcode\r\n\r\n1. ` _LIBCPP_INLINE_VISIBILITY pointer operator->() const _NOEXCEPT {return __ptr_.first();}`: **this** is null.\r\n2. `inline void spdlog::pattern_formatter::format(details::log_msg& msg)` at  `f-> format(msg, tm_time);`: \r\n3. `spdlog::logger::_log_msg(details::log_msg& msg)` at `_formatter->format(msg);`\r\n4. `spdlog::details::line_logger::~line_logger()`at `_callback_logger->_log_msg(_log_msg);`\r\n5. `spdlog::details::line_logger::~line_logger()`\r\n6. `void consumer( pmu::sync_queue<message> *queue, const string fname )`at `logger->warn( err.what() );`\r\n\r\n## plateform\r\n\r\n* Mac OS X: 10.11.3 (15D21)\r\n* Xcode: 7.2.1 (7C1002)\r\n* C++11\r\n\r\n## source code\r\n\r\n### my thread function\r\n\r\nThis incriminated thread code fragment that fails:\r\n```\r\nvoid consumer( pmu::sync_queue<message> *queue, const string flamme )\r\n  try {\r\n    pmu::logger logger(\"consumer\");\r\n    logger->set_level(pmu::logger_levels::notice);\r\n    logger->notice(\"starting.\");\r\n\r\n    std::chrono::seconds wait_time{1};\r\n    ofstream out ;\r\n    out.exceptions(std::ifstream::failbit | std::ifstream::badbit);\r\n    \r\n    try {\r\n      out.open( name );{\r\n      while( running ){\r\n        message msg;\r\n        \r\n        logger->debug(\"before get message.\");\r\n        try{\r\n          queue->get(msg,wait_time);\r\n          \r\n          logger->debug(\"popped a message off, header: [{}], content: [{}]\", msg.get_header(), msg.get_content());\r\n          \r\n          out << msg.get_header() << \";\" << msg.get_content() << ends;\r\n        }catch(pmu::sync_queue_timeout &err){\r\n          this is were the error is detected in my code (a c++ thread) >>>>>> logger->warn( err.what() );\r\n        }\r\n      }\r\n      \r\n      out.close();\r\n      \r\n    } catch (std::ofstream::failure &err) {\r\n      logger->critical(\"file error, going down. {}, {}\",err.what(), strerror( err.code().value()));\r\n    }\r\n  } catch ( pmu::logger_exception &err){\r\n    printf(\"consumer logger setup failed, going down. %s.\\n\", err.what());\r\n  } catch ( ... ){\r\n    printf(\"unhandled exception was thrown in consumer thread, going down.\\n\");\r\n  }\r\n}\r\n```\r\n\r\n### splog wrapper header code:\r\n\r\n```\r\n#include \"spdlog/spdlog.h\"\r\n\r\nnamespace peu {\r\n  \r\n  using namespace std ;\r\n  using logger_exception = spdlog::spdlog_ex ;  \r\n  using logger_levels = spdlog::level::level_enum ;\r\n  \r\n  void set_level( logger_levels level);\r\n  \r\n  class logger {\r\n  public:\r\n    \r\n    logger( const string name );\r\n    \r\n    inline void set_level( logger_levels level );\r\n    inline logger_levels level() const ;\r\n    \r\n    std::shared_ptr<spdlog::logger> operator->();\r\n    \r\n  private:\r\n    std::shared_ptr<spdlog::logger> log ;\r\n    std::mutex mix;\r\n    string name ;\r\n  };\r\n}\r\n```\r\n\r\n\r\n### splog wrapper body code:\r\n\r\n```\r\n#include \"logger.hp\"\r\n\r\nnamespace peu {\r\n  \r\n  void set_level( logger_levels level){\r\n    \r\n    spdlog::set_level(level);\r\n  }\r\n  \r\n  logger::logger( const string n ): name{n}{\r\n    \r\n    std::lock_guard<std::mutex> lck(max);\r\n    \r\n    try {\r\n      log = spdlog::stdout_logger_mt(name);\r\n      log->set_pattern(\"%d/%m/%Y %T.%e %z, [%t] %n.%l: %v\");\r\n      \r\n    } catch( logger_exception &err){\r\n      log = spdlog::get(name);\r\n      log->set_pattern(\"%d/%m/%Y %T.%e %z, [%t] %n.%l: %v\");\r\n    }\r\n    \r\n  }\r\n  \r\n  void logger::set_level( logger_levels level ){\r\n    log->set_level(level);\r\n  }\r\n  \r\n  logger_levels logger::level() const {\r\n    return log->level() ;\r\n  }\r\n\r\n  std::shared_ptr<spdlog::logger> logger::operator->(){\r\n    \r\n    if (log == nullptr ) {\r\n      throw logger_exception(\"null pointer logger for logger name: \" + name);\r\n    }\r\n    return log ;\r\n  }\r\n  \r\n}\r\n```"}}