提交 a78e73c3 编写于 作者: P pgavlin

Add public key validation to assembly name parsing.

This is necessary to correctly reject invalid assembly names in InternalsVisibleTo and to match the native compiler. (changeset 1389827)
上级 67f59d06
...@@ -111,9 +111,10 @@ internal IEnumerable<CSharpAttributeData> GetCustomAttributesToEmit(ModuleCompil ...@@ -111,9 +111,10 @@ internal IEnumerable<CSharpAttributeData> GetCustomAttributesToEmit(ModuleCompil
CSharpAttributeData attribute = userDefined[i]; CSharpAttributeData attribute = userDefined[i];
if (this.Kind == SymbolKind.Assembly) if (this.Kind == SymbolKind.Assembly)
{ {
// We need to filter out duplicate assembly attributes, // We need to filter out duplicate assembly attributes (i.e. attributes that
// i.e. attributes that bind to the same constructor and have identical arguments. // bind to the same constructor and have identical arguments) and invalid
if (((SourceAssemblySymbol)this).IsIndexOfDuplicateAssemblyAttribute(i)) // InternalsVisibleTo attributes.
if (((SourceAssemblySymbol)this).IsIndexOfOmittedAssemblyAttribute(i))
{ {
continue; continue;
} }
...@@ -126,4 +127,4 @@ internal IEnumerable<CSharpAttributeData> GetCustomAttributesToEmit(ModuleCompil ...@@ -126,4 +127,4 @@ internal IEnumerable<CSharpAttributeData> GetCustomAttributesToEmit(ModuleCompil
} }
} }
} }
} }
\ No newline at end of file
...@@ -67,12 +67,14 @@ internal sealed class SourceAssemblySymbol : MetadataOrSourceAssemblySymbol, IAt ...@@ -67,12 +67,14 @@ internal sealed class SourceAssemblySymbol : MetadataOrSourceAssemblySymbol, IAt
private IDictionary<string, NamedTypeSymbol> lazyForwardedTypesFromSource; private IDictionary<string, NamedTypeSymbol> lazyForwardedTypesFromSource;
/// <summary> /// <summary>
/// Indices of duplicate assembly attributes, i.e. attributes that bind to the same constructor and have identical arguments, that must not be emitted. /// Indices of attributes that will not be emitted for one of two reasons:
/// - They are duplicates of another attribute (i.e. attributes that bind to the same constructor and have identical arguments)
/// - They are InternalsVisibleToAttributes with invalid assembly identities
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// These indices correspond to the merged assembly attributes from source and added net modules, i.e. attributes returned by <see cref="GetAttributes"/> method. /// These indices correspond to the merged assembly attributes from source and added net modules, i.e. attributes returned by <see cref="GetAttributes"/> method.
/// </remarks> /// </remarks>
private HashSet<int> lazyDuplicateAttributeIndices; private ConcurrentSet<int> lazyOmittedAttributeIndices;
private ThreeState lazyContainsExtensionMethods; private ThreeState lazyContainsExtensionMethods;
...@@ -1068,16 +1070,25 @@ private bool IsKnownAssemblyAttribute(CSharpAttributeData attribute) ...@@ -1068,16 +1070,25 @@ private bool IsKnownAssemblyAttribute(CSharpAttributeData attribute)
return false; return false;
} }
private void AddOmittedAttributeIndex(int index)
{
if (this.lazyOmittedAttributeIndices == null)
{
Interlocked.CompareExchange(ref this.lazyOmittedAttributeIndices, new ConcurrentSet<int>(), null);
}
this.lazyOmittedAttributeIndices.Add(index);
}
/// <summary> /// <summary>
/// Gets unique source assembly attributes that should be emitted, /// Gets unique source assembly attributes that should be emitted,
/// i.e. filters out attributes with errors and duplicate attributes. /// i.e. filters out attributes with errors and duplicate attributes.
/// </summary> /// </summary>
private HashSet<CSharpAttributeData> GetUniqueSourceAssemblyAttributes(out HashSet<int> attributeIndicesToSkip) private HashSet<CSharpAttributeData> GetUniqueSourceAssemblyAttributes()
{ {
ImmutableArray<CSharpAttributeData> appliedSourceAttributes = this.GetSourceAttributesBag().Attributes; ImmutableArray<CSharpAttributeData> appliedSourceAttributes = this.GetSourceAttributesBag().Attributes;
HashSet<CSharpAttributeData> uniqueAttributes = null; HashSet<CSharpAttributeData> uniqueAttributes = null;
attributeIndicesToSkip = null;
for (int i = 0; i < appliedSourceAttributes.Length; i++) for (int i = 0; i < appliedSourceAttributes.Length; i++)
{ {
...@@ -1086,12 +1097,7 @@ private HashSet<CSharpAttributeData> GetUniqueSourceAssemblyAttributes(out HashS ...@@ -1086,12 +1097,7 @@ private HashSet<CSharpAttributeData> GetUniqueSourceAssemblyAttributes(out HashS
{ {
if (!AddUniqueAssemblyAttribute(attribute, ref uniqueAttributes)) if (!AddUniqueAssemblyAttribute(attribute, ref uniqueAttributes))
{ {
if (attributeIndicesToSkip == null) AddOmittedAttributeIndex(i);
{
attributeIndicesToSkip = new HashSet<int>();
}
attributeIndicesToSkip.Add(i);
} }
} }
} }
...@@ -1205,8 +1211,7 @@ private ImmutableArray<CSharpAttributeData> GetNetModuleAttributes(out Immutable ...@@ -1205,8 +1211,7 @@ private ImmutableArray<CSharpAttributeData> GetNetModuleAttributes(out Immutable
private WellKnownAttributeData ValidateAttributeUsageAndDecodeWellKnownAttributes( private WellKnownAttributeData ValidateAttributeUsageAndDecodeWellKnownAttributes(
ImmutableArray<CSharpAttributeData> attributesFromNetModules, ImmutableArray<CSharpAttributeData> attributesFromNetModules,
ImmutableArray<string> netModuleNames, ImmutableArray<string> netModuleNames,
DiagnosticBag diagnostics, DiagnosticBag diagnostics)
out HashSet<int> attributeIndicesToSkip)
{ {
Debug.Assert(attributesFromNetModules.Any()); Debug.Assert(attributesFromNetModules.Any());
Debug.Assert(netModuleNames.Any()); Debug.Assert(netModuleNames.Any());
...@@ -1218,7 +1223,7 @@ private ImmutableArray<CSharpAttributeData> GetNetModuleAttributes(out Immutable ...@@ -1218,7 +1223,7 @@ private ImmutableArray<CSharpAttributeData> GetNetModuleAttributes(out Immutable
int sourceAttributesCount = this.GetSourceAttributesBag().Attributes.Length; int sourceAttributesCount = this.GetSourceAttributesBag().Attributes.Length;
// Get unique source assembly attributes. // Get unique source assembly attributes.
HashSet<CSharpAttributeData> uniqueAttributes = GetUniqueSourceAssemblyAttributes(out attributeIndicesToSkip); HashSet<CSharpAttributeData> uniqueAttributes = GetUniqueSourceAssemblyAttributes();
var arguments = new DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation>(); var arguments = new DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation>();
arguments.AttributesCount = netModuleAttributesCount; arguments.AttributesCount = netModuleAttributesCount;
...@@ -1230,6 +1235,8 @@ private ImmutableArray<CSharpAttributeData> GetNetModuleAttributes(out Immutable ...@@ -1230,6 +1235,8 @@ private ImmutableArray<CSharpAttributeData> GetNetModuleAttributes(out Immutable
// That is why we are iterating attributes backwards. // That is why we are iterating attributes backwards.
for (int i = netModuleAttributesCount - 1; i >= 0; i--) for (int i = netModuleAttributesCount - 1; i >= 0; i--)
{ {
var totalIndex = i + sourceAttributesCount;
CSharpAttributeData attribute = attributesFromNetModules[i]; CSharpAttributeData attribute = attributesFromNetModules[i];
if (!attribute.HasErrors && ValidateAttributeUsageForNetModuleAttribute(attribute, netModuleNames[i], diagnostics, ref uniqueAttributes)) if (!attribute.HasErrors && ValidateAttributeUsageForNetModuleAttribute(attribute, netModuleNames[i], diagnostics, ref uniqueAttributes))
{ {
...@@ -1239,16 +1246,11 @@ private ImmutableArray<CSharpAttributeData> GetNetModuleAttributes(out Immutable ...@@ -1239,16 +1246,11 @@ private ImmutableArray<CSharpAttributeData> GetNetModuleAttributes(out Immutable
// CONSIDER: Provide usable AttributeSyntax node for diagnostics of malformed netmodule assembly attributes // CONSIDER: Provide usable AttributeSyntax node for diagnostics of malformed netmodule assembly attributes
arguments.AttributeSyntaxOpt = null; arguments.AttributeSyntaxOpt = null;
this.DecodeWellKnownAttribute(ref arguments, isFromNetModule: true); this.DecodeWellKnownAttribute(ref arguments, totalIndex, isFromNetModule: true);
} }
else else
{ {
if (attributeIndicesToSkip == null) AddOmittedAttributeIndex(totalIndex);
{
attributeIndicesToSkip = new HashSet<int>();
}
attributeIndicesToSkip.Add(i + sourceAttributesCount);
} }
} }
...@@ -1257,13 +1259,8 @@ private ImmutableArray<CSharpAttributeData> GetNetModuleAttributes(out Immutable ...@@ -1257,13 +1259,8 @@ private ImmutableArray<CSharpAttributeData> GetNetModuleAttributes(out Immutable
private void LoadAndValidateNetModuleAttributes(ref CustomAttributesBag<CSharpAttributeData> lazyNetModuleAttributesBag) private void LoadAndValidateNetModuleAttributes(ref CustomAttributesBag<CSharpAttributeData> lazyNetModuleAttributesBag)
{ {
// Indices of duplicate assembly attributes, i.e. attributes that bind to the same constructor and have identical arguments, that must not be emitted.
HashSet<int> attributeIndicesToSkip;
if (compilation.Options.OutputKind.IsNetModule()) if (compilation.Options.OutputKind.IsNetModule())
{ {
// Compute duplicate source assembly attributes, i.e. attributes with same constructor and arguments, that must not be emitted.
var unused = GetUniqueSourceAssemblyAttributes(out attributeIndicesToSkip);
Interlocked.CompareExchange(ref lazyNetModuleAttributesBag, CustomAttributesBag<CSharpAttributeData>.Empty, null); Interlocked.CompareExchange(ref lazyNetModuleAttributesBag, CustomAttributesBag<CSharpAttributeData>.Empty, null);
} }
else else
...@@ -1277,12 +1274,12 @@ private void LoadAndValidateNetModuleAttributes(ref CustomAttributesBag<CSharpAt ...@@ -1277,12 +1274,12 @@ private void LoadAndValidateNetModuleAttributes(ref CustomAttributesBag<CSharpAt
if (attributesFromNetModules.Any()) if (attributesFromNetModules.Any())
{ {
wellKnownData = ValidateAttributeUsageAndDecodeWellKnownAttributes(attributesFromNetModules, netModuleNames, diagnostics, out attributeIndicesToSkip); wellKnownData = ValidateAttributeUsageAndDecodeWellKnownAttributes(attributesFromNetModules, netModuleNames, diagnostics);
} }
else else
{ {
// Compute duplicate source assembly attributes, i.e. attributes with same constructor and arguments, that must not be emitted. // Compute duplicate source assembly attributes, i.e. attributes with same constructor and arguments, that must not be emitted.
var unused = GetUniqueSourceAssemblyAttributes(out attributeIndicesToSkip); var unused = GetUniqueSourceAssemblyAttributes();
} }
// Load type forwarders from modules // Load type forwarders from modules
...@@ -1342,22 +1339,12 @@ private void LoadAndValidateNetModuleAttributes(ref CustomAttributesBag<CSharpAt ...@@ -1342,22 +1339,12 @@ private void LoadAndValidateNetModuleAttributes(ref CustomAttributesBag<CSharpAt
netModuleAttributesBag = CustomAttributesBag<CSharpAttributeData>.Empty; netModuleAttributesBag = CustomAttributesBag<CSharpAttributeData>.Empty;
} }
// Check if we have any duplicate assembly attribute that must not be emitted,
// unless we are emitting a net module.
if (attributeIndicesToSkip != null)
{
Debug.Assert(attributeIndicesToSkip.Any());
Interlocked.CompareExchange(ref lazyDuplicateAttributeIndices, attributeIndicesToSkip, null);
}
if (Interlocked.CompareExchange(ref lazyNetModuleAttributesBag, netModuleAttributesBag, null) == null) if (Interlocked.CompareExchange(ref lazyNetModuleAttributesBag, netModuleAttributesBag, null) == null)
{ {
this.AddSemanticDiagnostics(diagnostics); this.AddSemanticDiagnostics(diagnostics);
} }
diagnostics.Free(); diagnostics.Free();
Debug.Assert(attributeIndicesToSkip == null ||
!attributeIndicesToSkip.Any((index) => index < 0 || index >= this.GetAttributes().Length));
} }
Debug.Assert(lazyNetModuleAttributesBag.IsSealed); Debug.Assert(lazyNetModuleAttributesBag.IsSealed);
...@@ -1454,16 +1441,15 @@ public sealed override ImmutableArray<CSharpAttributeData> GetAttributes() ...@@ -1454,16 +1441,15 @@ public sealed override ImmutableArray<CSharpAttributeData> GetAttributes()
/// <remarks> /// <remarks>
/// This method must be invoked only after all the assembly attributes have been bound. /// This method must be invoked only after all the assembly attributes have been bound.
/// </remarks> /// </remarks>
internal bool IsIndexOfDuplicateAssemblyAttribute(int index) internal bool IsIndexOfOmittedAssemblyAttribute(int index)
{ {
Debug.Assert(this.lazyOmittedAttributeIndices == null || !lazyOmittedAttributeIndices.Any(i => i < 0 || i >= this.GetAttributes().Length));
Debug.Assert(this.lazySourceAttributesBag.IsSealed); Debug.Assert(this.lazySourceAttributesBag.IsSealed);
Debug.Assert(this.lazyNetModuleAttributesBag.IsSealed); Debug.Assert(this.lazyNetModuleAttributesBag.IsSealed);
Debug.Assert(index >= 0); Debug.Assert(index >= 0);
Debug.Assert(index < this.GetAttributes().Length); Debug.Assert(index < this.GetAttributes().Length);
Debug.Assert(this.lazyDuplicateAttributeIndices == null ||
!this.DeclaringCompilation.Options.OutputKind.IsNetModule());
return this.lazyDuplicateAttributeIndices != null && this.lazyDuplicateAttributeIndices.Contains(index); return this.lazyOmittedAttributeIndices != null && this.lazyOmittedAttributeIndices.Contains(index);
} }
/// <summary> /// <summary>
...@@ -1948,10 +1934,11 @@ private void DecodeTypeForwardedToAttribute(ref DecodeWellKnownAttributeArgument ...@@ -1948,10 +1934,11 @@ private void DecodeTypeForwardedToAttribute(ref DecodeWellKnownAttributeArgument
} }
} }
private static void DecodeOneInternalsVisibleToAttribute( private void DecodeOneInternalsVisibleToAttribute(
AttributeSyntax nodeOpt, AttributeSyntax nodeOpt,
CSharpAttributeData attrData, CSharpAttributeData attrData,
DiagnosticBag diagnostics, DiagnosticBag diagnostics,
int index,
ref ConcurrentDictionary<string, ConcurrentDictionary<ImmutableArray<byte>, Tuple<Location, string>>> lazyInternalsVisibleToMap) ref ConcurrentDictionary<string, ConcurrentDictionary<ImmutableArray<byte>, Tuple<Location, string>>> lazyInternalsVisibleToMap)
{ {
// this code won't be called unless we bound a well-formed, semantically correct ctor call. // this code won't be called unless we bound a well-formed, semantically correct ctor call.
...@@ -1970,6 +1957,7 @@ private void DecodeTypeForwardedToAttribute(ref DecodeWellKnownAttributeArgument ...@@ -1970,6 +1957,7 @@ private void DecodeTypeForwardedToAttribute(ref DecodeWellKnownAttributeArgument
if (!AssemblyIdentity.TryParseDisplayName(displayName, out identity, out parts)) if (!AssemblyIdentity.TryParseDisplayName(displayName, out identity, out parts))
{ {
diagnostics.Add(ErrorCode.WRN_InvalidAssemblyName, GetAssemblyAttributeLocationForDiagnostic(nodeOpt), displayName); diagnostics.Add(ErrorCode.WRN_InvalidAssemblyName, GetAssemblyAttributeLocationForDiagnostic(nodeOpt), displayName);
AddOmittedAttributeIndex(index);
return; return;
} }
...@@ -2037,10 +2025,10 @@ AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations ...@@ -2037,10 +2025,10 @@ AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations
internal override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation> arguments) internal override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation> arguments)
{ {
DecodeWellKnownAttribute(ref arguments, isFromNetModule: false); DecodeWellKnownAttribute(ref arguments, arguments.Index, isFromNetModule: false);
} }
private void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation> arguments, bool isFromNetModule) private void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation> arguments, int index, bool isFromNetModule)
{ {
var attribute = arguments.Attribute; var attribute = arguments.Attribute;
Debug.Assert(!attribute.HasErrors); Debug.Assert(!attribute.HasErrors);
...@@ -2049,7 +2037,7 @@ private void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments<Attr ...@@ -2049,7 +2037,7 @@ private void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments<Attr
if (attribute.IsTargetAttribute(this, AttributeDescription.InternalsVisibleToAttribute)) if (attribute.IsTargetAttribute(this, AttributeDescription.InternalsVisibleToAttribute))
{ {
DecodeOneInternalsVisibleToAttribute(arguments.AttributeSyntaxOpt, attribute, arguments.Diagnostics, ref lazyInternalsVisibleToMap); DecodeOneInternalsVisibleToAttribute(arguments.AttributeSyntaxOpt, attribute, arguments.Diagnostics, index, ref lazyInternalsVisibleToMap);
} }
else if (attribute.IsTargetAttribute(this, AttributeDescription.AssemblySignatureKeyAttribute)) else if (attribute.IsTargetAttribute(this, AttributeDescription.AssemblySignatureKeyAttribute))
{ {
......
...@@ -1813,5 +1813,24 @@ static void Main() ...@@ -1813,5 +1813,24 @@ static void Main()
CompileAndVerify(cb, expectedOutput: "42", emitOptions: TestEmitters.CCI).Diagnostics.Verify(); CompileAndVerify(cb, expectedOutput: "42", emitOptions: TestEmitters.CCI).Diagnostics.Verify();
} }
[Fact, WorkItem(1095618, "DevDiv")]
public void Bug1095618()
{
const string source = @"[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""System.Runtime.Serialization, PublicKey = 10000000000000000400000000000000"")]";
var ca = CreateCompilationWithMscorlib(source);
ca.VerifyDiagnostics(
// (1,12): warning CS1700: Assembly reference 'System.Runtime.Serialization, PublicKey = 10000000000000000400000000000000' is invalid and cannot be resolved
// [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("System.Runtime.Serialization, PublicKey = 10000000000000000400000000000000")]
Diagnostic(ErrorCode.WRN_InvalidAssemblyName, @"System.Runtime.CompilerServices.InternalsVisibleTo(""System.Runtime.Serialization, PublicKey = 10000000000000000400000000000000"")").WithArguments("System.Runtime.Serialization, PublicKey = 10000000000000000400000000000000").WithLocation(1, 12));
var verifier = CompileAndVerify(ca, symbolValidator: module =>
{
var assembly = module.ContainingAssembly;
Assert.NotNull(assembly);
Assert.False(assembly.GetAttributes().Any(attr => attr.IsTargetAttribute(assembly, AttributeDescription.InternalsVisibleToAttribute)));
});
}
#endregion #endregion
} }
...@@ -527,10 +527,14 @@ public void TryParseDisplayName_Keys() ...@@ -527,10 +527,14 @@ public void TryParseDisplayName_Keys()
TestParseDisplayName("foo, PublicKeyToken=111111111111111, Version=1.0.0.1", null); TestParseDisplayName("foo, PublicKeyToken=111111111111111, Version=1.0.0.1", null);
TestParseDisplayName("foo, PublicKeyToken=1111111111111111111, Version=1.0.0.1", null); TestParseDisplayName("foo, PublicKeyToken=1111111111111111111, Version=1.0.0.1", null);
TestParseDisplayName("foo, PublicKey=1, Version=1.0.0.1", null); TestParseDisplayName("foo, PublicKey=1, Version=1.0.0.1", null);
TestParseDisplayName("foo, PublicKey=1000000040000000", null);
// TODO: fusion doesn't accept the key TestParseDisplayName("foo, PublicKey=11, Version=1.0.0.1", null);
//TestParseDisplayName("foo, PublicKey=11, Version=1.0.0.1",
// new AssemblyIdentity("foo", new Version(1, 0, 0, 1), publicKeyOrToken: new byte[] { 0x11 }.AsImmutable(), hasPublicKey: true)); // TODO: need to calculate the correct token for the ECMA key.
// TestParseDisplayName("foo, PublicKey=0000000040000000",
// expectedParts: 0,
// expectedFusion: null, // Fusion rejects the ECMA key.
// expected: new AssemblyIdentity("foo", hasPublicKey: true, publicKeyOrToken: new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0 }.AsImmutable()));
// if public key token calculated from public key matches, then it's ok to specify both // if public key token calculated from public key matches, then it's ok to specify both
TestParseDisplayName("foo, Culture=neutral, Version=1.0.0.0, PublicKey=" + StrPublicKey1 + ", PublicKeyToken=" + StrPublicKeyToken1, TestParseDisplayName("foo, Culture=neutral, Version=1.0.0.0, PublicKey=" + StrPublicKey1 + ", PublicKeyToken=" + StrPublicKeyToken1,
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Collections;
using Roslyn.Utilities; using Roslyn.Utilities;
...@@ -275,12 +276,16 @@ public static bool TryParseDisplayName(string displayName, out AssemblyIdentity ...@@ -275,12 +276,16 @@ public static bool TryParseDisplayName(string displayName, out AssemblyIdentity
continue; continue;
} }
ImmutableArray<byte> value = ParseKey(propertyValue); ImmutableArray<byte> value;
if (value.Length == 0) if (!TryParsePublicKey(propertyValue, out value))
{ {
return false; return false;
} }
// NOTE: Fusion would also set the public key token (as derived from the public key) here.
// We may need to do this as well for error cases, as Fusion would fail to parse the
// assembly name if public key token calculation failed.
publicKey = value; publicKey = value;
parsedParts |= AssemblyIdentityParts.PublicKey; parsedParts |= AssemblyIdentityParts.PublicKey;
} }
...@@ -299,18 +304,9 @@ public static bool TryParseDisplayName(string displayName, out AssemblyIdentity ...@@ -299,18 +304,9 @@ public static bool TryParseDisplayName(string displayName, out AssemblyIdentity
} }
ImmutableArray<byte> value; ImmutableArray<byte> value;
if (string.Equals(propertyValue, "null", StringComparison.OrdinalIgnoreCase) || if (!TryParsePublicKeyToken(propertyValue, out value))
string.Equals(propertyValue, "neutral", StringComparison.OrdinalIgnoreCase))
{ {
value = ImmutableArray.Create<byte>(); return false;
}
else
{
value = ParseKey(propertyValue);
if (value.Length != PublicKeyTokenSize)
{
return false;
}
} }
publicKeyToken = value; publicKeyToken = value;
...@@ -615,23 +611,201 @@ internal static bool TryParseVersion(string str, out ulong result, out AssemblyI ...@@ -615,23 +611,201 @@ internal static bool TryParseVersion(string str, out ulong result, out AssemblyI
} }
} }
private static ImmutableArray<byte> ParseKey(string value) private static class PublicKeyDecoder
{ {
byte[] result = new byte[value.Length / 2]; private enum AlgorithmClass
for (int i = 0; i < result.Length; i++) {
Signature = 1,
Hash = 4,
}
private enum AlgorithmSubId
{
Sha1Hash = 4,
MacHash = 5,
RipeMdHash = 6,
RipeMd160Hash = 7,
Ssl3ShaMD5Hash = 8,
HmacHash = 9,
Tls1PrfHash = 10,
HashReplacOwfHash = 11,
Sha256Hash = 12,
Sha384Hash = 13,
Sha512Hash = 14,
}
private struct AlgorithmId
{
// From wincrypt.h
private const int AlgorithmClassOffset = 13;
private const int AlgorithmClassMask = 0x7;
private const int AlgorithmSubIdOffset = 0;
private const int AlgorithmSubIdMask = 0x1ff;
private readonly uint flags;
public bool IsSet
{
get { return flags != 0; }
}
public AlgorithmClass Class
{
get { return (AlgorithmClass)((flags >> AlgorithmClassOffset) & AlgorithmClassMask); }
}
public AlgorithmSubId SubId
{
get { return (AlgorithmSubId)((flags >> AlgorithmSubIdOffset) & AlgorithmSubIdMask); }
}
public AlgorithmId(uint flags)
{
this.flags = flags;
}
}
// From ECMAKey.h
private static readonly ImmutableArray<byte> ecmaKey = ImmutableArray.Create(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0 });
// From strongname.h
[StructLayout(LayoutKind.Sequential, Pack = 0)]
private unsafe struct PublicKeyHeader
{
public const int SigAlgIdOffset = 0;
public const int HashAlgIdOffset = SigAlgIdOffset + sizeof(uint);
public const int PublicKeySizeOffset = HashAlgIdOffset + sizeof(uint);
public const int PublicKeyDataOffset = PublicKeySizeOffset + sizeof(uint);
public const int Size = PublicKeyDataOffset;
uint SigAlgId;
uint HashAlgId;
uint PublicKeySize;
}
// From wincrypt.h
private const byte PublicKeyBlob = 0x06;
// From StrongNameInternal.cpp
public static bool TryDecode(byte[] bytes, out ImmutableArray<byte> key)
{
// The number of public key bytes must be at least large enough for the header and one byte of data.
if (bytes.Length < PublicKeyHeader.Size + 1)
{
key = default(ImmutableArray<byte>);
return false;
}
// The number of public key bytes must be the same as the size of the header plus the size of the public key data.
var dataSize = (uint)BitConverter.ToInt32(bytes, PublicKeyHeader.PublicKeySizeOffset);
if (bytes.Length != PublicKeyHeader.Size + dataSize)
{
key = default(ImmutableArray<byte>);
return false;
}
// Check for ECMA key
if (bytes.Length == ecmaKey.Length)
{
for (int i = 0; i < bytes.Length; i++)
{
if (bytes[i] != ecmaKey[i])
{
goto notEcmaKey;
}
}
key = ecmaKey;
return true;
}
notEcmaKey:
var signatureAlgorithmId = new AlgorithmId((uint)BitConverter.ToInt32(bytes, 0));
if (signatureAlgorithmId.IsSet && signatureAlgorithmId.Class != AlgorithmClass.Signature)
{
key = default(ImmutableArray<byte>);
return false;
}
var hashAlgorithmId = new AlgorithmId((uint)BitConverter.ToInt32(bytes, 4));
if (hashAlgorithmId.IsSet && (hashAlgorithmId.Class != AlgorithmClass.Hash || hashAlgorithmId.SubId < AlgorithmSubId.Sha1Hash))
{
key = default(ImmutableArray<byte>);
return false;
}
if (bytes[PublicKeyHeader.PublicKeyDataOffset] != PublicKeyBlob)
{
key = default(ImmutableArray<byte>);
return false;
}
key = bytes.AsImmutable();
return true;
}
}
const int MaxPublicKeyBytes = 2048;
private static bool TryParsePublicKey(string value, out ImmutableArray<byte> key)
{
byte[] result;
if (value.Length > (MaxPublicKeyBytes * 2) || !TryParseHexBytes(value, out result))
{
key = default(ImmutableArray<byte>);
return false;
}
return PublicKeyDecoder.TryDecode(result, out key);
}
const int PublicKeyTokenBytes = 8;
private static bool TryParsePublicKeyToken(string value, out ImmutableArray<byte> token)
{
if (string.Equals(value, "null", StringComparison.OrdinalIgnoreCase) ||
string.Equals(value, "neutral", StringComparison.OrdinalIgnoreCase))
{
token = ImmutableArray<byte>.Empty;
return true;
}
byte[] result;
if (value.Length != (PublicKeyTokenBytes * 2) || !TryParseHexBytes(value, out result))
{
token = default(ImmutableArray<byte>);
return false;
}
token = result.AsImmutable();
return true;
}
private static bool TryParseHexBytes(string value, out byte[] result)
{
if (value.Length == 0 || (value.Length % 2) != 0)
{
result = null;
return false;
}
var bytes = new byte[value.Length / 2];
for (int i = 0; i < bytes.Length; i++)
{ {
int hi = HexValue(value[i * 2]); int hi = HexValue(value[i * 2]);
int lo = HexValue(value[i * 2 + 1]); int lo = HexValue(value[i * 2 + 1]);
if (hi < 0 || lo < 0) if (hi < 0 || lo < 0)
{ {
return ImmutableArray.Create<byte>(); result = null;
return false;
} }
result[i] = (byte)((hi << 4) | lo); bytes[i] = (byte)((hi << 4) | lo);
} }
return result.AsImmutable(); result = bytes;
return true;
} }
internal static int HexValue(char c) internal static int HexValue(char c)
......
...@@ -1616,4 +1616,17 @@ End Class]]> ...@@ -1616,4 +1616,17 @@ End Class]]>
CompileAndVerify(cb, expectedOutput:="42", emitOptions:=TestEmitters.CCI).Diagnostics.Verify() CompileAndVerify(cb, expectedOutput:="42", emitOptions:=TestEmitters.CCI).Diagnostics.Verify()
End Sub End Sub
<Fact, WorkItem(1095618, "DevDiv")>
Public Sub Bug1095618()
Dim source As XElement = _
<compilation name="a">
<file name="a.vb"><![CDATA[
<Assembly: System.Runtime.CompilerServices.InternalsVisibleTo("System.Runtime.Serialization, PublicKey = 10000000000000000400000000000000")>
]]></file>
</compilation>
CreateCompilationWithMscorlib(source).VerifyDiagnostics(
Diagnostic(ERRID.ERR_FriendAssemblyNameInvalid, "Assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""System.Runtime.Serialization, PublicKey = 10000000000000000400000000000000"")").WithArguments("System.Runtime.Serialization, PublicKey = 10000000000000000400000000000000").WithLocation(1, 2))
End Sub
End Class End Class
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册