Skip to content

Instantly share code, notes, and snippets.

@jaredpar
Created August 30, 2023 17:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jaredpar/ef5c3801fca5727c2b5cfbe21c8b8387 to your computer and use it in GitHub Desktop.
Save jaredpar/ef5c3801fca5727c2b5cfbe21c8b8387 to your computer and use it in GitHub Desktop.
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
Console.WriteLine(IsNullableEnabledAtBuild(@"C:\Users\jaredpar\temp\console\bin\Debug\net7.0\console.dll", out var reason));
Console.WriteLine(reason);
static bool IsNullableEnabledAtBuild(string assemblyFilePath, out string? reason)
{
MetadataReaderProvider? pdbReaderProvider = null;
try
{
using var reader = new FileStream(assemblyFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
using var peReader = new PEReader(reader);
if (!peReader.TryOpenAssociatedPortablePdb(assemblyFilePath, OpenPortablePdbFile, out pdbReaderProvider, out var pdbPath))
{
reason = $"Can't find portable pdb file for {assemblyFilePath}";
return false;
}
var compilationOptionsGuid = new Guid("B5FEEC05-8CD0-4A83-96DA-466284BB4BD8");
var pdbReader = pdbReaderProvider!.GetMetadataReader();
if (!TryGetCustomDebugInformationBlobReader(pdbReader, compilationOptionsGuid, out var blobReader))
{
reason = "Cannot find compilation options section";
return false;
}
return GetNullableOption(blobReader, out reason);
}
catch (Exception ex)
{
reason = ex.Message;
return false;
}
finally
{
pdbReaderProvider?.Dispose();
}
static bool GetNullableOption(BlobReader blobReader, out string? reason)
{
for (;;)
{
var nullIndex = blobReader.IndexOf(0);
if (nullIndex == -1)
{
break;
}
var key = blobReader.ReadUTF8(nullIndex);
blobReader.ReadByte(); // Skip null terminator
nullIndex = blobReader.IndexOf(0);
if (nullIndex == -1)
{
break;
}
var value = blobReader.ReadUTF8(nullIndex);
blobReader.ReadByte(); // Skip null terminator
if (key == "nullable")
{
reason = null;
return string.Equals(value, "enable", StringComparison.OrdinalIgnoreCase);
}
}
reason = "Cannot find compiler option";
return false;
}
static bool TryGetCustomDebugInformationBlobReader(MetadataReader pdbReader, Guid infoGuid, out BlobReader blobReader)
{
var blobs = from cdiHandle in pdbReader.GetCustomDebugInformation(EntityHandle.ModuleDefinition)
let cdi = pdbReader.GetCustomDebugInformation(cdiHandle)
where pdbReader.GetGuid(cdi.Kind) == infoGuid
select pdbReader.GetBlobReader(cdi.Value);
if (blobs.Any())
{
blobReader = blobs.Single();
return true;
}
blobReader = default;
return false;
}
static Stream? OpenPortablePdbFile(string filePath)
{
if (!File.Exists(filePath))
{
return null;
}
return new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment