Open
Description
Description
Calling ISymbolDocumentWriter.SetChecksum
on a ISymbolDocumentWriter
returned from ModuleBuilder.DefineDocument
results in a pdb with a document table containing a document with a Hash
field that is an invalid blob handle.
I've traced the problem to this line:
That line should refer to _pdbBuilder
, not _metadataBuilder
. Because it's _metadataBuilder
, the blob handle actually points into the blob heap in the emitted .dll, not the .pdb.
I'll put up a PR with the fix.
Reproduction Steps
using System.Diagnostics.SymbolStore;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
namespace System.Reflection.Emit.Tests;
public class PortablePdbStandalonePdbTest
{
private static readonly Guid HashAlgorithmSha256 = new Guid("8829d00f-11b8-4213-878b-770e8597ac16");
private static readonly byte[] TestHash = Convert.FromHexString("06CBAB3A501306FDD9176A00A83E5BB92EA4D7863CFD666355743527CF99EDC6");
public static void Main()
{
var pdbFile = Path.GetTempFileName();
var file = Path.GetTempFileName();
try
{
MetadataBuilder metadataBuilder = GenerateAssemblyAndMetadata(out var entryPoint, out BlobBuilder ilStream, out MetadataBuilder pdbMetadata);
MethodDefinitionHandle entryPointHandle = MetadataTokens.MethodDefinitionHandle(entryPoint.MetadataToken);
BlobBuilder portablePdbBlob = new BlobBuilder();
PortablePdbBuilder pdbBuilder = new PortablePdbBuilder(pdbMetadata, metadataBuilder.GetRowCounts(), entryPointHandle);
BlobContentId pdbContentId = pdbBuilder.Serialize(portablePdbBlob);
using var pdbFileStream = new FileStream(pdbFile, FileMode.Create, FileAccess.Write);
portablePdbBlob.WriteContentTo(pdbFileStream);
pdbFileStream.Close();
DebugDirectoryBuilder debugDirectoryBuilder = new DebugDirectoryBuilder();
debugDirectoryBuilder.AddCodeViewEntry(pdbFile, pdbContentId, pdbBuilder.FormatVersion);
ManagedPEBuilder peBuilder = new ManagedPEBuilder(
header: new PEHeaderBuilder(imageCharacteristics: Characteristics.ExecutableImage),
metadataRootBuilder: new MetadataRootBuilder(metadataBuilder),
ilStream: ilStream,
debugDirectoryBuilder: debugDirectoryBuilder,
entryPoint: entryPointHandle);
BlobBuilder peBlob = new BlobBuilder();
peBuilder.Serialize(peBlob);
using var assemblyFileStream = new FileStream(file, FileMode.Create, FileAccess.Write);
peBlob.WriteContentTo(assemblyFileStream);
assemblyFileStream.Close();
using var fs = new FileStream(pdbFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using MetadataReaderProvider provider = MetadataReaderProvider.FromPortablePdbStream(fs);
ValidatePDB(provider.GetMetadataReader());
}
finally
{
File.Delete(pdbFile);
File.Delete(file);
}
}
private static MetadataBuilder GenerateAssemblyAndMetadata(
out MethodBuilder entryPoint, out BlobBuilder ilStream, out MetadataBuilder pdbMetadata)
{
PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("MyAssembly2"), typeof(object).Assembly);
ModuleBuilder mb = ab.DefineDynamicModule("MyModule2");
TypeBuilder tb = mb.DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);
ISymbolDocumentWriter srcdoc = mb.DefineDocument("MySourceFile.cs", SymLanguageType.CSharp);
srcdoc.SetCheckSum(HashAlgorithmSha256, TestHash);
entryPoint = tb.DefineMethod("Mm", MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static);
ILGenerator il2 = entryPoint.GetILGenerator();
il2.MarkSequencePoint(srcdoc, 12, 0, 12, 37);
il2.Emit(OpCodes.Ret);
tb.CreateType();
return ab.GenerateMetadata(out ilStream, out BlobBuilder _, out pdbMetadata);
}
private static void ValidatePDB(MetadataReader reader)
{
var docHandle = reader.Documents.Single();
Document doc = reader.GetDocument(docHandle);
if (reader.GetGuid(doc.HashAlgorithm) != HashAlgorithmSha256)
{
throw new Exception("Incorrect hash algorithm");
}
if (!reader.GetBlobBytes(doc.Hash).SequenceEqual(TestHash))
{
throw new Exception("Incorrect hash");
}
}
}
Expected behavior
I expect the repro above to succeed.
Actual behavior
It crashes while attempting to retrieve the blob bytes corresponding to the document's Hash
blob handle:
Regression?
No response
Known Workarounds
No response
Configuration
.NET 9.0, Windows x64
Other information
No response