3

We recently upgraded to Json.NET 10.0r2 from 6.0.1 and since upgrading I noticed that one of our unit tests throws a Stack Overflow Exception when trying to deserialize invalid Json. The purpose of the test was to ensure handling of invalid Json. This same test used to throw a JsonSerializationException, but now is bringing down nUnit with the StackOverflow.

I've replicated it in Json.NET's own unit testing project with this test:

[Test]
public void FailOnInvalidJSON( )
{
    string json = @"{'Row' : ";

    Assert.Throws<JsonSerializationException>(()=>JsonConvert.DeserializeXmlNode(json, "ROOT"));
}

Any ideas on work a work-around?

Thanks!

0

1 Answer 1

1

Update

And promptly fixed in change set 822c3f0. Should be in the next release after 10.0.2.

Original Answer

It looks like a change to JsonTextReader in version 8.0.1 may have uncovered a bug in XmlNodeConverter.

In 7.0.1, when the unexpected end of file is reached, JsonReader.TokenType becomes JsonToken.None after the next attempt to Read(), which causes DeserializeNode() to throw an Unexpected JsonToken when deserializing node: None exception. But in 8.0.1 and later the TokenType appears to stay stuck at the type of the last encountered token, namely JsonToken.PropertyName, which causes the infinite recursion.

The correct fix would be, in XmlNodeConverter.DeserializeNode() around line 2171, to check the return from reader.Read():

case JsonToken.PropertyName:
    if (currentNode.NodeType == XmlNodeType.Document && document.DocumentElement != null)
    {
        throw JsonSerializationException.Create(reader, "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifying a DeserializeRootElementName.");
    }

    string propertyName = reader.Value.ToString();
    // Need to check the return from reader.Read() here:
    if (!reader.Read())
    {
        throw JsonSerializationException.Create(reader, "Unexpected end of file when deserializing property: " + propertyName );
    }

... And it appears there are a few more places in XmlNodeConverter.cs where the return from reader.Read() needs to be checked, for instance in ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager) around line 1942.

You could report an issue if you want.

In the meantime, your options for a workaround would be:

  • Corrupt the JSON in a different manner, for instance like so:

    string json = @"{'Row' : }";
    

    And check for the more general exception JsonException.

  • Pre-parse the JSON into a JToken:

    Assert.Throws<JsonException>(()=>JsonConvert.DeserializeXmlNode(JToken.Parse(json).ToString(), "ROOT"));
    
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.