JamesNK / Newtonsoft.Json

Json.NET is a popular high-performance JSON framework for .NET
https://www.newtonsoft.com/json
MIT License
10.73k stars 3.25k forks source link

DeserializeObject does not respect JsonSerializerSettings.MaxDepth #2850

Open briandesarmo opened 1 year ago

briandesarmo commented 1 year ago

Source/destination types

See Steps to Reproduce

Source/destination JSON

See Steps to Reproduce

Expected behavior

DeserializeObject<T>(...) respects MaxDepth from JsonSerializerSettings

Actual behavior

DeserializeObject<T>(...) does not respect MaxDepth from JsonSerializerSettings

Steps to reproduce

using Newtonsoft.Json;
using System.Collections.Generic;

namespace MaxDepthMRE
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var settings = new JsonSerializerSettings
            {
                TypeNameHandling = TypeNameHandling.Auto,
                MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead,
                ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
                PreserveReferencesHandling = PreserveReferencesHandling.All,
                MaxDepth = int.MaxValue
            };

            var all = new List<TestClass>();
            var testClass = new TestClass { Id = 0, Others = all };
            all.Add(testClass);

            var current = testClass;
            for (var d = 0; d < 64; d++)
            {
                var other = new TestClass() { Id = d, Others = all };
                all.Add(other);
                current.Other = other;
                current = other;
            }

            var serialized = JsonConvert.SerializeObject(testClass, settings);

            JsonConvert.DeserializeObject<TestClass>(serialized, settings);
        }

        private class TestClass
        {
            public long Id { get; set; }
            public TestClass Other { get; set; }
            public List<TestClass> Others { get; set; }
        }
    }
}

The DeserializeObject call in the above code works in 12.0.3, but does not work in 13.0.1, 13.0.2, or 13.0.3.

The folllowing exception is thrown:

Newtonsoft.Json.JsonReaderException: 'The reader's MaxDepth of 64 has been exceeded. 
JamesNK commented 1 year ago

Doesn't your sample set MaxDepth to int.MaxValue? That basically removes the limit.

elgonzo commented 1 year ago

@JamesNK

Doesn't your sample set MaxDepth to int.MaxValue?

I am not the author of this issue report, but looking at the code in the opening post, it apparently does.

That basically removes the limit.

Then why the exception about the reader's MaxDepth of 64 being exceeded?

Anyways, it's not specifically the int.MaxValue value. It actually doesn't matter what value you set as long as it is larger than or equal to 68. It's always exactly the same exception mentioning a MaxDepth of 64.

Try 68. Still throwing exception about the MaxDepth of 64 being exceeded.

Try 67. Now the exception states MaxDepth being 67 that has been exceeded. Also note that the stacktrace here is different compared to when the MaxDepth setting is 68 or larger.

Something isn't right with how the MaxDepth setting is being handled.

briandesarmo commented 1 year ago

Doesn't your sample set MaxDepth to int.MaxValue? That basically removes the limit.

Yes we are trying to use it without a limit.

briandesarmo commented 1 year ago

If the example code is modified to omit the MetadataPropertyHandling.ReadAhead an exception is no longer thrown. This is likely the same issue as reported in #2858 https://dotnetfiddle.net/8lXCu3