Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[System.Text.Json] UnsafeRelaxedJsonEscaping can result in StackOverflowException #30814

Closed
pranavkm opened this issue Sep 10, 2019 · 15 comments · Fixed by dotnet/corefx#40996
Closed
Assignees
Milestone

Comments

@pranavkm
Copy link
Contributor

var test = new { Name = "测试11" };
Console.WriteLine(JsonSerializer.Serialize(test, new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }));

Here's what's causing the StackOverflow:

image


Original text:

From @Zonciu on Tuesday, September 10, 2019 2:16:16 PM

Describe the bug

WebApi returning specific content cause stack overflow

To Reproduce

Reproduction project

WebApplication.zip

Steps to reproduce the behavior:

  1. Using this version of NET Core 3.0 Preview 9
  2. dotnet new webapi
  3. Add controller methods:
    public class Test
    {
        public string Name { get; set; }
    }

    [ApiController]
    [Route("test")]
    public class TestController : ControllerBase
    {
        [HttpGet("1")]
        public Test Get([FromServices] ILogger<Test> logger)
        {
            logger.LogInformation("Get test 2");
            return new Test {Name = "测试"};
        }

        [HttpGet("2")]
        public Test Get2([FromServices] ILogger<Test> logger)
        {
            logger.LogInformation("Get test 2");
            return new Test {Name = "测试11"};
        }
    }
  1. Access /test/1 is ok, but /test/2 causing stack overflow and crashed.

Expected behavior

Access /test/2, return {"name":"测试1"}

Screenshots

/test/1
image

/test/2
image

Additional context

dotnet --info output

.NET Core SDK(反映任何 global.json):
 Version:   3.0.100-preview9-014004
 Commit:    8e7ef240a5

运行时环境:
 OS Name:     Windows
 OS Version:  10.0.17763
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\3.0.100-preview9-014004\

Host (useful for support):
  Version: 3.0.0-preview9-19423-09
  Commit:  2be172345a

.NET Core SDKs installed:
  2.1.801 [C:\Program Files\dotnet\sdk]
  3.0.100-preview9-014004 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0-preview9.19424.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0-preview9-19423-09 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.0.0-preview9-19423-09 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Copied from original issue: dotnet/aspnetcore#13856

@pranavkm
Copy link
Contributor Author

From @rynowak on Tuesday, September 10, 2019 2:51:25 PM

@ahsonkhan - the only differnce between these cases appears to be the text.

@pranavkm
Copy link
Contributor Author

From @mkArtakMSFT on Tuesday, September 10, 2019 4:00:42 PM

@rynowak I can repro this. yes, the only difference is the text.

@pranavkm
Copy link
Contributor Author

From @mkArtakMSFT on Tuesday, September 10, 2019 4:01:06 PM

Thanks for reporting this, @Zonciu.

@pranavkm
Copy link
Contributor Author

From @mkArtakMSFT on Tuesday, September 10, 2019 4:04:23 PM

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET http://localhost:5000/test/2
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'WebApplication.Controllers.TestController.Get2 (WebApplication)'
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[3]
      Route matched with {action = "Get2", controller = "Test"}. Executing controller action with signature WebApplication.Controllers.Test Get2(Microsoft.Extensions.Logging.ILogger`1[WebApplication.Controllers.Test]) on controller WebApplication.Controllers.TestController (WebApplication).
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
      Executing action method WebApplication.Controllers.TestController.Get2 (WebApplication) - Validation state: Valid
info: WebApplication.Controllers.Test[0]
      Get test 2
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2]
      Executed action method WebApplication.Controllers.TestController.Get2 (WebApplication), returned result Microsoft.AspNetCore.Mvc.ObjectResult in 2.2163ms.
info: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[1]
      Executing ObjectResult, writing value of type 'WebApplication.Controllers.Test'.
Stack overflow.

C:\Users\artakm\Desktop\repro\bin\Debug\netcoreapp3.0\WebApplication.exe (process 24844) exited with code -1073741819.

@pranavkm
Copy link
Contributor Author

From @pranavkm on Tuesday, September 10, 2019 4:27:00 PM

Here's the minimal repro step without MVC involved:

var test = new { Name = "测试11" };
Console.WriteLine(JsonSerializer.Serialize(test, new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }));

Here's what's causing the StackOverflow:

image

It's specifically the UnsafeRelaxedJsonEncoding which is what MVC uses by default for Json serialization.

@pranavkm pranavkm changed the title WebApi return specific content cause stack overflow UnsafeRelaxedJsonEscaping can result in StackOverflowException Sep 10, 2019
@pranavkm pranavkm changed the title UnsafeRelaxedJsonEscaping can result in StackOverflowException [System.Text.Json] UnsafeRelaxedJsonEscaping can result in StackOverflowException Sep 10, 2019
@ericstj
Copy link
Member

ericstj commented Sep 10, 2019

Let's try to get this in 3.0. @ahsonkhan can you take a look.

@pranavkm
Copy link
Contributor Author

pranavkm commented Sep 10, 2019

@Zonciu, in the meanwhile, you could configure MVC to use the default JavaScriptEncoder which works around this particular instance of the issue:

// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Default);
}

@ahsonkhan
Copy link
Member

ahsonkhan commented Sep 11, 2019

you could configure MVC to use the default JavaScriptEncoder which works around this particular instance of the issue

@Zonciu, note, that particular workaround wouldn't work in general. I couldn't come up with a good workaround for the bug. Please re-try with the latest changes/nightly build and verify the issue has been fixed for your scenario. Otherwise, re-open the issue.

Fixed in master by dotnet/corefx#40996, and in release by dotnet/corefx#40997

@Zonciu
Copy link

Zonciu commented Sep 11, 2019

@ahsonkhan @pranavkm For now I use AddControllers().AddNewtonsoftJson(), that works fine.

@ahsonkhan
Copy link
Member

That works too. Let me know when you revert back to using the built-in serializer and if you find any bugs/issues or have some feedback to share.

@xcaptain
Copy link

I have the same issue using Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping to serialize an object causes a stack overflow, is this bug fixed? I'm using dotnet core 3 preview 9

@Zonciu
Copy link

Zonciu commented Sep 19, 2019

@xcaptain It has been fixed in nightly build, but not in 3.0 rc1

@xcaptain
Copy link

I'm still having this issue even I upgraded to 3.0 rc1

图片

My code is at https://dotnetfiddle.net/5rUTaW

if I change the Name to other string it runs. @Zonciu can you help test my case?

@Zonciu
Copy link

Zonciu commented Sep 19, 2019

@xcaptain 3.0 rc1 doesn't contain this fix, you need to use Newtonsoft.Json, or try the daily build
I'd tested it in docker (nightly build 09/17/2019), it works.

@xcaptain
Copy link

@Zonciu Thanks

@msftgits msftgits transferred this issue from dotnet/corefx Feb 1, 2020
@msftgits msftgits added this to the 3.0 milestone Feb 1, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 12, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
6 participants