diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1321.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1321.cs new file mode 100644 index 00000000..215b2aff --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1321.cs @@ -0,0 +1,202 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +#if !(NET20 || NET35 || NET40 || PORTABLE40) +using System.Threading.Tasks; +#endif +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Xml; +#if !NET20 +using System.Xml.Linq; +#endif +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue1321 : TestFixtureBase + { + [Test] + public void Test() + { + ExceptionAssert.Throws(() => + { + JsonConvert.DeserializeObject( + @"[""1"",", + new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.None, MaxDepth = 1024 }); + }, "Unexpected end when reading token. Path ''."); + } + + [Test] + public void Test2() + { + JArray a = new JArray(); + + var writer = a.CreateWriter(); + + JsonTextReader reader = new JsonTextReader(new StringReader(@"[""1"",")); + + ExceptionAssert.Throws(() => + { + writer.WriteToken(reader); + }, "Unexpected end when reading token. Path ''."); + } + +#if !(NET20 || NET35 || NET40 || PORTABLE40) + [Test] + public async Task Test2_Async() + { + JArray a = new JArray(); + + var writer = a.CreateWriter(); + + JsonTextReader reader = new JsonTextReader(new StringReader(@"[""1"",")); + + await ExceptionAssert.ThrowsAsync(async () => + { + await writer.WriteTokenAsync(reader); + }, "Unexpected end when reading token. Path ''."); + } +#endif + + [Test] + public void Test3() + { + JArray a = new JArray(); + + var writer = a.CreateWriter(); + + JsonTextReader reader = new JsonTextReader(new StringReader(@"[""1"",")); + reader.Read(); + + ExceptionAssert.Throws(() => + { + writer.WriteToken(reader); + }, "Unexpected end when reading token. Path ''."); + } + +#if !(NET20 || NET35 || NET40 || PORTABLE40) + [Test] + public async Task Test3_Async() + { + JArray a = new JArray(); + + var writer = a.CreateWriter(); + + JsonTextReader reader = new JsonTextReader(new StringReader(@"[""1"",")); + await reader.ReadAsync(); + + await ExceptionAssert.ThrowsAsync(async () => + { + await writer.WriteTokenAsync(reader); + }, "Unexpected end when reading token. Path ''."); + } +#endif + + [Test] + public void Test4() + { + JArray a = new JArray(); + + var writer = a.CreateWriter(); + + JsonTextReader reader = new JsonTextReader(new StringReader(@"[[""1"",")); + reader.Read(); + reader.Read(); + + ExceptionAssert.Throws(() => + { + writer.WriteToken(reader); + }, "Unexpected end when reading token. Path ''."); + } + +#if !(NET20 || NET35 || NET40 || PORTABLE40) + [Test] + public async Task Test4_Async() + { + JArray a = new JArray(); + + var writer = a.CreateWriter(); + + JsonTextReader reader = new JsonTextReader(new StringReader(@"[[""1"",")); + await reader.ReadAsync(); + await reader.ReadAsync(); + + await ExceptionAssert.ThrowsAsync(async () => + { + await writer.WriteTokenAsync(reader); + }, "Unexpected end when reading token. Path ''."); + } +#endif + + [Test] + public void Test5() + { + StringWriter sw = new StringWriter(); + JsonTextWriter writer = new JsonTextWriter(sw); + writer.WriteStartArray(); + + JsonTextReader reader = new JsonTextReader(new StringReader(@"[[""1"",")); + reader.Read(); + reader.Read(); + + ExceptionAssert.Throws(() => + { + writer.WriteToken(reader); + }, "Unexpected end when reading token. Path '[0]'."); + } + +#if !(NET20 || NET35 || NET40 || PORTABLE40) + [Test] + public async Task Test5_Async() + { + StringWriter sw = new StringWriter(); + JsonTextWriter writer = new JsonTextWriter(sw); + writer.WriteStartArray(); + + JsonTextReader reader = new JsonTextReader(new StringReader(@"[[""1"",")); + await reader.ReadAsync(); + await reader.ReadAsync(); + + await ExceptionAssert.ThrowsAsync(async () => + { + await writer.WriteTokenAsync(reader); + }, "Unexpected end when reading token. Path '[0]'."); + } +#endif + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonWriter.Async.cs b/Src/Newtonsoft.Json/JsonWriter.Async.cs index 8cc0b25c..89d2ad4b 100644 --- a/Src/Newtonsoft.Json/JsonWriter.Async.cs +++ b/Src/Newtonsoft.Json/JsonWriter.Async.cs @@ -675,7 +675,7 @@ namespace Newtonsoft.Json internal virtual async Task WriteTokenAsync(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments, CancellationToken cancellationToken) { - int initialDepth = CalculateWriteTokenDepth(reader); + int initialDepth = CalculateWriteTokenInitialDepth(reader); do { @@ -696,6 +696,11 @@ namespace Newtonsoft.Json initialDepth - 1 < reader.Depth - (JsonTokenUtils.IsEndToken(reader.TokenType) ? 1 : 0) && writeChildren && await reader.ReadAsync(cancellationToken).ConfigureAwait(false)); + + if (initialDepth < CalculateWriteTokenFinalDepth(reader)) + { + throw JsonWriterException.Create(this, "Unexpected end when reading token.", null); + } } // For internal use, when we know the writer does not offer true async support (e.g. when backed @@ -703,7 +708,7 @@ namespace Newtonsoft.Json // path through the sync version. internal async Task WriteTokenSyncReadingAsync(JsonReader reader, CancellationToken cancellationToken) { - int initialDepth = CalculateWriteTokenDepth(reader); + int initialDepth = CalculateWriteTokenInitialDepth(reader); do { @@ -720,6 +725,11 @@ namespace Newtonsoft.Json // stop if we have reached the end of the token being read initialDepth - 1 < reader.Depth - (JsonTokenUtils.IsEndToken(reader.TokenType) ? 1 : 0) && await reader.ReadAsync(cancellationToken).ConfigureAwait(false)); + + if (initialDepth < CalculateWriteTokenFinalDepth(reader)) + { + throw JsonWriterException.Create(this, "Unexpected end when reading token.", null); + } } private async Task WriteConstructorDateAsync(JsonReader reader, CancellationToken cancellationToken) diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 34a2d6b0..52264ab3 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -641,7 +641,7 @@ namespace Newtonsoft.Json internal virtual void WriteToken(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments) { - int initialDepth = CalculateWriteTokenDepth(reader); + int initialDepth = CalculateWriteTokenInitialDepth(reader); do { @@ -662,9 +662,14 @@ namespace Newtonsoft.Json initialDepth - 1 < reader.Depth - (JsonTokenUtils.IsEndToken(reader.TokenType) ? 1 : 0) && writeChildren && reader.Read()); + + if (initialDepth < CalculateWriteTokenFinalDepth(reader)) + { + throw JsonWriterException.Create(this, "Unexpected end when reading token.", null); + } } - private int CalculateWriteTokenDepth(JsonReader reader) + private int CalculateWriteTokenInitialDepth(JsonReader reader) { JsonToken type = reader.TokenType; if (type == JsonToken.None) @@ -675,6 +680,17 @@ namespace Newtonsoft.Json return JsonTokenUtils.IsStartToken(type) ? reader.Depth : reader.Depth + 1; } + private int CalculateWriteTokenFinalDepth(JsonReader reader) + { + JsonToken type = reader.TokenType; + if (type == JsonToken.None) + { + return -1; + } + + return JsonTokenUtils.IsEndToken(type) ? reader.Depth - 1 : reader.Depth; + } + private void WriteConstructorDate(JsonReader reader) { if (!reader.Read())