Skip to content

Commit

Permalink
Enable single file analyzer in the runtime (#50894)
Browse files Browse the repository at this point in the history
Summary:
Enables single file analyzer in the runtime by adding the ILLink.Analyzers package and the property EnableSingleFileAnalyzer equals to true
Deletes entries IL3000 and IL3001 in the CodeAnalysis.ruleset so the analyzer can actually produce these warnings otherwise the analyzer execution would be skipped. *Note*: tests warnings are controlled by CodeAnalysis.test.ruleset (this PR adds IL3002 to the CodeAnalysis.test.ruleset to disable the warning on tests)
Resolve warnings on single file dangerous patterns by:
- Annotating incompatible single file patterns with RequiresAssemblyFiles
- Suppressing the warning (because there is code that handles the incompatible code)
- Fixing the issue on code (remove the incompatible code and replace it with something that won't fail)
- Opening an issue to track fix and either annotate/suppress the current behavior
  • Loading branch information
tlakollo committed May 19, 2021
1 parent a287b6d commit aad916c
Show file tree
Hide file tree
Showing 36 changed files with 129 additions and 20 deletions.
2 changes: 2 additions & 0 deletions eng/Analyzers.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
<CodeAnalysisRuleset>$(MSBuildThisFileDirectory)CodeAnalysis.ruleset</CodeAnalysisRuleset>
<!-- Disable analyzers in sourcebuild -->
<RunAnalyzers Condition="'$(DotNetBuildFromSource)' == 'true'">false</RunAnalyzers>
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
</PropertyGroup>
<ItemGroup Condition="'$(RunAnalyzers)' != 'false'">
<PackageReference Include="Microsoft.DotNet.CodeAnalysis" Version="$(MicrosoftDotNetCodeAnalysisVersion)" PrivateAssets="all" IsImplicitlyDefined="true" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="$(MicrosoftCodeAnalysisNetAnalyzersVersion)" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeStyle" Version="$(MicrosoftCodeAnalysisCSharpCodeStyleVersion)" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="$(StyleCopAnalyzersVersion)" PrivateAssets="all" />
<PackageReference Include="Microsoft.NET.ILLink.Analyzers" Version="$(MicrosoftNETILLinkAnalyzerPackageVersion)" PrivateAssets="all" />
</ItemGroup>
</Project>
2 changes: 0 additions & 2 deletions eng/CodeAnalysis.ruleset
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,6 @@
<Rule Id="CA5401" Action="None" /> <!-- Do not use CreateEncryptor with non-default IV -->
<Rule Id="CA5402" Action="None" /> <!-- Use CreateEncryptor with the default IV -->
<Rule Id="CA5403" Action="None" /> <!-- Do not hard-code certificate -->
<Rule Id="IL3000" Action="None" /> <!-- Avoid using accessing Assembly file path when publishing as a single-file -->
<Rule Id="IL3001" Action="None" /> <!-- Avoid using accessing Assembly file path when publishing as a single-file -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="AD0001" Action="None" /> <!-- Analyzer threw an exception -->
Expand Down
1 change: 1 addition & 0 deletions eng/CodeAnalysis.test.ruleset
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@
<Rule Id="CA5403" Action="None" /> <!-- Do not hard-code certificate -->
<Rule Id="IL3000" Action="None" /> <!-- Avoid using accessing Assembly file path when publishing as a single-file -->
<Rule Id="IL3001" Action="None" /> <!-- Avoid using accessing Assembly file path when publishing as a single-file -->
<Rule Id="IL3002" Action="None" /> <!-- Using member with RequiresAssemblyFilesAttribute can break functionality when embedded in a single-file app -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="AD0001" Action="None" /> <!-- Analyzer threw an exception -->
Expand Down
1 change: 1 addition & 0 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@
<MicrosoftPrivateIntellisenseVersion>5.0.0-preview-20201009.2</MicrosoftPrivateIntellisenseVersion>
<!-- ILLink -->
<MicrosoftNETILLinkTasksVersion>6.0.100-preview.5.21267.3</MicrosoftNETILLinkTasksVersion>
<MicrosoftNETILLinkAnalyzerPackageVersion>$(MicrosoftNETILLinkTasksVersion)</MicrosoftNETILLinkAnalyzerPackageVersion>
<!-- ICU -->
<MicrosoftNETCoreRuntimeICUTransportVersion>6.0.0-preview.5.21267.1</MicrosoftNETCoreRuntimeICUTransportVersion>
<!-- Mono LLVM -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ public partial class DependencyContext
public DependencyContext(Microsoft.Extensions.DependencyModel.TargetInfo target, Microsoft.Extensions.DependencyModel.CompilationOptions compilationOptions, System.Collections.Generic.IEnumerable<Microsoft.Extensions.DependencyModel.CompilationLibrary> compileLibraries, System.Collections.Generic.IEnumerable<Microsoft.Extensions.DependencyModel.RuntimeLibrary> runtimeLibraries, System.Collections.Generic.IEnumerable<Microsoft.Extensions.DependencyModel.RuntimeFallbacks> runtimeGraph) { }
public Microsoft.Extensions.DependencyModel.CompilationOptions CompilationOptions { get { throw null; } }
public System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.DependencyModel.CompilationLibrary> CompileLibraries { get { throw null; } }
[System.Diagnostics.CodeAnalysis.RequiresAssemblyFilesAttribute(Message = "DependencyContext for an assembly from a application published as single-file is not supported. The method will return null. Make sure the calling code can handle this case.")]
public static Microsoft.Extensions.DependencyModel.DependencyContext Default { get { throw null; } }
public System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.DependencyModel.RuntimeFallbacks> RuntimeGraph { get { throw null; } }
public System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.DependencyModel.RuntimeLibrary> RuntimeLibraries { get { throw null; } }
public Microsoft.Extensions.DependencyModel.TargetInfo Target { get { throw null; } }
[System.Diagnostics.CodeAnalysis.RequiresAssemblyFilesAttribute(Message = "DependencyContext for an assembly from a application published as single-file is not supported. The method will return null. Make sure the calling code can handle this case.")]
public static Microsoft.Extensions.DependencyModel.DependencyContext Load(System.Reflection.Assembly assembly) { throw null; }
public Microsoft.Extensions.DependencyModel.DependencyContext Merge(Microsoft.Extensions.DependencyModel.DependencyContext other) { throw null; }
}
Expand Down Expand Up @@ -95,6 +97,7 @@ public partial class DependencyContextLoader
{
public DependencyContextLoader() { }
public static Microsoft.Extensions.DependencyModel.DependencyContextLoader Default { get { throw null; } }
[System.Diagnostics.CodeAnalysis.RequiresAssemblyFilesAttribute(Message = "DependencyContext for an assembly from a application published as single-file is not supported. The method will return null. Make sure the calling code can handle this case.")]
public Microsoft.Extensions.DependencyModel.DependencyContext Load(System.Reflection.Assembly assembly) { throw null; }
}
public partial class DependencyContextWriter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Microsoft.Extensions.DependencyModel.cs" />
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\RequiresAssemblyFilesAttribute.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;

namespace Microsoft.Extensions.DependencyModel
{
public class DependencyContext
{

[UnconditionalSuppressMessage("SingleFile", "IL3002:Avoid calling members marked with 'RequiresAssemblyFilesAttribute' when publishing as a single-file",
Justification = "The annotation should be on the static constructor but is Compiler Generated, annotating the caller Default method instead")]
private static readonly Lazy<DependencyContext> _defaultContext = new Lazy<DependencyContext>(LoadDefault);

public DependencyContext(TargetInfo target,
Expand Down Expand Up @@ -46,6 +50,7 @@ public DependencyContext(TargetInfo target,
RuntimeGraph = runtimeGraph.ToArray();
}

[RequiresAssemblyFiles(Message = "DependencyContext for an assembly from a application published as single-file is not supported. The method will return null. Make sure the calling code can handle this case.")]
public static DependencyContext Default => _defaultContext.Value;

public TargetInfo Target { get; }
Expand Down Expand Up @@ -74,6 +79,7 @@ public DependencyContext Merge(DependencyContext other)
);
}

[RequiresAssemblyFiles(Message = "DependencyContext for an assembly from a application published as single-file is not supported. The method will return null. Make sure the calling code can handle this case.")]
private static DependencyContext LoadDefault()
{
var entryAssembly = Assembly.GetEntryAssembly();
Expand All @@ -85,6 +91,7 @@ private static DependencyContext LoadDefault()
return Load(entryAssembly);
}

[RequiresAssemblyFiles(Message = "DependencyContext for an assembly from a application published as single-file is not supported. The method will return null. Make sure the calling code can handle this case.")]
public static DependencyContext Load(Assembly assembly)
{
return DependencyContextLoader.Default.Load(assembly);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;

Expand Down Expand Up @@ -50,6 +51,7 @@ private static Stream GetResourceStream(Assembly assembly, string name)
return assembly.GetManifestResourceStream(name);
}

[RequiresAssemblyFiles(Message = "DependencyContext for an assembly from a application published as single-file is not supported. The method will return null. Make sure the calling code can handle this case.")]
public DependencyContext Load(Assembly assembly)
{
if (assembly == null)
Expand Down Expand Up @@ -103,6 +105,7 @@ private DependencyContext LoadContext(IDependencyContextReader reader, string lo
return null;
}

[RequiresAssemblyFiles(Message = "DependencyContext for an assembly from a application published as single-file is not supported. The method will return null. Make sure the calling code can handle this case.")]
private DependencyContext LoadAssemblyContext(Assembly assembly, IDependencyContextReader reader)
{
using (Stream stream = GetResourceStream(assembly, assembly.GetName().Name + DepsJsonExtension))
Expand All @@ -125,6 +128,7 @@ private DependencyContext LoadAssemblyContext(Assembly assembly, IDependencyCont
return null;
}

[RequiresAssemblyFiles(Message = "The use of DependencyContextLoader is not supported when publishing as single-file")]
private string GetDepsJsonPath(Assembly assembly)
{
// Assemblies loaded in memory (e.g. single file) return empty string from Location.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Microsoft.Extensions.DependencyModel.DependencyContext</PackageDescription>
<ItemGroup>
<Compile Include="$(CoreLibSharedDir)\System\Numerics\Hashing\HashHelpers.cs"
Link="System\Numerics\Hashing\HashHelpers.cs" />
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\RequiresAssemblyFilesAttribute.cs" />
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\UnconditionalSuppressMessageAttribute.cs" />
</ItemGroup>

<ItemGroup>
Expand All @@ -29,4 +31,5 @@ Microsoft.Extensions.DependencyModel.DependencyContext</PackageDescription>
<ProjectReference Include="$(LibrariesProjectRoot)System.Text.Encodings.Web\src\System.Text.Encodings.Web.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Text.Json\src\System.Text.Json.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;

Expand All @@ -27,6 +28,8 @@ public static void Enable()
// has run.
}

[UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file",
Justification = "The code has a fallback to use AppDomain.CurrentDomain.BaseDirectory so it will work correctly in single-file")]
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// apply any existing policy
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.SDK">
<Project Sdk="Microsoft.NET.SDK">
<!-- These are wrapper project files for packaging.-->
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppToolCurrent);net472</TargetFrameworks>
Expand All @@ -21,6 +21,7 @@
<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
<Compile Include="BuildTask.Desktop.cs" />
<Compile Include="AssemblyResolver.cs" />
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\UnconditionalSuppressMessageAttribute.cs" />
</ItemGroup>

<ItemGroup>
Expand All @@ -38,7 +39,7 @@
<Content Condition="'$(AdditionalRuntimeIdentifiers)' != ''" Include="$(IntermediateOutputPath)runtime.json" PackagePath="/" />
<Content Include="_._" PackagePath="lib/netstandard1.0" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="$(RefOnlyMicrosoftBuildVersion)" />
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="$(RefOnlyMicrosoftBuildTasksCoreVersion)" />
Expand All @@ -55,4 +56,4 @@
</Target>

<Import Project="runtimeGroups.props" />
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
<StringResourcesName>FxResources.$(AssemblyName.Replace('-', '_')).SR</StringResourcesName>
<OutputType>Exe</OutputType>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<EnableSingleFileAnalyzer>false</EnableSingleFileAnalyzer>
</PropertyGroup>

<ItemGroup>
<Compile Include="Sgen.cs" />
</ItemGroup>

<Import Project=".\GenerateThisAssemblyCs.targets" />
</Project>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@
<Compile Include="$(CommonPath)System\Composition\Diagnostics\TraceWriter.cs"
Link="Common\System\Composition\Diagnostics\TraceWriter.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != '$(NetCoreAppCurrent)'">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\UnconditionalSuppressMessageAttribute.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard2.0'">
<Reference Include="Microsoft.Win32.Primitives" />
<Reference Include="System.Collections" />
Expand Down Expand Up @@ -211,4 +214,4 @@
<Reference Include="System.Threading.Thread" />
<Reference Include="System.Text.Encoding.Extensions" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,8 @@ private void ThrowIfDisposed()
private string GetDisplayName() =>
$"{GetType().Name} (Assembly=\"{Assembly.FullName}\")"; // NOLOC

[UnconditionalSuppressMessage("SingleFile", "IL3000: Avoid accessing Assembly file path when publishing as a single file",
Justification = "Setting a CodeBase is single file compatible")]
private static Assembly LoadAssembly(string codeBase)
{
Requires.NotNullOrEmpty(codeBase, nameof(codeBase));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using System.Collections;
Expand Down Expand Up @@ -57,6 +58,8 @@ private string GetLocalPath(string fileName)
return uri.LocalPath + uri.Fragment;
}

[UnconditionalSuppressMessage("SingleFile", "IL3000: Avoid accessing Assembly file path when publishing as a single file",
Justification = "Suppressing the warning until gets fixed, see https://github.com/dotnet/runtime/issues/50821")]
public override string GetSavedLicenseKey(Type type, Assembly resourceAssembly)
{
if (_savedLicenseKeys == null || _savedLicenseKeys[type.AssemblyQualifiedName] == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@
<Compile Include="$(CommonPath)System\IO\TempFileCollection.cs"
Link="Common\System\IO\TempFileCollection.cs" />
<Compile Include="$(CommonPath)System\Obsoletions.cs" Link="Common\System\Obsoletions.cs" />
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\UnconditionalSuppressMessageAttribute.cs" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
<ProjectReference Include="$(LibrariesProjectRoot)System.Security.Cryptography.ProtectedData\src\System.Security.Cryptography.ProtectedData.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Reflection;
Expand All @@ -28,6 +29,8 @@ internal sealed class ClientConfigPaths
private readonly bool _includesUserConfig;
private string _companyName;

[UnconditionalSuppressMessage("SingleFile", "IL3000: Avoid accessing Assembly file path when publishing as a single file",
Justification = "Code handles single file case")]
private ClientConfigPaths(string exePath, bool includeUserConfig)
{
_includesUserConfig = includeUserConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Win32.Registry\src\Microsoft.Win32.Registry.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Threading.AccessControl\src\System.Threading.AccessControl.csproj" />
</ItemGroup>

<ItemGroup Condition="!$(TargetFramework.StartsWith('$(NetCoreAppCurrent)'))">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\UnconditionalSuppressMessageAttribute.cs" />
</ItemGroup>
<!-- Ensure we run ResolveProjectReferences to add the message DLL to the package.
We do this here rather than in the pkgproj to ensure the package paths are in sync -->
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
Expand All @@ -138,4 +140,4 @@
Condition="'$(TargetsWindows)' == 'true'"
DependsOnTargets="ResolveProjectReferences"
BeforeTargets="GetFilesToPackage" />
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
Expand Down Expand Up @@ -691,6 +692,8 @@ internal static RegistryKey GetEventLogRegKey(string machine, bool writable)
return null;
}

[UnconditionalSuppressMessage("SingleFile", "IL3000: Avoid accessing Assembly file path when publishing as a single file",
Justification = "The code handles if the path is null by calling AppContext.BaseDirectory")]
internal static string GetDllPath(string machineName)
{
string dllPath = Path.Combine(NetFrameworkUtils.GetLatestBuildDllDirectory(machineName), DllName);
Expand Down
Loading

0 comments on commit aad916c

Please sign in to comment.