Skip to content

Commit 0faaeea

Browse files
MarcoRossignolitonerdo
authored andcommitted
Skip instrumentation of module with embedded ppbd without local sources (#510)
* handle ppbd without local sources * add test * nit formatting * check all docs existence * update tests
1 parent 872e087 commit 0faaeea

File tree

4 files changed

+86
-3
lines changed

4 files changed

+86
-3
lines changed

src/coverlet.core/Helpers/InstrumentationHelper.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.IO;
66
using System.Linq;
77
using System.Reflection;
8+
using System.Reflection.Metadata;
89
using System.Reflection.PortableExecutable;
910
using System.Text.RegularExpressions;
1011
using Coverlet.Core.Abstracts;
@@ -67,8 +68,9 @@ public static string[] GetCoverableModules(string module, string[] directories,
6768
.ToArray();
6869
}
6970

70-
public static bool HasPdb(string module)
71+
public static bool HasPdb(string module, out bool embedded)
7172
{
73+
embedded = false;
7274
using (var moduleStream = File.OpenRead(module))
7375
using (var peReader = new PEReader(moduleStream))
7476
{
@@ -80,6 +82,7 @@ public static bool HasPdb(string module)
8082
if (codeViewData.Path == $"{Path.GetFileNameWithoutExtension(module)}.pdb")
8183
{
8284
// PDB is embedded
85+
embedded = true;
8386
return true;
8487
}
8588

@@ -91,6 +94,41 @@ public static bool HasPdb(string module)
9194
}
9295
}
9396

97+
public static bool EmbeddedPortablePdbHasLocalSource(string module)
98+
{
99+
using (FileStream moduleStream = File.OpenRead(module))
100+
using (var peReader = new PEReader(moduleStream))
101+
{
102+
foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
103+
{
104+
if (entry.Type == DebugDirectoryEntryType.EmbeddedPortablePdb)
105+
{
106+
using (MetadataReaderProvider embeddedMetadataProvider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(entry))
107+
{
108+
MetadataReader metadataReader = embeddedMetadataProvider.GetMetadataReader();
109+
foreach (DocumentHandle docHandle in metadataReader.Documents)
110+
{
111+
Document document = metadataReader.GetDocument(docHandle);
112+
string docName = metadataReader.GetString(document.Name);
113+
114+
// We verify all docs and return false if not all are present in local
115+
// We could have false negative if doc is not a source
116+
// Btw check for all possible extension could be weak approach
117+
if (!File.Exists(docName))
118+
{
119+
return false;
120+
}
121+
}
122+
}
123+
}
124+
}
125+
}
126+
127+
// If we don't have EmbeddedPortablePdb entry return true, for instance empty dll
128+
// We should call this method only on embedded pdb module
129+
return true;
130+
}
131+
94132
public static void BackupOriginalModule(string module, string identifier)
95133
{
96134
var backupPath = GetBackupPath(module, identifier);

src/coverlet.core/Instrumentation/Instrumenter.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,29 @@ public bool CanInstrument()
5454
{
5555
try
5656
{
57-
return InstrumentationHelper.HasPdb(_module);
57+
if (InstrumentationHelper.HasPdb(_module, out bool embeddedPdb))
58+
{
59+
if (embeddedPdb)
60+
{
61+
if (InstrumentationHelper.EmbeddedPortablePdbHasLocalSource(_module))
62+
{
63+
return true;
64+
}
65+
else
66+
{
67+
_logger.LogWarning($"Unable to instrument module: {_module}, embedded pdb without local source files");
68+
return false;
69+
}
70+
}
71+
else
72+
{
73+
return true;
74+
}
75+
}
76+
else
77+
{
78+
return false;
79+
}
5880
}
5981
catch (Exception ex)
6082
{

test/coverlet.core.tests/Helpers/InstrumentationHelperTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ public void TestGetDependenciesWithTestAssembly()
2727
[Fact]
2828
public void TestHasPdb()
2929
{
30-
Assert.True(InstrumentationHelper.HasPdb(typeof(InstrumentationHelperTests).Assembly.Location));
30+
Assert.True(InstrumentationHelper.HasPdb(typeof(InstrumentationHelperTests).Assembly.Location, out bool embeddedPdb));
31+
Assert.False(embeddedPdb);
3132
}
3233

3334
[Fact]

test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using System.Reflection;
55

6+
using Coverlet.Core.Helpers;
67
using Coverlet.Core.Logging;
78
using Coverlet.Core.Samples.Tests;
89
using Microsoft.CodeAnalysis;
@@ -231,5 +232,26 @@ public void TestInstrument_NetStandardAwareAssemblyResolver_FromFolder()
231232
// We check if final netstandard.dll resolved is local folder one and not "official" netstandard.dll
232233
Assert.Equal(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "netstandard.dll"), Path.GetFullPath(resolved.MainModule.FileName));
233234
}
235+
236+
[Fact]
237+
public void SkipEmbeddedPpdbWithoutLocalSource()
238+
{
239+
string xunitDll = Directory.GetFiles(Directory.GetCurrentDirectory(), "xunit.*.dll").First();
240+
var loggerMock = new Mock<ILogger>();
241+
Instrumenter instrumenter = new Instrumenter(xunitDll, "_xunit_instrumented", Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(), false, loggerMock.Object);
242+
Assert.True(InstrumentationHelper.HasPdb(xunitDll, out bool embedded));
243+
Assert.True(embedded);
244+
Assert.False(instrumenter.CanInstrument());
245+
loggerMock.Verify(l => l.LogWarning(It.IsAny<string>()));
246+
247+
// Default case
248+
string coverletCoreDll = Directory.GetFiles(Directory.GetCurrentDirectory(), "coverlet.core.dll").First();
249+
instrumenter = new Instrumenter(coverletCoreDll, "_coverlet_core_instrumented", Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(), false, loggerMock.Object);
250+
Assert.True(InstrumentationHelper.HasPdb(coverletCoreDll, out embedded));
251+
Assert.False(embedded);
252+
Assert.True(instrumenter.CanInstrument());
253+
loggerMock.VerifyNoOtherCalls();
254+
}
255+
234256
}
235257
}

0 commit comments

Comments
 (0)