Skip to content

Json::Value crash after copy #422

@cpisz-compeat

Description

@cpisz-compeat

Is Json::Value meant to be copyable?
Am I permitted to store it in a std::vector and then retrieve it later and call its methods?

I am developing and testing my own "path" method in a class built on top of JsonCpp. When using the path build into the JsonCpp library, it would crash with any path more than 1 level deep. So, I figured I'd roll my own. It also crashes on any level more than 1 deep when calling a method on a Json::Value that was stored in an std::vector.

It looks like it occurs on line 1003 of json_value.cpp is being triggered or an exception is thrown, but the type is an array value, so I don't understand what's going on. gtests is gobbling it up. I will try taking this code out of gtest in the meanwhile to see if it's an exception or the assert.

My method:

//--------------------------------------------------------------------------------------------------
// In development
std::vector<JsonLoader::JsonElement> JsonLoader::GetFromPath(const std::string & path)
{
    std::vector<JsonElement> result;
    JsonElement element;
    element.m_key    = "root";
    element.m_value  = m_root;
    element.m_parent = Json::Value(NULL);
    result.push_back(element);

    // Tokenize the path
    // Currently, the only path symbols we support are 
    // '/'

    if (path.empty())
    {
        return result;
    }

    size_t                  currentPosition = 0;
    char                    currentChar = path[currentPosition];
    std::string             currentToken;
    std::deque<std::string> tokens;

    if (currentChar != '$')
    {
        const std::string msg("Json path must begin with  '$' for root.");
        throw Shared::Exception(__FILE__, __LINE__, msg);
    }

    while(currentPosition < path.size() )
    {
        switch (currentChar)
        {
        case '$':
            break;
        case '.':
            tokens.push_back(currentToken);
            currentToken.clear();
            break;
        default:
            currentToken.push_back(currentChar);
            break;
        }

        ++currentPosition;
        currentChar = path[currentPosition];
    }

    if (!currentToken.empty() )
    {
        tokens.push_back(currentToken);
        currentToken.clear();
    }

    std::vector<JsonElement> elementsLevelBeingSearched;
    std::vector<JsonElement> elementsLevelToSearchNext;

    elementsLevelToSearchNext.push_back(element);

    for(size_t currentDepth = 0; currentDepth < tokens.size(); ++currentDepth)
    {
        elementsLevelBeingSearched = elementsLevelToSearchNext;
        elementsLevelToSearchNext.clear();

        for (std::vector<JsonElement>::iterator itElementsBeingSearched = elementsLevelBeingSearched.begin();
             itElementsBeingSearched != elementsLevelBeingSearched.end(); ++itElementsBeingSearched)
        {
            JsonElement & elementBeingSearched = *itElementsBeingSearched;

            // Crash occurs here on 2nd iteration of outter for loop
            // with Path = "$people_with_jobs.jobs"
            if ( elementBeingSearched.m_value.isMember(tokens[currentDepth]) )
            {
                element.m_key    = tokens[currentDepth];
                element.m_value  = elementBeingSearched.m_value.get(tokens[currentDepth], Json::Value());
                element.m_parent = elementBeingSearched.m_value;

                elementsLevelToSearchNext.push_back(element);
            }
        }
    }

    return elementsLevelToSearchNext;
}

class JsonLoader : public IJsonLoader
{
public:
    // This struct is really just for easy debugging for now
    struct JsonElement
    {   
        std::string m_key;
        Json::Value m_value;
        Json::Value m_parent;
    };

    /// <summary>
    /// Constructor
    /// </summary>
    JsonLoader(const std::string & json);

    /// <summary>
    /// Deconstructor
    /// </summary>
    virtual ~JsonLoader();

    /// <summary>
    /// Implements <c>IJsonLoader</c>
    /// </summary>
    virtual void Parse(const std::string & json,
                       const std::list<EntityDefinition::SharedPtr> & entityDefinitions);

protected:

    Json::Value  m_root;

    /// <summary>
    /// Based http://goessner.net/articles/JsonPath/
    /// If the path references a non existant value Json::Value(NULL) is returned.
    /// in development
    /// </summary>
    virtual std::vector<JsonElement> GetFromPath(const std::string & path);

};

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions