Runtime: [System.Text.Json] UnsafeRelaxedJsonEscaping can result in StackOverflowException

Created on 10 Sep 2019  ·  15Comments  ·  Source: dotnet/runtime

```C#
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](https://user-images.githubusercontent.com/174281/64631901-ef0db780-d3ac-11e9-9bca-563841083e8a.png)

---------------------------------------------------
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](https://github.com/aspnet/AspNetCore/files/3596081/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"};
    }
}
4. 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](https://user-images.githubusercontent.com/10374056/64621218-e0101f00-d417-11e9-9fce-86ad3da7e051.png)


/test/2
![image](https://user-images.githubusercontent.com/10374056/64621165-cbcc2200-d417-11e9-9261-f6861d1708dd.png)


### 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: aspnet/AspNetCore#13856_

area-System.Text.Json

Most helpful comment

@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.

All 15 comments

_From @rynowak on Tuesday, September 10, 2019 2:51:25 PM_

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

_From @mkArtakMSFT on Tuesday, September 10, 2019 4:00:42 PM_

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

_From @mkArtakMSFT on Tuesday, September 10, 2019 4:01:06 PM_

Thanks for reporting this, @Zonciu.

_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.

_From @pranavkm on Tuesday, September 10, 2019 4:27:00 PM_

Here's the minimal repro step without MVC involved:

C# 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.

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

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

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

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 https://github.com/dotnet/corefx/pull/40996, and in release by https://github.com/dotnet/corefx/pull/40997

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

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.

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

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

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?

@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.

@Zonciu Thanks

Was this page helpful?
0 / 5 - 0 ratings