-Fixed infinite loop from an input error when reading an array and error handling is catching the error

-Fixed base object error not being handled when deserializing
This commit is contained in:
James Newton-King
2012-04-28 01:41:56 +12:00
parent d63e662bda
commit a0fd6bb3e0
5 changed files with 196 additions and 10 deletions
@@ -2481,6 +2481,76 @@ bye", reader.Value);
Assert.IsTrue(reader.Read());
#endif
}
[Test]
public void ResetJsonTextReaderErrorCount()
{
ToggleReaderError toggleReaderError = new ToggleReaderError(new StringReader("{'first':1,'second':2,'third':3}"));
JsonTextReader jsonTextReader = new JsonTextReader(toggleReaderError);
Assert.IsTrue(jsonTextReader.Read());
toggleReaderError.Error = true;
ExceptionAssert.Throws<Exception>(
"Read error",
() => jsonTextReader.Read());
ExceptionAssert.Throws<Exception>(
"Read error",
() => jsonTextReader.Read());
toggleReaderError.Error = false;
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual("first", jsonTextReader.Value);
toggleReaderError.Error = true;
ExceptionAssert.Throws<Exception>(
"Read error",
() => jsonTextReader.Read());
toggleReaderError.Error = false;
Assert.IsTrue(jsonTextReader.Read());
Assert.AreEqual(1, jsonTextReader.Value);
toggleReaderError.Error = true;
ExceptionAssert.Throws<Exception>(
"Read error",
() => jsonTextReader.Read());
ExceptionAssert.Throws<Exception>(
"Read error",
() => jsonTextReader.Read());
ExceptionAssert.Throws<Exception>(
"Read error",
() => jsonTextReader.Read());
toggleReaderError.Error = false;
Assert.IsFalse(jsonTextReader.Read());
}
public class ToggleReaderError : TextReader
{
private readonly TextReader _inner;
public bool Error { get; set; }
public ToggleReaderError(TextReader inner)
{
_inner = inner;
}
public override int Read(char[] buffer, int index, int count)
{
if (Error)
throw new Exception("Read error");
return _inner.Read(buffer, index, 1);
}
}
}
public class SlowStream : Stream
@@ -361,6 +361,84 @@ namespace Newtonsoft.Json.Tests.Serialization
{
public Nest A { get; set; }
}
[Test]
public void InfiniteErrorHandlingLoopFromInputError()
{
IList<string> errors = new List<string>();
JsonSerializer serializer = new JsonSerializer();
serializer.Error += (sender, e) =>
{
errors.Add(e.ErrorContext.Error.Message);
e.ErrorContext.Handled = true;
};
ErrorPerson[] result = serializer.Deserialize<ErrorPerson[]>(new JsonTextReader(new ThrowingReader()));
Assert.IsNull(result);
Assert.AreEqual(4, errors.Count);
Assert.AreEqual("too far", errors[0]);
Assert.AreEqual("too far", errors[1]);
Assert.AreEqual("too far", errors[2]);
Assert.AreEqual("Unexpected end when deserializing array. Path '[1023]', line 1, position 65536.", errors[3]);
}
public class ThrowingReader : TextReader
{
int _position = 0;
static string element = "{\"FirstName\":\"Din\",\"LastName\":\"Rav\",\"Item\":{\"ItemName\":\"temp\"}}";
bool _firstRead = true;
bool _readComma = false;
public ThrowingReader()
{
}
public override int Read(char[] buffer, int index, int count)
{
char[] temp = new char[buffer.Length];
int charsRead = 0;
if (_firstRead)
{
charsRead = new StringReader("[").Read(temp, index, count);
_firstRead = false;
}
else
{
if (_readComma)
{
charsRead = new StringReader(",").Read(temp, index, count);
_readComma = false;
}
else
{
charsRead = new StringReader(element).Read(temp, index, count);
_readComma = true;
}
}
_position += charsRead;
if (_position > 65536)
{
throw new Exception("too far");
}
Array.Copy(temp, index, buffer, index, charsRead);
return charsRead;
}
}
}
public class ErrorPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public ErrorItem Item { get; set; }
}
public class ErrorItem
{
public string ItemName { get; set; }
}
[JsonObject]
+23 -1
View File
@@ -55,6 +55,7 @@ namespace Newtonsoft.Json
private const char UnicodeReplacementChar = '\uFFFD';
private readonly TextReader _reader;
private int _readerFailureCount;
private char[] _chars;
private int _charsUsed;
@@ -75,6 +76,8 @@ namespace Newtonsoft.Json
throw new ArgumentNullException("reader");
_reader = reader;
_readerFailureCount = 0;
_lineNumber = 1;
_chars = new char[4097];
@@ -323,7 +326,26 @@ namespace Newtonsoft.Json
int attemptCharReadCount = _chars.Length - _charsUsed - 1;
int charsRead = _reader.Read(_chars, _charsUsed, attemptCharReadCount);
int charsRead;
try
{
charsRead = _reader.Read(_chars, _charsUsed, attemptCharReadCount);
_readerFailureCount = 0;
}
catch
{
// to prevent infinate loop when error handling is enabled
if (!_isEndOfFile)
{
_readerFailureCount++;
if (_readerFailureCount >= 3)
_isEndOfFile = true;
}
throw;
}
_charsUsed += charsRead;
if (charsRead == 0)
@@ -101,7 +101,8 @@ namespace Newtonsoft.Json.Serialization
protected bool IsErrorHandled(object currentObject, JsonContract contract, object keyValue, string path, Exception ex)
{
ErrorContext errorContext = GetErrorContext(currentObject, keyValue, path, ex);
contract.InvokeOnError(currentObject, Serializer.Context, errorContext);
if (contract != null)
contract.InvokeOnError(currentObject, Serializer.Context, errorContext);
if (!errorContext.Handled)
Serializer.OnError(new ErrorEventArgs(currentObject, errorContext));
@@ -113,17 +113,32 @@ namespace Newtonsoft.Json.Serialization
JsonContract contract = GetContractSafe(objectType);
JsonConverter converter = GetConverter(contract, null, null);
if (reader.TokenType == JsonToken.None && !ReadForType(reader, contract, converter != null, false))
try
{
if (contract != null && !contract.IsNullable)
throw JsonSerializationException.Create(reader, "No JSON content found and type '{0}' is not nullable.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
JsonConverter converter = GetConverter(contract, null, null);
return null;
if (reader.TokenType == JsonToken.None && !ReadForType(reader, contract, converter != null, false))
{
if (contract != null && !contract.IsNullable)
throw JsonSerializationException.Create(reader, "No JSON content found and type '{0}' is not nullable.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
return null;
}
return CreateValueNonProperty(reader, objectType, contract, converter, null);
}
catch (Exception ex)
{
if (IsErrorHandled(null, contract, null, reader.Path, ex))
{
HandleError(reader, 0);
return null;
}
else
{
throw;
}
}
return CreateValueNonProperty(reader, objectType, contract, converter, null);
}
private JsonSerializerProxy GetInternalSerializer()