JsonConvert.DeserializeXmlNode中的StackOverflowException

时间:2017-04-21 21:10:42

标签: json json.net overflow

我们最近从6.0.1升级到Json.NET 10.0r2,自升级以来,我注意到我们的一个单元测试在尝试反序列化无效的Json时抛出了一个Stack Overflow异常。测试的目的是确保处理无效的Json。同样的测试用于抛出JsonSerializationException,但现在正在使用StackOverflow降低nUnit。

我已经通过此测试在Json.NET自己的单元测试项目中复制了它:

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

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

关于工作的任何想法都是一种解决方法吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

<强>更新

并及时fixed更改集822c3f0。应该在10.0.2之后的下一个版本中。

原始答案

看起来版本8.0.1中对JsonTextReader的更改可能会在XmlNodeConverter中发现错误。

7.0.1中,当文件意外结束时,JsonReader.TokenType在下次尝试Read()后变为JsonToken.None,导致DeserializeNode()投掷一个Unexpected JsonToken when deserializing node: None例外。但是在8.0.1之后,TokenType似乎仍然停留在最后遇到的令牌的类型上,即JsonToken.PropertyName,这会导致无限递归。

正确的解决方法是在第2171行的XmlNodeConverter.DeserializeNode()中检查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 );
    }

...在XmlNodeConverter.cs中还有一些地方需要检查reader.Read()的返回,例如ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager) line 1942周围的string json = @"{'Row' : }";

如果你愿意,你可以report an issue

与此同时,您可以选择解决方法:

  • 以不同的方式破坏JSON,例如:

    JsonException

    并检查更一般的例外JToken

  • 将JSON预解析为Assert.Throws<JsonException>(()=>JsonConvert.DeserializeXmlNode(JToken.Parse(json).ToString(), "ROOT"));

    var descriptor = {
        blocks: [
            ['b', 'Check credentials %s %s', ext.verify_acc, 'Username', 'Password'],
        ]
    };