Skip to content

Resolve dllimport.cpp runtimeasync todos - #122466

Merged
jkoritzinsky merged 9 commits into
dotnet:mainfrom
jkoritzinsky:runtime-async-dllimport
Dec 27, 2025
Merged

Resolve dllimport.cpp runtimeasync todos#122466
jkoritzinsky merged 9 commits into
dotnet:mainfrom
jkoritzinsky:runtime-async-dllimport

Conversation

@jkoritzinsky

@jkoritzinskyjkoritzinsky commented Dec 11, 2025

Copy link
Copy Markdown
Member

Roslyn should never mark a P/Invoke or a delegate's Invoke method as an async method, so there's not a good way to add tests without writing them in IL and it doesn't seem particularly useful to do so.

Fixes#121758

@github-actionsgithub-actionsBot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Dec 11, 2025
@jkoritzinskyjkoritzinsky added area-Interop-coreclr runtime-async and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Dec 11, 2025

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR resolves TODOs related to async method handling in the P/Invoke implementation. The changes replace placeholder TODO comments with explanatory comments about why async methods are not supported for P/Invoke scenarios, convert some assertions to preconditions, and adjust error handling in one case to defer exception throwing to the IL stub generation path.

Key changes:

  • Adds PRECONDITION checks for async methods in constructor contracts and function preconditions
  • Replaces TODO comments with clarifying comments explaining that async P/Invoke methods should use async variant stubs that call task-returning interop stubs
  • Changes MarshalingRequired to return TRUE for async methods (to trigger proper exception later) instead of throwing immediately

Comment threadsrc/coreclr/vm/dllimport.cpp
Comment threadsrc/coreclr/vm/dllimport.cpp
Comment threadsrc/coreclr/vm/dllimport.cpp Outdated
@VSadov

Copy link
Copy Markdown
Member

Roslyn should never mark a P/Invoke or a delegate's Invoke method as an async method

Interestingly it allows Synchronized.
Like:

[MethodImpl(MethodImplOptions.Synchronized)][DllImport("kernel32.dll")]privatestaticexternboolQueryPerformanceFrequency(outlongfrequency);

It results in

Unhandled exception. System.TypeLoadException: Synchronized attribute cannot be used with this method type.
at Program.Main()

Perhaps MethodImplOptions.Async should result in a similar error.

In theory we could just ignore Async on DllImport methods, since we spec'd it as

The [MethodImpl(MethodImplOptions.Async)] only has effect when applied to method definitions with CIL implementation.

The runtime could be more strict than the spec and making it an error as it is the case with Synchronized might be more consistent.

@VSadov

Copy link
Copy Markdown
Member

I can think of only two ways to get async involved with DllImport.

  • Non-task Async method.

Roslyn does not like adding Async outside of corlib/AsyncHelpers, but should be possible in IL.
Perhaps should produce the same error as with Synchronized

The runtime also does not allow non-task Async methods outside of corlib, so maybe that will error out first.

[MethodImpl(MethodImplOptions.Async)][DllImport("kernel32.dll")]privatestaticexternboolQueryPerformanceFrequency(outlongfrequency);
  • Task-returning pinvokes:
[DllImport("kernel32.dll")]privatestaticexternTaskQueryPerformanceFrequency(outlongfrequency);[DllImport("kernel32.dll")]privatestaticexternValueTaskQueryPerformanceCounter(outlongcounter);

I am not sure if either of above can work right now.
Ideally the behavior with async enabled should be the same.

@jkoritzinsky

Copy link
Copy Markdown
MemberAuthor

@VSadov good point on MethodImpl attribute. I'll add some tests to make sure we don't crash.

@jkoritzinsky

Copy link
Copy Markdown
MemberAuthor

@VSadov I've rewritten this PR to have the following implementation:

Loading a P/Invoke with the async bit set fails to load.

The async variant for a P/Invoke method (if even usable) will not be considered a P/Invoke (similar to how we handled this for COM interop).

Jitting a method with UnmanagedCallersOnly with the async bit set fails with InvalidProgramException.

dllimport.cpp asserts that it never sees a method with the async bit set.

@VSadov

VSadov commented Dec 16, 2025

Copy link
Copy Markdown
Member

The [MethodImpl(MethodImplOptions.Async)] + [DllImport] scenario could be hard to test since Roslyn would not allow MethodImplOptions.Async on random methods.

The scenario like the following is testable though. It is also a preexisting scenario, so regression is a bigger deal. Perhaps we should have a test.

[DllImport("kernel32.dll")]privatestaticexternTaskQueryPerformanceFrequency(outlongfrequency);[DllImport("kernel32.dll")]privatestaticexternValueTaskQueryPerformanceCounter(outlongcounter);

Otherwise looks good to me.

Comment threadsrc/coreclr/dlls/mscorrc/mscorrc.rc Outdated
Comment threadsrc/coreclr/vm/methodtablebuilder.cpp Outdated
Comment threadsrc/coreclr/vm/comdelegate.cpp
Comment threadsrc/coreclr/vm/methodtablebuilder.cpp Outdated
Comment threadsrc/coreclr/dlls/mscorrc/resource.h Outdated

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@jkoritzinsky
jkoritzinsky merged commit 82562bb into dotnet:mainDec 27, 2025
144 of 146 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jan 26, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[RuntimeAsync] 6 TODOs in dllimport.cpp

4 participants

@jkoritzinsky@VSadov@jkotas