jbeder / yaml-cpp

A YAML parser and emitter in C++
MIT License
5.06k stars 1.82k forks source link

Abort using yaml-cpp #419

Open vziparo opened 7 years ago

vziparo commented 7 years ago

Hello, I am using this version of yaml-cpp

commit 57805dfd6a741e55477ea8d4d5b3b6f0272d1f0e Author: Rodrigo Hernandez kwizatz@aeongames.com Date: Tue Jan 26 11:45:00 2016 -0600_

And running in some weird errors. I use the library inside a singleton that is accessed by a number of threads read-only. The code looks like this:


#include <stdio.h>
#include <iostream>

#include <yaml-cpp/yaml.h>

class Experiments  {

    YAML::Node _node;

    Experiments(){
        std::string config="./experiments.yaml";
        try{
            _node=YAML::LoadFile(config);
        }catch(std::exception& e){
            std::cerr<<"[ERROR] Experiments::Experiments() Cannot open ./experiments.yaml. Exception: "<<e.what()<<std::endl;
            exit(-1);
        }
    }

    Experiments(Experiments const&) =delete;
    void operator=(Experiments const&) =delete;

public:
    static YAML::Node& instance(){
        static Experiments _instance;
        return _instance._node;
    }
};

Is yaml-cpp thread-safe?

This is the stack trace I get:

_gdb) bt
#0  __libc_do_syscall () at ../sysdeps/unix/sysv/linux/arm/libc-do-syscall.S:47
#1  0x0006273e in raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/pt-raise.c:36
#2  0x003c9502 in abort () at abort.c:89
#3  0x003da2e4 in __libc_message (do_abort=do_abort@entry=2, fmt=0x531bdc "*** Error in `%s': %s: 0x%s ***\n")
    at ../sysdeps/posix/libc_fatal.c:175
#4  0x003dd92c in malloc_printerr (action=3, str=0x531d94 "double free or corruption (fasttop)", ptr=<optimized out>) at malloc.c:4960
#5  0x003ddee4 in _int_free (av=<optimized out>, p=<optimized out>, have_lock=<optimized out>) at malloc.c:3831
#6  0x00318622 in __gnu_cxx::new_allocator<YAML::RegEx>::deallocate (this=0x5de848 <YAML::Exp::Break()::e+8>, __p=<optimized out>)
    at /opt/irobot/brahms-1.0/gcc-linaro-5.2-2015.11-2-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/include/c++/5.2.1/ext/new_allocator.h:110
#7  std::allocator_traits<std::allocator<YAML::RegEx> >::deallocate (__a=..., __n=<optimized out>, __p=<optimized out>)
    at /opt/irobot/brahms-1.0/gcc-linaro-5.2-2015.11-2-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/include/c++/5.2.1/bits/alloc_traits.h:386
#8  std::_Vector_base<YAML::RegEx, std::allocator<YAML::RegEx> >::_M_deallocate (this=0x5de848 <YAML::Exp::Break()::e+8>, 
    __n=<optimized out>, __p=<optimized out>)
    at /opt/irobot/brahms-1.0/gcc-linaro-5.2-2015.11-2-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/include/c++/5.2.1/bits/stl_vector.h:178
#9  std::vector<YAML::RegEx, std::allocator<YAML::RegEx> >::_M_emplace_back_aux<YAML::RegEx>(YAML::RegEx&&) (
    this=this@entry=0x5de848 <YAML::Exp::Break()::e+8>)
    at /opt/xxx/gcc-linaro-5.2-2015.11-2-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/include/c++/5.2.1/bits/vector.tcc:438
#10 0x003182f8 in std::vector<YAML::RegEx, std::allocator<YAML::RegEx> >::push_back (__x=..., this=0x5de848 <YAML::Exp::Break()::e+8>)
    at /opt/irobot/brahms-1.0/gcc-linaro-5.2-2015.11-2-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/include/c++/5.2.1/bits/stl_vector.h:923
#11 YAML::operator|| (ex1=..., ex2=...) at external/yaml-cpp/src/regex_yaml.cpp:28
#12 0x003041fa in YAML::Exp::Break () at external/yaml-cpp/src/exp.h:40
#13 YAML::Scanner::ScanToNextToken (this=this@entry=0xb1002b98) at external/yaml-cpp/src/scanner.cpp:179
#14 0x00305aa8 in YAML::Scanner::ScanNextToken (this=this@entry=0xb1002b98) at external/yaml-cpp/src/scanner.cpp:97
#15 0x00306646 in YAML::Scanner::EnsureTokensInQueue (this=this@entry=0xb1002b98) at external/yaml-cpp/src/scanner.cpp:82
#16 0x003066bc in YAML::Scanner::empty (this=0xb1002b98) at external/yaml-cpp/src/scanner.cpp:22
#17 0x00301f6a in YAML::Parser::ParseDirectives (this=this@entry=0xb21efb38) at external/yaml-cpp/src/parser.cpp:52
#18 0x00301f8c in YAML::Parser::HandleNextDocument (this=this@entry=0xb21efb38, eventHandler=...) at external/yaml-cpp/src/parser.cpp:37
#19 0x00300712 in YAML::Load (input=...) at external/yaml-cpp/src/parse.cpp:25
#20 0x00300bdc in YAML::LoadFile (filename=...) at external/yaml-cpp/src/parse.cpp:35
#21 0x00069b8e in Config::Config (this=0x5b2cbc <Config::instance()::_instance>)

Thanks! Vittorio

tambry commented 7 years ago

Assuming that the code you gave above is in a header, it would result the Experiments static class object getting created for every compilation unit. Try setting the static Experiments _instance; to extern Experiments _instance; and then defining it in the .cpp.

vziparo commented 7 years ago

Thank you for the prompt reply. I will follow your advice. Once I have safely constructed the object and I have just one static class object, will the library be thread safe for concurrent read-only operations? Thanks!

tambry commented 7 years ago

Yes, I think it should be thread-safe for read-only operations, from what I can tell. In my application I personally parse and load the config file into my structures. This for me doesn't cause much overhead, as the config is reloaded very rarely.

Please note that I'm not a maintainer of the library but just a developer with some experience using it.

jbeder commented 7 years ago

yaml-cpp is not necessarily threadsafe for all read-only operations, though it is for some. I haven't verified in detail, but I believe, if you have a const YAML::Node:

But:

are not threadsafe. I'm not 100% sure, however, since I've never tested this.

vziparo commented 7 years ago

Thank you!