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 when set MetadataPropertyHandling.ReadAhead #2858

Open jixinwang01 opened 1 year ago

jixinwang01 commented 1 year ago

Source/destination types

private object? CreateObject(JsonReader reader, Type? objectType, JsonContract? contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerMember, object? existingValue)
        {
            string? id;
            Type? resolvedObjectType = objectType;

            if (Serializer.MetadataPropertyHandling == MetadataPropertyHandling.Ignore)
            {
                // don't look for metadata properties
                reader.ReadAndAssert();
                id = null;
            }
            else if (Serializer.MetadataPropertyHandling == MetadataPropertyHandling.ReadAhead)
            {
                if (!(reader is JTokenReader tokenReader))
                {
                    JToken t = JToken.ReadFrom(reader);
                    tokenReader = (JTokenReader)t.CreateReader();
                    tokenReader.Culture = reader.Culture;
                    tokenReader.DateFormatString = reader.DateFormatString;
                    tokenReader.DateParseHandling = reader.DateParseHandling;
                    tokenReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
                    tokenReader.FloatParseHandling = reader.FloatParseHandling;
                    tokenReader.SupportMultipleContent = reader.SupportMultipleContent;

                    // start
                    tokenReader.ReadAndAssert();

                    reader = tokenReader;
                }

                if (ReadMetadataPropertiesToken(tokenReader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out object? newValue, out id))
                {
                    return newValue;
                }
            }

        protected JsonReader()
        {
            _currentState = State.Start;
            _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
            _dateParseHandling = DateParseHandling.DateTime;
            _floatParseHandling = FloatParseHandling.Double;
            _maxDepth = 64;

            CloseInput = true;
        }

Expected behavior

MaxDepth is used with ISerializable deserialization when JsonSerializerSettings.MetadataPropertyHandling set MetadataPropertyHandling.ReadAhead

Actual behavior

Create new JTokenReader object and can't copy JsonReader MaxDepth to this object

tokenReader.MaxDepth = reader.MaxDepth;

Steps to reproduce

 config.Formatters.JsonFormatter.SerializerSettings.MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead;
 config.Formatters.JsonFormatter.SerializerSettings.MaxDepth = 256;
elgonzo commented 1 year ago

Nice find!

This might also quite possibly be related to or being the underlying root cause of the recently reported issue https://github.com/JamesNK/Newtonsoft.Json/issues/2850.

jixinwang01 commented 1 year ago

So when will this issue be fixed if we insist on using this attribute MetadataPropertyHandling.ReadAhead

jixinwang01 commented 1 year ago

hi elgonzo, briandesarmo

Haven't any else update?

Thanks.

briandesarmo commented 1 year ago

hi elgonzo, briandesarmo

Haven't any else update?

Thanks.

We are working around this bug by using the MetadataPropertyHandling default, instead of MetadataPropertyHandling.ReadAhead.

EmiyaKiritsuguZz commented 11 months ago

Anyone can help on this issue?

ratneshdubeysolidatus commented 6 months ago

I tried to update the MaxDepth but takes 64 as default and still facing the same issue here is the exception trace

[Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware] [bd577466 ERR] [0HN23UCMHFS3P:00000003] [::1] An unhandled exception has occurred while executing the request.
System.InvalidOperationException: Current error context error is different to requested error.
   at ErrorContext Newtonsoft.Json.Serialization.JsonSerializerInternalBase.GetErrorContext(object currentObject, object member, string path, Exception error)
   at bool Newtonsoft.Json.Serialization.JsonSerializerInternalBase.IsErrorHandled(object currentObject, JsonContract contract, object keyValue, IJsonLineInfo lineInfo, string path, Exception ex)
   at object Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, bool checkAdditionalContent)
   at object Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at async Task<InputFormatterResult> Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
   at async Task<InputFormatterResult> Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
   at async Task Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)
   at async ValueTask<ModelBindingResult> Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, object value, object container)
   at void Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider+<>c__DisplayClass0_0+<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
   at async Task Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()+Awaited(?)
   at async Task Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeNextResourceFilter()+Awaited(?)
   at void Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Task Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
   at async Task Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()+Awaited(?)
   at async Task Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeAsync()+Awaited(?)
   at async Task Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeAsync()+Awaited(?)
   at async Task Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at async Task Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at async Task Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at async Task Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at async Task Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at async Task IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events, IBackChannelLogoutService backChannelLogoutService)
   at async Task IdentityServer4.Hosting.MutualTlsEndpointMiddleware.Invoke(HttpContext context, IAuthenticationSchemeProvider schemes)
   at async Task Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at async Task IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext context)

The data that I am passing is 32 levels deep but due to the [FromBody] attribute in the parameter it read more than 64 and caused the above exception.

when will this issue be fixed? Thanks