Add [RequiresUnsafe] to all extern and LibraryImport methods (CoreLib) + IL5005/IL5006 diagnostics#125894
Add [RequiresUnsafe] to all extern and LibraryImport methods (CoreLib) + IL5005/IL5006 diagnostics#125894
Conversation
…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
|
Tagging subscribers to this area: @dotnet/area-system-reflection |
|
@copilot please split ExternMethodMissingRequiresUnsafe (IL5005) into two: for |
…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
Done in d5e10fb. Split into:
Each has its own diagnostic descriptor, strings in SharedStrings.resx, and the test for LibraryImport now asserts |
|
@copilot update LibraryImportGenerator to emit [RequiresUnsafe] over the |
…_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
Done in bce5280. The LibraryImportGenerator now emits |
|
@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
Investigated and fixed the PR-related failure in 3833b0a.
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:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot please refactor |
…rt methods Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e3122303-b003-4824-94ed-abc029a06f46
Done in 56e5847. Refactored
Also fixed a minor bug in the process: |
There was a problem hiding this comment.
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]onexternmethods (IL5005) and[LibraryImport]partial methods (IL5006), extend the code-fix, and add tests/resources/IDs. - Teach
LibraryImportGeneratorto emit[RequiresUnsafe]on generated P/Invoke helpers when the attribute is defined in the current compilation. - Add a
RequiresUnsafeAttributepolyfill for libraries (viaDirectory.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]. |
| <data name="ExternMethodMissingRequiresUnsafeTitle" xml:space="preserve"> | ||
| <value>extern methods should be annotated with 'RequiresUnsafeAttribute'.</value> | ||
| </data> |
There was a problem hiding this comment.
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.
| <!-- 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'))"> |
There was a problem hiding this comment.
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.
| 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 ())); | ||
| } | ||
| } |
There was a problem hiding this comment.
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).
This PR takes over #125880 and implements all the items from the original PR description while addressing reviewer feedback.
Description
What this PR does
New IL5005 diagnostic — Issues
IL5005forexternmethods without[RequiresUnsafe]on them. (IL5004already exists for pointer-type signatures.)New IL5006 diagnostic — Issues
IL5006for[LibraryImport]partial methods without[RequiresUnsafe]on them.Extends the code-fixer —
UnsafeMethodMissingRequiresUnsafeCodeFixProvidernow also offers to add[RequiresUnsafe]when IL5005 or IL5006 is reported (forextern/[LibraryImport]methods).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.Adds
[RequiresUnsafe]to all CoreLib methods — All[LibraryImport]and[UnsafeAccessor]extern methods inSystem.Private.CoreLibare now annotated.Creates
RequiresUnsafeAttributepolyfill - since many files are compiled for NS2.0/NETFX targets. The polyfill inDirectory.Build.targetsexcludes shim/facade/ref/PNSE assemblies that must only contain type-forwards.LibraryImportGenerator emits
[RequiresUnsafe]— The generator now emits[global::System.Diagnostics.CodeAnalysis.RequiresUnsafeAttribute]on the generated__PInvokeextern local function. This is conditional onRequiresUnsafeAttributebeing defined in the compilation being built (checked viaCompilation.Assemblyequality), so external projects without the polyfill are unaffected.Refactored analyzer detection methods —
GetExternOrLibraryImportRulewas refactored into two focused boolean methods:IsExtern(IMethodSymbol)andIsLibraryImport(IMethodSymbol)for clearer separation of concerns.Not done (tracked in PR description)
MethodImplOptions.InternalCallexempted with a TODO — too many safe APIs with InternalCall (allMath.*etc.)[RequiresUnsafe(false)]if that overload is ever introduced[RequiresUnsafe(false)]⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.