mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
C#: Favor DLLs with most recent .NET Core target framework when resolving dependencies in standalone
This commit is contained in:
@@ -59,10 +59,13 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
// The OrderBy is used to ensure that we by default select the highest version number.
|
||||
foreach (var info in assemblyInfoByFileName.Values
|
||||
.OrderBy(info => info.Name)
|
||||
.ThenBy(info => info.NetCoreVersion ?? emptyVersion)
|
||||
.ThenBy(info => info.Version ?? emptyVersion))
|
||||
{
|
||||
foreach (var index in info.IndexStrings)
|
||||
{
|
||||
assemblyInfoById[index] = info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,15 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores information about an assembly file (DLL).
|
||||
/// </summary>
|
||||
internal sealed class AssemblyInfo
|
||||
internal sealed partial class AssemblyInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The file containing the assembly.
|
||||
@@ -28,6 +30,17 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// </summary>
|
||||
public System.Version? Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The version number of the .NET Core framework that this assembly targets.
|
||||
///
|
||||
/// This is extracted from the `TargetFrameworkAttribute` of the assembly, e.g.
|
||||
/// ```
|
||||
/// [assembly:TargetFramework(".NETCoreApp,Version=v7.0")]
|
||||
/// ```
|
||||
/// yields version 7.0.
|
||||
/// </summary>
|
||||
public Version? NetCoreVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The public key token of the assembly.
|
||||
/// </summary>
|
||||
@@ -97,13 +110,14 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
Filename = filename;
|
||||
}
|
||||
|
||||
private AssemblyInfo(string filename, string name, Version version, string culture, string publicKeyToken)
|
||||
private AssemblyInfo(string filename, string name, Version version, string culture, string publicKeyToken, Version? netCoreVersion)
|
||||
{
|
||||
Filename = filename;
|
||||
Name = name;
|
||||
Version = version;
|
||||
Culture = culture;
|
||||
PublicKeyToken = publicKeyToken;
|
||||
NetCoreVersion = netCoreVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -150,7 +164,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
var metadata = pereader.GetMetadata();
|
||||
unsafe
|
||||
{
|
||||
var reader = new System.Reflection.Metadata.MetadataReader(metadata.Pointer, metadata.Length);
|
||||
var reader = new MetadataReader(metadata.Pointer, metadata.Length);
|
||||
var def = reader.GetAssemblyDefinition();
|
||||
|
||||
// This is how you compute the public key token from the full public key.
|
||||
@@ -162,7 +176,39 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
publicKeyString.AppendFormat("{0:x2}", b);
|
||||
|
||||
var culture = def.Culture.IsNil ? "neutral" : reader.GetString(def.Culture);
|
||||
return new AssemblyInfo(filename, reader.GetString(def.Name), def.Version, culture, publicKeyString.ToString());
|
||||
Version? netCoreVersion = null;
|
||||
|
||||
foreach (var attrHandle in def.GetCustomAttributes().Select(reader.GetCustomAttribute))
|
||||
{
|
||||
var ctorHandle = attrHandle.Constructor;
|
||||
if (ctorHandle.Kind != HandleKind.MemberReference)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var mHandle = reader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent;
|
||||
if (mHandle.Kind != HandleKind.TypeReference)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var name = reader.GetString(reader.GetTypeReference((TypeReferenceHandle)mHandle).Name);
|
||||
|
||||
if (name is "TargetFrameworkAttribute")
|
||||
{
|
||||
var decoded = attrHandle.DecodeValue(new DummyAttributeDecoder());
|
||||
if (
|
||||
decoded.FixedArguments.Length > 0 &&
|
||||
decoded.FixedArguments[0].Value is string value &&
|
||||
NetCoreAppRegex().Match(value).Groups.TryGetValue("version", out var match))
|
||||
{
|
||||
netCoreVersion = new Version(match.Value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new AssemblyInfo(filename, reader.GetString(def.Name), def.Version, culture, publicKeyString.ToString(), netCoreVersion);
|
||||
}
|
||||
}
|
||||
catch (BadImageFormatException)
|
||||
@@ -176,5 +222,33 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
throw new AssemblyLoadException();
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"^\.NETCoreApp,Version=v(?<version>\d+\.\d+)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
|
||||
private static partial Regex NetCoreAppRegex();
|
||||
|
||||
private class DummyAttributeDecoder : ICustomAttributeTypeProvider<int>
|
||||
{
|
||||
public int GetPrimitiveType(PrimitiveTypeCode typeCode) => 0;
|
||||
|
||||
public int GetSystemType() => throw new NotImplementedException();
|
||||
|
||||
public int GetSZArrayType(int elementType) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
public int GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
public int GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
public int GetTypeFromSerializedName(string name) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
public PrimitiveTypeCode GetUnderlyingEnumType(int type) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
public bool IsSystemType(int type) => throw new NotImplementedException();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,12 +122,12 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
ResolveConflicts();
|
||||
|
||||
// Output the findings
|
||||
foreach (var r in usedReferences.Keys)
|
||||
foreach (var r in usedReferences.Keys.OrderBy(r => r))
|
||||
{
|
||||
progressMonitor.ResolvedReference(r);
|
||||
}
|
||||
|
||||
foreach (var r in unresolvedReferences)
|
||||
foreach (var r in unresolvedReferences.OrderBy(r => r.Key))
|
||||
{
|
||||
progressMonitor.UnresolvedReference(r.Key, r.Value);
|
||||
}
|
||||
@@ -232,7 +232,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
}
|
||||
|
||||
sortedReferences = sortedReferences.OrderBy(r => r.Version).ToList();
|
||||
var emptyVersion = new Version(0, 0);
|
||||
sortedReferences = sortedReferences.OrderBy(r => r.NetCoreVersion ?? emptyVersion).ThenBy(r => r.Version ?? emptyVersion).ToList();
|
||||
|
||||
var finalAssemblyList = new Dictionary<string, AssemblyInfo>();
|
||||
|
||||
@@ -253,9 +254,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
foreach (var r in sortedReferences)
|
||||
{
|
||||
var resolvedInfo = finalAssemblyList[r.Name];
|
||||
if (resolvedInfo.Version != r.Version)
|
||||
if (resolvedInfo.Version != r.Version || resolvedInfo.NetCoreVersion != r.NetCoreVersion)
|
||||
{
|
||||
progressMonitor.ResolvedConflict(r.Id, resolvedInfo.Id);
|
||||
progressMonitor.ResolvedConflict(r.Id, resolvedInfo.Id + resolvedInfo.NetCoreVersion is null ? "" : $" (.NET Core {resolvedInfo.NetCoreVersion})");
|
||||
++conflictedReferences;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user