Skip to content

Console.WriteLine hangs in ASP.NET Core NativeAOT when published as Library and invoked via P/Invoke #118773

@lindexi

Description

@lindexi

Description

When an ASP.NET Core Native AOT project is changed to OutputType=Library and its startup logic is invoked via P/Invoke from another process, any call to Console.WriteLine (or other Console APIs) causes the execution to hang. The ASP.NET Core host never finishes starting and no port is bound.

Reproduction Steps

  1. Create project from official template (per https://learn.microsoft.com/en-us/aspnet/core/fundamentals/native-aot?view=aspnetcore-9.0):

dotnet new webapiaot -n Lib1

  1. Change the project to library output (csproj: <OutputType>Library</OutputType>).
  2. Move the original Program.cs logic into a static Start method:
public static class Program
{
    [UnmanagedCallersOnly(EntryPoint = "Start", CallConvs = [typeof(CallConvCdecl)])]
    public static int Start()
    {
        Console.WriteLine($"Start run");

        Task.Run(StartInner);

        return 2;
    }

    private static void StartInner()
    {
        var builder = WebApplication.CreateSlimBuilder([]);

        builder.Services.ConfigureHttpJsonOptions(options =>
        {
            options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
        });

        var app = builder.Build();

        var sampleTodos = new Todo[]
        {
            new(1, "Walk the dog"),
            new(2, "Do the dishes", DateOnly.FromDateTime(DateTime.Now)),
            new(3, "Do the laundry", DateOnly.FromDateTime(DateTime.Now.AddDays(1))),
            new(4, "Clean the bathroom"),
            new(5, "Clean the car", DateOnly.FromDateTime(DateTime.Now.AddDays(2)))
        };

        var todosApi = app.MapGroup("/todos");
        todosApi.MapGet("/", () => sampleTodos);
        todosApi.MapGet("/{id}", (int id) =>
            sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
                ? Results.Ok(todo)
                : Results.NotFound());

        app.Run();
    }
}
  1. Publish Native AOT:dotnet publish -r win-x64 Lib1/Lib1.csproj
  2. Create a new console application that invokes the exported entry via P/Invoke:
using System.Runtime.InteropServices;

var result = Start();
Console.WriteLine("Hello, World!");

[DllImport("Lib1.dll")]
static extern int Start();
  1. Run the console app. Execution hangs; ASP.NET Core does not start and no port is listening. Debugging shows the call stack:
 	ntdll.dll!00007ffd21881e54()	
 	KernelBase.dll!WaitForSingleObjectEx()	
 	Lib1.dll!S_P_CoreLib_System_Threading_Thread__JoinInternal() Line 166	
 	Lib1.dll!S_P_CoreLib_System_Threading_Thread__StartCore() Line 383	
 	Lib1.dll!S_P_CoreLib_System_Diagnostics_Tracing_CounterGroup__EnableTimer() Line 177	
 	Lib1.dll!S_P_CoreLib_System_Diagnostics_Tracing_CounterGroup__OnEventSourceCommand() Line 73	
 	Lib1.dll!S_P_CoreLib_System_Diagnostics_Tracing_EventSource__DoCommand() Line 2780	
 	Lib1.dll!S_P_CoreLib_System_Diagnostics_Tracing_EventSource__Initialize() Line 1732	
 	Lib1.dll!S_P_CoreLib_System_Diagnostics_Tracing_RuntimeEventSource___ctor_0() Line 12	
 	Lib1.dll!S_P_CoreLib_System_Diagnostics_Tracing_RuntimeEventSource___cctor() Line 27	
 	Lib1.dll!S_P_CoreLib_System_Runtime_CompilerServices_ClassConstructorRunner__EnsureClassConstructorRun() Line 93	
 	Lib1.dll!S_P_CoreLib_System_Runtime_CompilerServices_ClassConstructorRunner__CheckStaticClassConstructionReturnGCStaticBase() Line 36	
 	Lib1.dll!S_P_CoreLib_System_Diagnostics_Tracing_EventSource__InitializeDefaultEventSources() Line 3890	
 	Lib1.dll!S_P_CoreLib_Internal_Runtime_CompilerHelpers_StartupCodeHelpers__RunInitializers() Line 177	
 	Lib1.dll!S_P_CoreLib_Internal_Runtime_CompilerHelpers_StartupCodeHelpers__RunModuleInitializers() Line 165	
 	Lib1.dll!Internal_CompilerGenerated__Module___NativeLibraryStartup()	
 	Lib1.dll!InitializeRuntime() Line 210	C++
 	[Inline] Lib1.dll!Thread::EnsureRuntimeInitialized() Line 1225	C++
 	[Inline] Lib1.dll!Thread::ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame *) Line 1187	C++
 	Lib1.dll!RhpReversePInvokeAttachOrTrapThread2(ReversePInvokeFrame * pFrame=0x000000f9fa37ecf0) Line 1306	C++
>	Lib1.dll!Lib1_Lib1_Program__Start() Line 11	
 	App1.dll!Program.<Main>$(string[] args = {string[0]}) Line 5	C#
 	hostpolicy.dll!00007ffc6f70e93b()	
 	hostpolicy.dll!00007ffc6f70ec1c()	
 	hostpolicy.dll!00007ffc6f70f553()	
 	hostfxr.dll!00007ffcff16d8a6()	
 	hostfxr.dll!00007ffcff16fe05()	
 	hostfxr.dll!00007ffcff171eb2()	
 	hostfxr.dll!00007ffcff1703d2()	
 	hostfxr.dll!00007ffcff168580()	
 	App1.exe!exe_start(const int argc=1, const wchar_t * * argv=0x000002c3f68d4560) Line 253	C++
 	App1.exe!wmain(const int argc, const wchar_t * * argv=0x000002c3f68d4560) Line 324	C++
 	[Inline] App1.exe!invoke_main() Line 90	C++
 	App1.exe!__scrt_common_main_seh() Line 288	C++
 	kernel32.dll!00007ffd206de8d7()	
 	ntdll.dll!00007ffd2175c34c()	

Full minimal repro: https://github.com/lindexi/lindexi_gd/tree/ede2d237c50b121b9ad36e03f7578f9b9e674bf7/Workbench/FurhocecaiqayYearwedalofawrair

And you can clone my code by the commands:

git init
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin ede2d237c50b121b9ad36e03f7578f9b9e674bf7

After cloning:

  1. Navigate to: Workbench/FurhocecaiqayYearwedalofawrair
  2. Publish the library:
    dotnet publish -r win-x64 Lib1/Lib1.csproj
  3. Build and run the App1 project.
  4. Observe the hang after the 5th line in the library startup.

Expected behavior

ASP.NET Core can run well.

Actual behavior

The ASP.NET Core was hangs.

Regression?

No response

Known Workarounds

No response

Configuration

.NET Version: 9.0.7

OS: Windows 11 x64

Other information

Reference: #91762

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions