JsonConvert.DeserializeXmlNode 中的 StackOverflowException
StackOverflowException in JsonConvert.DeserializeXmlNode
我们最近从 6.0.1 升级到 Json.NET 10.0r2,升级后我注意到我们的一个单元测试在尝试反序列化无效 Json 时抛出堆栈溢出异常。测试的目的是确保处理无效 Json。这个相同的测试曾经抛出 JsonSerializationException,但现在正在使用 Whosebug 关闭 nUnit。
我已经在 Json.NET 自己的单元测试项目中复制了这个测试:
[Test]
public void FailOnInvalidJSON( )
{
string json = @"{'Row' : ";
Assert.Throws<JsonSerializationException>(()=>JsonConvert.DeserializeXmlNode(json, "ROOT"));
}
有什么变通办法吗?
谢谢!
更新
并迅速 fixed in change set 822c3f0
。应该在10.0.2之后的下一个版本中。
原答案
看起来像是对 JsonTextReader
in version 8.0.1 may have uncovered a bug in XmlNodeConverter
的更改。
在 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 及之后的 TokenType
似乎停留在最后遇到的标记的类型,即 JsonToken.PropertyName
,这导致无限递归。
正确的解决方法是,在第 2171 行附近的 XmlNodeConverter.DeserializeNode()
中,从 reader.Read()
:
检查 return
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
where the return from reader.Read()
needs to be checked, for instance in ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager)
around line 1942.
中似乎还有几个地方
如果你愿意,你可以report an issue。
与此同时,您可以选择的解决方法是:
以不同的方式破坏 JSON,例如:
string json = @"{'Row' : }";
并检查更一般的异常 JsonException
。
将JSON预解析为JToken
:
Assert.Throws<JsonException>(()=>JsonConvert.DeserializeXmlNode(JToken.Parse(json).ToString(), "ROOT"));
我们最近从 6.0.1 升级到 Json.NET 10.0r2,升级后我注意到我们的一个单元测试在尝试反序列化无效 Json 时抛出堆栈溢出异常。测试的目的是确保处理无效 Json。这个相同的测试曾经抛出 JsonSerializationException,但现在正在使用 Whosebug 关闭 nUnit。
我已经在 Json.NET 自己的单元测试项目中复制了这个测试:
[Test]
public void FailOnInvalidJSON( )
{
string json = @"{'Row' : ";
Assert.Throws<JsonSerializationException>(()=>JsonConvert.DeserializeXmlNode(json, "ROOT"));
}
有什么变通办法吗?
谢谢!
更新
并迅速 fixed in change set 822c3f0
。应该在10.0.2之后的下一个版本中。
原答案
看起来像是对 JsonTextReader
in version 8.0.1 may have uncovered a bug in XmlNodeConverter
的更改。
在 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 及之后的 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
where the return from reader.Read()
needs to be checked, for instance in ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager)
around line 1942.
如果你愿意,你可以report an issue。
与此同时,您可以选择的解决方法是:
以不同的方式破坏 JSON,例如:
string json = @"{'Row' : }";
并检查更一般的异常
JsonException
。将JSON预解析为
JToken
:Assert.Throws<JsonException>(()=>JsonConvert.DeserializeXmlNode(JToken.Parse(json).ToString(), "ROOT"));