FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

ILC crash with runtime-async enabled calling JsonSerializer.DeserializeAsync<T>(...) from a generic method in NativeAOT · Issue #127179 · dotnet/runtime · GitHub

/ runtime Public

ILC crash with runtime-async enabled calling JsonSerializer.DeserializeAsync<T>(...) from a generic method in NativeAOT #127179

Description

Description

When the runtime-async feature is enabled in .NET 11 Preview 3 (11.0.100-preview.3.26207.106), compiling a NativeAOT application fails with an ILC crash if a generic method calls JsonSerializer.DeserializeAsync<T> passing a JsonTypeInfo<T> instance, where T is a generic type parameter. This pattern is commonly used for deserializing JSON into generic types (see minimal example below).

This is being hit in npgsql/npgsql#6488.

Related discussion: npgsql/npgsql#6488 (comment)


Minimal reproducing code

sealed class ReproConverter<T, TBase> where T : TBase?
{
    readonly JsonTypeInfo _jsonTypeInfo;

    public async ValueTask<T?> ReadAsync(bool async, Stream stream, CancellationToken cancellationToken)
    {
        return _jsonTypeInfo switch
        {
            // ❌ ILC crash with runtime-async enabled:
            JsonTypeInfo<T> typeInfoOfT => async
                ? await JsonSerializer.DeserializeAsync(stream, typeInfoOfT, cancellationToken).ConfigureAwait(false)
                : JsonSerializer.Deserialize(stream, typeInfoOfT),
            _ => (T?)(async
                ? await JsonSerializer.DeserializeAsync(stream, (JsonTypeInfo<TBase?>)_jsonTypeInfo, cancellationToken).ConfigureAwait(false)
                : JsonSerializer.Deserialize(stream, (JsonTypeInfo<TBase?>)_jsonTypeInfo))
        };
    }
}

See full minimal repro project for instructions and code: https://github.com/manandre/repro-dotnet-runtime-async-aot-json

Reproduction Steps

cd ReproAsyncAotJson

Run publish with runtime-async enabled (default):

dotnet publish -c Release           # fails

Run publish with runtime-async disabled:

dotnet publish -c Release -p:RuntimeAsync=false   # succeeds

Expected behavior

NativeAOT compilation should succeed when calling JsonSerializer.DeserializeAsync<T> in the described scenario.

Actual behavior

ILC crashes with the following error and stack trace:

EXEC : error : One or more errors occurred. (Code generation failed for method '[Npgsql]Npgsql.Internal.Converters.JsonConverter`2<System.__Canon,System.__Canon>.Read(bool,PgReader,CancellationToken)') [test/Npgsql.NativeAotTests/Npgsql.NativeAotTests.csproj::TargetFramework=net11.0]
  System.AggregateException: One or more errors occurred. (Code generation failed for method '[Npgsql]Npgsql.Internal.Converters.JsonConverter`2<System.__Canon,System.__Canon>.Read(bool,PgReader,CancellationToken)')
   ---> ILCompiler.CodeGenerationFailedException: Code generation failed for method '[Npgsql]Npgsql.Internal.Converters.JsonConverter`2<System.__Canon,System.__Canon>.Read(bool,PgReader,CancellationToken)'
   ---> System.InvalidOperationException: [Npgsql]Npgsql.Internal.Converters.JsonConverter`2<System.__Canon,System.__Canon>: MethodDictionary: [System.Text.Json]System.Text.Json.JsonSerializer.DeserializeAsync<__Canon>(Stream,JsonTypeInfo`1<__Canon>,CancellationToken)
     at ILCompiler.DependencyAnalysis.PrecomputedDictionaryLayoutNode.TryGetSlotForEntry(GenericLookupResult, Int32&)
     at ILCompiler.Compilation.ComputeGenericLookup(MethodDesc, ReadyToRunHelperId, Object)
     at Internal.JitInterface.CorInfoImpl.ComputeLookup(CORINFO_RESOLVED_TOKEN&, Object, ReadyToRunHelperId, MethodDesc, CORINFO_LOOKUP&)
     at Internal.JitInterface.CorInfoImpl._embedGenericHandle(IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, Byte, CORINFO_METHOD_STRUCT_*, CORINFO_GENERICHANDLE_RESULT*)
     --- End of inner exception stack trace ---
     at Internal.JitInterface.CorInfoImpl.CompileMethodInternal(IMethodNode, MethodIL)
     at ILCompiler.RyuJitCompilation.CompileSingleMethod(CorInfoImpl, MethodCodeNode)
     at Internal.JitInterface.CorInfoImpl.CompileSingleMethod(MethodCodeNode)
     at System.Threading.Tasks.Parallel.<>c__DisplayClass19_0`2.<ForWorker>b__1(RangeWorker&, Int64, Boolean&)
  --- End of stack trace from previous location ---
     at System.Threading.Tasks.Parallel.ThrowSingleCancellationExceptionOrOtherException(ICollection, CancellationToken, Exception)
     at System.Threading.Tasks.Parallel.ForWorker[TLocal,TInt](TInt, TInt, ParallelOptions, Action`1, Action`2, Func`4, Func`1, Action`1)
     at ILCompiler.RyuJitCompilation.CompileMultiThreaded(List`1)
     at ILCompiler.RyuJitCompilation.ComputeDependencyNodeDependencies(List`1)
     at ILCompiler.DependencyAnalysisFramework.DependencyAnalyzer`2.ComputeMarkedNodes()
     at ILCompiler.RyuJitCompilation.CompileInternal(String, ObjectDumper)
     at ILCompiler.Compilation.ILCompiler.ICompilation.Compile(String, ObjectDumper)
     at ILCompiler.Program.Run()
     at ILCompiler.ILCompilerRootCommand.<>c__DisplayClass264_0.<.ctor>b__0(ParseResult)
/home/runner/.nuget/packages/microsoft.dotnet.ilcompiler/11.0.0-preview.3.26207.106/build/Microsoft.NETCore.Native.targets(311,5): error MSB3073: The command ".../ilc ..." exited with code 1. [test/Npgsql.NativeAotTests/Npgsql.NativeAotTests.csproj::TargetFramework=net11.0]

Regression?

Unknown.
This specific crash appears in .NET 11 Preview 3 and is triggered by the new runtime-async implementation. This code pattern was not previously published using runtime-async + NativeAOT.

Known Workarounds

Cast the type info to the non-generic base JsonTypeInfo and use the non-generic overload:

JsonTypeInfo<T> typeInfoOfT => (T?)(async
    ? await JsonSerializer.DeserializeAsync(stream, (JsonTypeInfo)typeInfoOfT, cancellationToken).ConfigureAwait(false)
    : JsonSerializer.Deserialize(stream, (JsonTypeInfo)typeInfoOfT),

This sacrifices type-safety and should not be required.

Configuration

.NET SDK: 11.0.100-preview.3.26207.106
OS: Linux x64 (GitHub Actions), reproduces locally and in CI
Repro: https://github.com/manandre/repro-dotnet-runtime-async-aot-json

Other information

First hit when integrating runtime-async feature in Npgsql (the .NET data provider for PostgreSQL). PR: npgsql/npgsql#6488

Area labels: area-System.Text.Json, area-NativeAOT-coreclr, runtime-async

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status
    No status

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


    Back | FazBrowse Home | New Git URL