Skip to content

Add [RequiresUnsafe] to all extern and LibraryImport methods (CoreLib) + IL5005/IL5006 diagnostics#125894

Open
Copilot wants to merge 8 commits intomainfrom
copilot/handle-pr-125880-feedback
Open

Add [RequiresUnsafe] to all extern and LibraryImport methods (CoreLib) + IL5005/IL5006 diagnostics#125894
Copilot wants to merge 8 commits intomainfrom
copilot/handle-pr-125880-feedback

Conversation

Copy link
Contributor

Copilot AI commented Mar 21, 2026

This PR takes over #125880 and implements all the items from the original PR description while addressing reviewer feedback.

Description

What this PR does

  1. New IL5005 diagnostic — Issues IL5005 for extern methods without [RequiresUnsafe] on them. (IL5004 already exists for pointer-type signatures.)

  2. New IL5006 diagnostic — Issues IL5006 for [LibraryImport] partial methods without [RequiresUnsafe] on them.

  3. Extends the code-fixerUnsafeMethodMissingRequiresUnsafeCodeFixProvider now also offers to add [RequiresUnsafe] when IL5005 or IL5006 is reported (for extern/[LibraryImport] methods).

  4. Suppresses IL5000 repo-wide — The "api with [RequiresUnsafe] is invoked in a safe context" warning is temporarily disabled. We'll re-enable it once we're ready to do so - there are way too many new unsafe {} scopes to add. IL5004/IL5005/IL5006 remain active to prevent regressions.

  5. Adds [RequiresUnsafe] to all CoreLib methods — All [LibraryImport] and [UnsafeAccessor] extern methods in System.Private.CoreLib are now annotated.

  6. Creates RequiresUnsafeAttribute polyfill - since many files are compiled for NS2.0/NETFX targets. The polyfill in Directory.Build.targets excludes shim/facade/ref/PNSE assemblies that must only contain type-forwards.

  7. LibraryImportGenerator emits [RequiresUnsafe] — The generator now emits [global::System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute] on the generated __PInvoke extern local function. This is conditional on RequiresUnsafeAttribute being defined in the compilation being built (checked via Compilation.Assembly equality), so external projects without the polyfill are unaffected.

  8. Refactored analyzer detection methodsGetExternOrLibraryImportRule was refactored into two focused boolean methods: IsExtern(IMethodSymbol) and IsLibraryImport(IMethodSymbol) for clearer separation of concerns.

Not done (tracked in PR description)

  1. Non-CoreLib (analyzers only enabled for CoreLib currently per Add analyzer+codefix for applying RequiresUnsafe to pointer methods #125196)
  2. MethodImplOptions.InternalCall exempted with a TODO — too many safe APIs with InternalCall (all Math.* etc.)
  3. Maybe some pinvokes could be marked [RequiresUnsafe(false)] if that overload is ever introduced
  4. INFO severity is used (just like for the existing 5004) - we need to agree on a way how we can annotate safe APIs: either via #pragma warning disable or introduce [RequiresUnsafe(false)]

⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.

Copilot AI and others added 3 commits March 21, 2026 20:46
…add IL5005 analyzer + code fix + tests

Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/95dc0f33-5a80-4f50-9ecd-51682f5f449a
… IL prefix note in DiagnosticId.cs

Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/95dc0f33-5a80-4f50-9ecd-51682f5f449a
…t.Bcl.Memory.csproj (Directory.Build.targets now handles it); fix style nit

Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/95dc0f33-5a80-4f50-9ecd-51682f5f449a
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

@EgorBo
Copy link
Member

EgorBo commented Mar 21, 2026

@copilot please split ExternMethodMissingRequiresUnsafe (IL5005) into two: for extern and IL5006 for LibraryImport

…rn and IL5006 for LibraryImport

Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/1f6e08a2-50a6-46c6-ba5c-8d9d168f3afd
Copy link
Contributor Author

Copilot AI commented Mar 21, 2026

@copilot please split ExternMethodMissingRequiresUnsafe (IL5005) into two: for extern and IL5006 for LibraryImport

Done in d5e10fb. Split into:

  • ExternMethodMissingRequiresUnsafe (IL5005) — for extern methods
  • LibraryImportMethodMissingRequiresUnsafe (IL5006) — for [LibraryImport] methods

Each has its own diagnostic descriptor, strings in SharedStrings.resx, and the test for LibraryImport now asserts DiagnosticId.LibraryImportMethodMissingRequiresUnsafe. All 62 RequiresUnsafe tests pass.

Copilot AI changed the title Add [RequiresUnsafe] to all extern and LibraryImport methods (CoreLib) + IL5005 diagnostic Add [RequiresUnsafe] to all extern and LibraryImport methods (CoreLib) + IL5005/IL5006 diagnostics Mar 21, 2026
@EgorBo
Copy link
Member

EgorBo commented Mar 21, 2026

@copilot update LibraryImportGenerator to emit [RequiresUnsafe] over the extern member it might generate (is it __Pinvoke)

…_PInvoke extern method

Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e0346bc4-ee44-4840-92fd-f9f8157089b6
Copy link
Contributor Author

Copilot AI commented Mar 21, 2026

@copilot update LibraryImportGenerator to emit [RequiresUnsafe] over the extern member it might generate (is it __Pinvoke)

Done in bce5280. The LibraryImportGenerator now emits [global::System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute] on the generated __PInvoke extern local function. The attribute is only emitted when RequiresUnsafeAttribute is defined in the compilation being built (checked via Compilation.Assembly equality), so external projects without the polyfill won't be affected. All 702 LibraryImportGenerator unit tests and 62 RequiresUnsafe analyzer tests pass.

@EgorBo
Copy link
Member

EgorBo commented Mar 22, 2026

@copilot please investigate the CI failures if they're related to these changes.

…te polyfill include

Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/068e4204-ee25-490f-8b8b-9f150fb14a92
Copy link
Contributor Author

Copilot AI commented Mar 22, 2026

@copilot please investigate the CI failures if they're related to these changes.

Investigated and fixed the PR-related failure in 3833b0a.

ShimsHaveOnlyTypeForwards test failures (12 jobs) — PR-related, now fixed. The Directory.Build.targets polyfill was unconditionally added to ALL .csproj files, including shim assemblies (mscorlib, System.Threading.Overlapped) that must contain only type-forwards. Fixed by adding conditions to exclude IsPartialFacadeAssembly, IsReferenceAssemblyProject, PNSE assemblies, and shim directory projects.

ThreadPoolBoundHandle CS0260 build errors (2 WASM multithreaded jobs) — Pre-existing, NOT related to this PR. Both ThreadPoolBoundHandle.PlatformNotSupported.cs (non-partial) and ThreadPoolBoundHandle.Browser.Threads.cs (partial) are included for WASM multithreaded builds, causing a conflict. None of these files were touched by this PR.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • helixr1107v0xdcypoyl9e7f.blob.core.windows.net
    • Triggering command: /usr/bin/pwsh pwsh .github/skills/ci-analysis/scripts/Get-CIStatus.ps1 -PRNumber 125894 -ShowLogs -MaxJobs 10 (dns block)
  • helixr1107v0xdeko0k025g8.blob.core.windows.net
    • Triggering command: /usr/bin/pwsh pwsh .github/skills/ci-analysis/scripts/Get-CIStatus.ps1 -PRNumber 125894 -ShowLogs -MaxJobs 10 (dns block)
    • Triggering command: /usr/bin/curl curl -sL REDACTED (dns block)
    • Triggering command: /usr/bin/curl curl -sL -o /tmp/helix-log.txt REDACTED (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@EgorBo
Copy link
Member

EgorBo commented Mar 22, 2026

@copilot please refactor DiagnosticDescriptor? GetExternOrLibraryImportRule to be two methods: bool IsExtern and bool IsLibraryImport

Copy link
Contributor Author

Copilot AI commented Mar 22, 2026

@copilot please refactor DiagnosticDescriptor? GetExternOrLibraryImportRule to be two methods: bool IsExtern and bool IsLibraryImport

Done in 56e5847. Refactored GetExternOrLibraryImportRule into two separate methods:

  • bool IsExtern(IMethodSymbol) — checks extern + InternalCall exemption
  • bool IsLibraryImport(IMethodSymbol) — checks partial + LibraryImportAttribute

Also fixed a minor bug in the process: (mio & (int)MethodImplOptions.InternalCall) was mixing enum with int, now uses (mio & MethodImplOptions.InternalCall) which is correct for [Flags] enums.

@EgorBo EgorBo marked this pull request as ready for review March 22, 2026 02:58
@EgorBo EgorBo requested a review from sbomer as a code owner March 22, 2026 02:58
Copilot AI review requested due to automatic review settings March 22, 2026 02:58
Copy link
Contributor

Copilot AI left a comment

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 expands the RequiresUnsafe analyzer/code-fix infrastructure (new IL5005/IL5006) and updates CoreLib and source-generation/build plumbing so all extern and [LibraryImport] entrypoints (and generated stubs) are consistently annotated with [RequiresUnsafe], while temporarily suppressing the call-site diagnostic IL5000 repo-wide.

Changes:

  • Add new diagnostics for missing [RequiresUnsafe] on extern methods (IL5005) and [LibraryImport] partial methods (IL5006), extend the code-fix, and add tests/resources/IDs.
  • Teach LibraryImportGenerator to emit [RequiresUnsafe] on generated P/Invoke helpers when the attribute is defined in the current compilation.
  • Add a RequiresUnsafeAttribute polyfill for libraries (via Directory.Build.targets) and annotate CoreLib QCalls/externs/UnsafeAccessor usages with [RequiresUnsafe]; temporarily suppress IL5000 in repo build props.

Reviewed changes

Copilot reviewed 50 out of 50 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Directory.Build.props Temporarily suppress IL5000 repo-wide via NoWarn.
src/tools/illink/src/ILLink.Shared/DiagnosticId.cs Add DiagnosticId entries for IL5005/IL5006.
src/tools/illink/src/ILLink.Shared/SharedStrings.resx Add title/message resources for IL5005/IL5006.
src/tools/illink/src/ILLink.RoslynAnalyzer/UnsafeMethodMissingRequiresUnsafeAnalyzer.cs Extend analyzer to report IL5005/IL5006 in addition to IL5004.
src/tools/illink/src/ILLink.CodeFix/UnsafeMethodMissingRequiresUnsafeCodeFixProvider.cs Extend code fix to cover IL5005/IL5006.
src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/UnsafeMethodMissingRequiresUnsafeTests.cs Add tests covering new diagnostics + fixer behavior.
src/libraries/Directory.Build.targets Include RequiresUnsafeAttribute polyfill in library projects (with exclusions).
src/libraries/Common/src/System/Diagnostics/CodeAnalysis/RequiresUnsafeAttribute.cs Add shared polyfill definition of RequiresUnsafeAttribute.
src/libraries/Microsoft.Bcl.Memory/src/Microsoft.Bcl.Memory.csproj Remove direct compile include now covered by the new polyfill mechanism.
src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs Add type/name syntax constants for RequiresUnsafeAttribute.
src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs Conditionally forward [RequiresUnsafe] onto generated P/Invoke helpers.
src/coreclr/System.Private.CoreLib/src/System/Variant.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/TypeLoadException.CoreCLR.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs Annotate multiple QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Threading/Monitor.CoreCLR.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs Annotate multiple QCall [LibraryImport] / extern entrypoints with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/String.CoreCLR.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs Annotate multiple QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/TrackerObjectManager.CoreCLR.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs Annotate multiple QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.CoreCLR.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreCLR.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Runtime/DependentHandle.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Runtime/ControlledExecution.CoreCLR.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/VirtualDispatchHelpers.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs Annotate multiple QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/InitHelpers.cs Annotate [UnmanagedCallersOnly] entrypoint with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/GenericsHelpers.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs Annotate multiple QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodBase.CoreCLR.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeTypeBuilder.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeModuleBuilder.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs Annotate multiple QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Enum.CoreCLR.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs Annotate [UnsafeAccessor] extern members with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrame.CoreCLR.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Diagnostics/Debugger.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/ComAwareWeakReference.CoreCLR.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/ArgIterator.cs Annotate QCall [LibraryImport] methods with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/System/AppContext.CoreCLR.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/Internal/VersionResilientHashCode.CoreCLR.cs Annotate QCall [LibraryImport] with [RequiresUnsafe].
src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs Annotate multiple [UnsafeAccessor] extern members with [RequiresUnsafe].

Comment on lines +1302 to +1304
<data name="ExternMethodMissingRequiresUnsafeTitle" xml:space="preserve">
<value>extern methods should be annotated with 'RequiresUnsafeAttribute'.</value>
</data>
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

Diagnostic titles in this .resx are consistently sentence-cased (start with an uppercase letter), but ExternMethodMissingRequiresUnsafeTitle currently starts with lowercase extern. Consider changing it to start with Extern to match the surrounding titles and standard diagnostic title casing.

Copilot uses AI. Check for mistakes.
Comment on lines +202 to +209
<!-- Adds RequiresUnsafeAttribute polyfill for non-CoreLib library source projects that share Common
source files annotated with [RequiresUnsafe]. Excluded from shim/facade/ref/PNSE assemblies that
must only contain type-forwards. -->
<ItemGroup Condition="'$(MSBuildProjectExtension)' == '.csproj' and
'$(IsPartialFacadeAssembly)' != 'true' and
'$(IsReferenceAssemblyProject)' != 'true' and
'$(GeneratePlatformNotSupportedAssemblyMessage)' == '' and
!$(MSBuildProjectDirectory.Contains('shims'))">
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

The comment says this polyfill is excluded from PNSE assemblies, but the condition only checks GeneratePlatformNotSupportedAssemblyMessage and not GeneratePlatformNotSupportedAssembly. Since the build infra treats both properties as PNSE indicators elsewhere in this file, consider updating the condition (or the comment) so they stay consistent and PNSE assemblies can’t accidentally pick up this implementation file in the future.

Copilot uses AI. Check for mistakes.
Comment on lines +52 to 66
if (HasPointerInSignature (method)) {
foreach (var location in method.Locations) {
context.ReportDiagnostic (Diagnostic.Create (s_pointerRule, location, method.GetDisplayName ()));
}
}

if (IsExtern (method)) {
foreach (var location in method.Locations) {
context.ReportDiagnostic (Diagnostic.Create (s_externRule, location, method.GetDisplayName ()));
}
} else if (IsLibraryImport (method)) {
foreach (var location in method.Locations) {
context.ReportDiagnostic (Diagnostic.Create (s_libraryImportRule, location, method.GetDisplayName ()));
}
}
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

AnalyzeMethod can report multiple diagnostics for the same method (e.g., an extern method with pointer types will hit both HasPointerInSignature and IsExtern, producing IL5004 + IL5005). This is likely redundant/noisy and can result in duplicate code-fix offerings. Consider making the diagnostics mutually exclusive (e.g., prefer extern/LibraryImport diagnostics over the pointer-signature diagnostic, or otherwise choose a single rule to report per method).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.Reflection linkable-framework Issues associated with delivering a linker friendly framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants