kastnermario / yaml-cpp

Automatically exported from code.google.com/p/yaml-cpp
MIT License
0 stars 0 forks source link

Problem with exceptions.h, specifically the const initialization of the std::string literals in the ErrorMsg namespace. #95

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?
Any yaml file that causes a KEY_NOT_FOUND exception.

What is the expected output? What do you see instead?
Expected to see the exception thrown.

Instead I see a SEGV due to the const initialization in the declaration in 
ErrorMsg namespace in exceptions.h

What version of the product are you using? On what operating system?
0.25

Please provide any additional information below.

Problem with exceptions.h, specifically the const initialization of the 
std::string literals. I believe the C++ standard states that only integer or 
enum constants can be initialized in the declaration. The string literals in 
the ErrorMsg namespace need to be initialized in a compilation unit and not in 
the header.

Original issue reported on code.google.com by christop...@gmail.com on 1 Mar 2011 at 7:12

GoogleCodeExporter commented 8 years ago
By the way, I am using yaml-cpp 0.25 on Ubuntu 10.04 using gcc 4.4.1

Original comment by christop...@gmail.com on 1 Mar 2011 at 7:13

GoogleCodeExporter commented 8 years ago
I have fixed this issue by creating the a new file called src/exceptions.cpp 
and moved the const std::string initializations in ErrorMsg namespace into the 
src/exceptions.cpp file. Also the ErrorMsg namespace is now a class and all of 
its members are declared static.

// begin include/exceptions.h
#pragma once

#ifndef EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66

#include "mark.h"
#include "traits.h"
#include <exception>
#include <string>
#include <sstream>

namespace YAML
{
    // error messages
    //namespace ErrorMsg
        //{
    class ErrorMsg
    {
    public:
      /*
        const std::string YAML_DIRECTIVE_ARGS    = "YAML directives must have exactly one argument";
        const std::string YAML_VERSION           = "bad YAML version: ";
        const std::string YAML_MAJOR_VERSION     = "YAML major version too large";
        const std::string REPEATED_YAML_DIRECTIVE= "repeated YAML directive";
        const std::string TAG_DIRECTIVE_ARGS     = "TAG directives must have exactly two arguments";
        const std::string REPEATED_TAG_DIRECTIVE = "repeated TAG directive";
        const std::string CHAR_IN_TAG_HANDLE     = "illegal character found while scanning tag handle";
        const std::string TAG_WITH_NO_SUFFIX     = "tag handle with no suffix";
        const std::string END_OF_VERBATIM_TAG    = "end of verbatim tag not found";
        const std::string END_OF_MAP             = "end of map not found";
        const std::string END_OF_MAP_FLOW        = "end of map flow not found";
        const std::string END_OF_SEQ             = "end of sequence not found";
        const std::string END_OF_SEQ_FLOW        = "end of sequence flow not found";
        const std::string MULTIPLE_TAGS          = "cannot assign multiple tags to the same node";
        const std::string MULTIPLE_ANCHORS       = "cannot assign multiple anchors to the same node";
        const std::string MULTIPLE_ALIASES       = "cannot assign multiple aliases to the same node";
        const std::string ALIAS_CONTENT          = "aliases can't have any content, *including* tags";
        const std::string INVALID_HEX            = "bad character found while scanning hex number";
        const std::string INVALID_UNICODE        = "invalid unicode: ";
        const std::string INVALID_ESCAPE         = "unknown escape character: ";
        const std::string UNKNOWN_TOKEN          = "unknown token";
        const std::string DOC_IN_SCALAR          = "illegal document indicator in scalar";
        const std::string EOF_IN_SCALAR          = "illegal EOF in scalar";
        const std::string CHAR_IN_SCALAR         = "illegal character in scalar";
        const std::string TAB_IN_INDENTATION     = "illegal tab when looking for indentation";
        const std::string FLOW_END               = "illegal flow end";
        const std::string BLOCK_ENTRY            = "illegal block entry";
        const std::string MAP_KEY                = "illegal map key";
        const std::string MAP_VALUE              = "illegal map value";
        const std::string ALIAS_NOT_FOUND        = "alias not found after *";
        const std::string ANCHOR_NOT_FOUND       = "anchor not found after &";
        const std::string CHAR_IN_ALIAS          = "illegal character found while scanning alias";
        const std::string CHAR_IN_ANCHOR         = "illegal character found while scanning anchor";
        const std::string ZERO_INDENT_IN_BLOCK   = "cannot set zero indentation for a block scalar";
        const std::string CHAR_IN_BLOCK          = "unexpected character in block scalar";
        const std::string AMBIGUOUS_ANCHOR     = "cannot assign the same alias to multiple nodes";
        const std::string UNKNOWN_ANCHOR       = "the referenced anchor is not defined";

        const std::string INVALID_SCALAR         = "invalid scalar";
        const std::string KEY_NOT_FOUND          = "key not found";
        const std::string BAD_DEREFERENCE        = "bad dereference";

        const std::string UNMATCHED_GROUP_TAG    = "unmatched group tag";
        const std::string UNEXPECTED_END_SEQ     = "unexpected end sequence token";
        const std::string UNEXPECTED_END_MAP     = "unexpected end map token";
        const std::string SINGLE_QUOTED_CHAR     = "invalid character in single-quoted string";
        const std::string INVALID_ANCHOR         = "invalid anchor";
        const std::string INVALID_ALIAS          = "invalid alias";
        const std::string INVALID_TAG            = "invalid tag";
        const std::string EXPECTED_KEY_TOKEN     = "expected key token";
        const std::string EXPECTED_VALUE_TOKEN   = "expected value token";
        const std::string UNEXPECTED_KEY_TOKEN   = "unexpected key token";
        const std::string UNEXPECTED_VALUE_TOKEN = "unexpected value token";
      */

        static const std::string YAML_DIRECTIVE_ARGS;
        static const std::string YAML_VERSION;
        static const std::string YAML_MAJOR_VERSION;
        static const std::string REPEATED_YAML_DIRECTIVE;
        static const std::string TAG_DIRECTIVE_ARGS;
        static const std::string REPEATED_TAG_DIRECTIVE;
        static const std::string CHAR_IN_TAG_HANDLE;
        static const std::string TAG_WITH_NO_SUFFIX;
        static const std::string END_OF_VERBATIM_TAG;
        static const std::string END_OF_MAP;
        static const std::string END_OF_MAP_FLOW;
        static const std::string END_OF_SEQ;
        static const std::string END_OF_SEQ_FLOW;
        static const std::string MULTIPLE_TAGS;
        static const std::string MULTIPLE_ANCHORS;
        static const std::string MULTIPLE_ALIASES;
        static const std::string ALIAS_CONTENT;
        static const std::string INVALID_HEX;
        static const std::string INVALID_UNICODE;
        static const std::string INVALID_ESCAPE;
        static const std::string UNKNOWN_TOKEN;
        static const std::string DOC_IN_SCALAR;
        static const std::string EOF_IN_SCALAR;
        static const std::string CHAR_IN_SCALAR;
        static const std::string TAB_IN_INDENTATION;
        static const std::string FLOW_END;
        static const std::string BLOCK_ENTRY;
        static const std::string MAP_KEY;
        static const std::string MAP_VALUE;
        static const std::string ALIAS_NOT_FOUND;
        static const std::string ANCHOR_NOT_FOUND;
        static const std::string CHAR_IN_ALIAS;
        static const std::string CHAR_IN_ANCHOR;
        static const std::string ZERO_INDENT_IN_BLOCK;
        static const std::string CHAR_IN_BLOCK;
        static const std::string AMBIGUOUS_ANCHOR;
        static const std::string UNKNOWN_ANCHOR;

        static const std::string INVALID_SCALAR;
        static const std::string KEY_NOT_FOUND;
        static const std::string BAD_DEREFERENCE;

        static const std::string UNMATCHED_GROUP_TAG;
        static const std::string UNEXPECTED_END_SEQ;
        static const std::string UNEXPECTED_END_MAP;
        static const std::string SINGLE_QUOTED_CHAR;
        static const std::string INVALID_ANCHOR;
        static const std::string INVALID_ALIAS;
        static const std::string INVALID_TAG;
        static const std::string EXPECTED_KEY_TOKEN;
        static const std::string EXPECTED_VALUE_TOKEN;
        static const std::string UNEXPECTED_KEY_TOKEN;
        static const std::string UNEXPECTED_VALUE_TOKEN;

        template <typename T>
        inline static const std::string KEY_NOT_FOUND_WITH_KEY(const T&, typename disable_if<is_numeric<T> >::type * = 0) {
            return KEY_NOT_FOUND;
        }

        inline static const std::string KEY_NOT_FOUND_WITH_KEY(const std::string& key) {
            return KEY_NOT_FOUND + ": " + key;
        }

        template <typename T>
        inline static const std::string KEY_NOT_FOUND_WITH_KEY(const T& key, typename enable_if<is_numeric<T> >::type * = 0) {
            std::stringstream stream;
            stream << KEY_NOT_FOUND << ": " << key;
            return stream.str();
        }
    };

    class Exception: public std::exception {
    public:
        Exception(const Mark& mark_, const std::string& msg_)
            : mark(mark_), msg(msg_) {
                std::stringstream output;
                output << "yaml-cpp: error at line " << mark.line+1 << ", column " << mark.column+1 << ": " << msg;
                what_ = output.str();
            }
        virtual ~Exception() throw() {}
        virtual const char *what() const throw() { return what_.c_str(); }

        Mark mark;
        std::string msg;

    private:
        std::string what_;
    };

    class ParserException: public Exception {
    public:
        ParserException(const Mark& mark_, const std::string& msg_)
            : Exception(mark_, msg_) {}
    };

    class RepresentationException: public Exception {
    public:
        RepresentationException(const Mark& mark_, const std::string& msg_)
            : Exception(mark_, msg_) {}
    };

    // representation exceptions
    class InvalidScalar: public RepresentationException {
    public:
        InvalidScalar(const Mark& mark_)
            : RepresentationException(mark_, ErrorMsg::INVALID_SCALAR) {}
    };

    class KeyNotFound: public RepresentationException {
    public:
        template <typename T>
        KeyNotFound(const Mark& mark_, const T& key_)
            : RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) {}
    };

    template <typename T>
    class TypedKeyNotFound: public KeyNotFound {
    public:
        TypedKeyNotFound(const Mark& mark_, const T& key_)
            : KeyNotFound(mark_, key_), key(key_) {}
        virtual ~TypedKeyNotFound() throw() {}

        T key;
    };

    template <typename T>
    inline TypedKeyNotFound <T> MakeTypedKeyNotFound(const Mark& mark, const T& key) {
        return TypedKeyNotFound <T> (mark, key);
    }

    class BadDereference: public RepresentationException {
    public:
        BadDereference()
        : RepresentationException(Mark::null(), ErrorMsg::BAD_DEREFERENCE) {}
    };

    class EmitterException: public Exception {
    public:
        EmitterException(const std::string& msg_)
        : Exception(Mark::null(), msg_) {}
    };
}

#endif // EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
// end include/exceptions.h

// begin src/exceptions.cpp
#include "exceptions.h"

namespace YAML
{
  const std::string ErrorMsg::YAML_DIRECTIVE_ARGS    = "YAML directives must have exactly one argument";
  const std::string ErrorMsg::YAML_VERSION           = "bad YAML version: ";
  const std::string ErrorMsg::YAML_MAJOR_VERSION     = "YAML major version too large";
  const std::string ErrorMsg::REPEATED_YAML_DIRECTIVE= "repeated YAML directive";
  const std::string ErrorMsg::TAG_DIRECTIVE_ARGS     = "TAG directives must have exactly two arguments";
  const std::string ErrorMsg::REPEATED_TAG_DIRECTIVE = "repeated TAG directive";
  const std::string ErrorMsg::CHAR_IN_TAG_HANDLE     = "illegal character found while scanning tag handle";
  const std::string ErrorMsg::TAG_WITH_NO_SUFFIX     = "tag handle with no suffix";
  const std::string ErrorMsg::END_OF_VERBATIM_TAG    = "end of verbatim tag not found";
  const std::string ErrorMsg::END_OF_MAP             = "end of map not found";
  const std::string ErrorMsg::END_OF_MAP_FLOW        = "end of map flow not found";
  const std::string ErrorMsg::END_OF_SEQ             = "end of sequence not found";
  const std::string ErrorMsg::END_OF_SEQ_FLOW        = "end of sequence flow not found";
  const std::string ErrorMsg::MULTIPLE_TAGS          = "cannot assign multiple tags to the same node";
  const std::string ErrorMsg::MULTIPLE_ANCHORS       = "cannot assign multiple anchors to the same node";
  const std::string ErrorMsg::MULTIPLE_ALIASES       = "cannot assign multiple aliases to the same node";
  const std::string ErrorMsg::ALIAS_CONTENT          = "aliases can't have any content, *including* tags";
  const std::string ErrorMsg::INVALID_HEX            = "bad character found while scanning hex number";
  const std::string ErrorMsg::INVALID_UNICODE        = "invalid unicode: ";
  const std::string ErrorMsg::INVALID_ESCAPE         = "unknown escape character: ";
  const std::string ErrorMsg::UNKNOWN_TOKEN          = "unknown token";
  const std::string ErrorMsg::DOC_IN_SCALAR          = "illegal document indicator in scalar";
  const std::string ErrorMsg::EOF_IN_SCALAR          = "illegal EOF in scalar";
  const std::string ErrorMsg::CHAR_IN_SCALAR         = "illegal character in scalar";
  const std::string ErrorMsg::TAB_IN_INDENTATION     = "illegal tab when looking for indentation";
  const std::string ErrorMsg::FLOW_END               = "illegal flow end";
  const std::string ErrorMsg::BLOCK_ENTRY            = "illegal block entry";
  const std::string ErrorMsg::MAP_KEY                = "illegal map key";
  const std::string ErrorMsg::MAP_VALUE              = "illegal map value";
  const std::string ErrorMsg::ALIAS_NOT_FOUND        = "alias not found after *";
  const std::string ErrorMsg::ANCHOR_NOT_FOUND       = "anchor not found after &";
  const std::string ErrorMsg::CHAR_IN_ALIAS          = "illegal character found while scanning alias";
  const std::string ErrorMsg::CHAR_IN_ANCHOR         = "illegal character found while scanning anchor";
  const std::string ErrorMsg::ZERO_INDENT_IN_BLOCK   = "cannot set zero indentation for a block scalar";
  const std::string ErrorMsg::CHAR_IN_BLOCK          = "unexpected character in block scalar";
  const std::string ErrorMsg::AMBIGUOUS_ANCHOR     = "cannot assign the same alias to multiple nodes";
  const std::string ErrorMsg::UNKNOWN_ANCHOR       = "the referenced anchor is not defined";

  const std::string ErrorMsg::INVALID_SCALAR         = "invalid scalar";
  const std::string ErrorMsg::KEY_NOT_FOUND          = "key not found";
  const std::string ErrorMsg::BAD_DEREFERENCE        = "bad dereference";

  const std::string ErrorMsg::UNMATCHED_GROUP_TAG    = "unmatched group tag";
  const std::string ErrorMsg::UNEXPECTED_END_SEQ     = "unexpected end sequence token";
  const std::string ErrorMsg::UNEXPECTED_END_MAP     = "unexpected end map token";
  const std::string ErrorMsg::SINGLE_QUOTED_CHAR     = "invalid character in single-quoted string";
  const std::string ErrorMsg::INVALID_ANCHOR         = "invalid anchor";
  const std::string ErrorMsg::INVALID_ALIAS          = "invalid alias";
  const std::string ErrorMsg::INVALID_TAG            = "invalid tag";
  const std::string ErrorMsg::EXPECTED_KEY_TOKEN     = "expected key token";
  const std::string ErrorMsg::EXPECTED_VALUE_TOKEN   = "expected value token";
  const std::string ErrorMsg::UNEXPECTED_KEY_TOKEN   = "unexpected key token";
  const std::string ErrorMsg::UNEXPECTED_VALUE_TOKEN = "unexpected value token";
}
// end src/exceptions.cpp

Original comment by christop...@gmail.com on 1 Mar 2011 at 8:06

GoogleCodeExporter commented 8 years ago
When you say "only integer or enum constants can be initialized in the 
declaration", you may be thinking of static class members, not (static) 
constants at namespace scope. If this were the problem, you'd be getting a 
compiler error, not a runtime error.

My guess is that you're loading the YAML file before main() - is that correct? 
If so, then the string constants may not be constructed, so you'll get the seg 
fault.

That said, I think you're right, we shouldn't have all these std::string 
objects. I'll change them to string literals (const char *), which will mean 
they won't have to be stored in every translation unit.

Original comment by jbe...@gmail.com on 2 Mar 2011 at 3:52

GoogleCodeExporter commented 8 years ago
Fixed, r431. Please let me know if it works for you. Thanks for the report!

Original comment by jbe...@gmail.com on 2 Mar 2011 at 4:13

GoogleCodeExporter commented 8 years ago
I tried the latest checkout, (using the svn command to grab the read-only) and 
now it throws a key not found error for this construct:

- log: __ENV_CFG_LOG__

Any thoughts?

Original comment by christop...@gmail.com on 2 Mar 2011 at 5:33

GoogleCodeExporter commented 8 years ago
Also I noticed that when I make and make install the 0.25 release I see this:

cgomez@ubuntu-kai build [59] > make
Scanning dependencies of target yaml-cpp
[  3%] Building CXX object CMakeFiles/yaml-cpp.dir/src/exceptions.cpp.o
Linking CXX shared library libyaml-cpp.so
[ 80%] Built target yaml-cpp
Linking CXX executable run-tests
[ 96%] Built target run-tests
Linking CXX executable parse
[100%] Built target parse
cgomez@ubuntu-kai build [60] > sudo make install
[ 80%] Built target yaml-cpp
[ 96%] Built target run-tests
[100%] Built target parse
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/lib/libyaml-cpp.so.0.2.5
-- Up-to-date: /usr/local/lib/libyaml-cpp.so.0.2
-- Up-to-date: /usr/local/lib/libyaml-cpp.so
-- Up-to-date: /usr/local/include/yaml-cpp/yaml.h
-- Up-to-date: /usr/local/include/yaml-cpp/exceptions.h
-- Up-to-date: /usr/local/include/yaml-cpp/null.h
-- Up-to-date: /usr/local/include/yaml-cpp/stlemitter.h
-- Up-to-date: /usr/local/include/yaml-cpp/stlnode.h
-- Up-to-date: /usr/local/include/yaml-cpp/iterator.h
-- Up-to-date: /usr/local/include/yaml-cpp/mark.h
-- Up-to-date: /usr/local/include/yaml-cpp/emitter.h
-- Up-to-date: /usr/local/include/yaml-cpp/node.h
-- Up-to-date: /usr/local/include/yaml-cpp/nodeutil.h
-- Up-to-date: /usr/local/include/yaml-cpp/traits.h
-- Up-to-date: /usr/local/include/yaml-cpp/parser.h
-- Up-to-date: /usr/local/include/yaml-cpp/nodeimpl.h
-- Up-to-date: /usr/local/include/yaml-cpp/conversion.h
-- Up-to-date: /usr/local/include/yaml-cpp/nodereadimpl.h
-- Up-to-date: /usr/local/include/yaml-cpp/noncopyable.h
-- Up-to-date: /usr/local/include/yaml-cpp/ostream.h
-- Up-to-date: /usr/local/include/yaml-cpp/emittermanip.h
-- Up-to-date: /usr/local/lib/pkgconfig/yaml-cpp.pc
cgomez@ubuntu-kai build [61] > 

But when I make and make install the latest code I only this (notice the 
missing .so files), Am I missing something in the build? Currently my 
application depends on the shared library version of yaml-cpp):

cgomez@ubuntu-kai build [30] > sudo make install
[sudo] password for cgomez: 
[ 83%] Built target yaml-cpp
[ 97%] Built target run-tests
[100%] Built target parse
Install the project...
-- Install configuration: "Release"
-- Up-to-date: /usr/local/lib/libyaml-cpp.a
-- Installing: /usr/local/include/yaml-cpp/yaml.h
-- Up-to-date: /usr/local/include/yaml-cpp/nodeproperties.h
-- Up-to-date: /usr/local/include/yaml-cpp/anchor.h
-- Installing: /usr/local/include/yaml-cpp/exceptions.h
-- Installing: /usr/local/include/yaml-cpp/null.h
-- Up-to-date: /usr/local/include/yaml-cpp/eventhandler.h
-- Installing: /usr/local/include/yaml-cpp/stlemitter.h
-- Installing: /usr/local/include/yaml-cpp/stlnode.h
-- Up-to-date: /usr/local/include/yaml-cpp/emitfromevents.h
-- Installing: /usr/local/include/yaml-cpp/iterator.h
-- Installing: /usr/local/include/yaml-cpp/mark.h
-- Installing: /usr/local/include/yaml-cpp/emitter.h
-- Installing: /usr/local/include/yaml-cpp/node.h
-- Installing: /usr/local/include/yaml-cpp/nodeutil.h
-- Installing: /usr/local/include/yaml-cpp/traits.h
-- Up-to-date: /usr/local/include/yaml-cpp/aliasmanager.h
-- Installing: /usr/local/include/yaml-cpp/parser.h
-- Installing: /usr/local/include/yaml-cpp/nodeimpl.h
-- Installing: /usr/local/include/yaml-cpp/conversion.h
-- Installing: /usr/local/include/yaml-cpp/nodereadimpl.h
-- Up-to-date: /usr/local/include/yaml-cpp/graphbuilder.h
-- Up-to-date: /usr/local/include/yaml-cpp/anchordict.h
-- Installing: /usr/local/include/yaml-cpp/noncopyable.h
-- Installing: /usr/local/include/yaml-cpp/ostream.h
-- Installing: /usr/local/include/yaml-cpp/emittermanip.h
-- Installing: /usr/local/lib/pkgconfig/yaml-cpp.pc

Original comment by christop...@gmail.com on 2 Mar 2011 at 5:51

GoogleCodeExporter commented 8 years ago
OK, I figured out how to generate the shared libraries (by editing the 
build/CMakeCache.txt file)and now everything works as expected.

Thanks again for the quick fix and release :-)

By the way, I find yaml-cpp very easy to use and of great quality, and have 
recommended to my colleagues (here at AMD).

Original comment by christop...@gmail.com on 2 Mar 2011 at 6:03

GoogleCodeExporter commented 8 years ago
Cool! The CMakeLists.txt has undergone some recent changes, so the default 
switched from shared to static. I think I ought to change it back - sorry.

Original comment by jbe...@gmail.com on 2 Mar 2011 at 6:59