Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ static bool HasResourceDesignerAssemblyReference (ITaskItem assembly)
return false;
}
using var pe = new PEReader (File.OpenRead (assembly.ItemSpec));
if (!pe.HasMetadata) {
return false;
}
var reader = pe.GetMetadataReader ();
return HasResourceDesignerAssemblyReference (reader);
}
Expand Down
4 changes: 4 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/FilterAssemblies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ public override bool RunTask ()
void ProcessAssembly(ITaskItem assemblyItem, List<ITaskItem> output)
{
using var pe = new PEReader (File.OpenRead (assemblyItem.ItemSpec));
if (!pe.HasMetadata) {
Log.LogDebugMessage ($"Skipping non-.NET assembly: {assemblyItem.ItemSpec}");
return;
}
var reader = pe.GetMetadataReader ();
// Check in-memory cache
var module = reader.GetModuleDefinition ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@ void Extract (
Log.LogDebugMessage ($"Refreshing {fileName}");

using (var pe = new PEReader (File.OpenRead (assemblyPath))) {
if (!pe.HasMetadata) {
Log.LogDebugMessage ($"Skipping non-.NET assembly: {assemblyPath}");
continue;
}
var reader = pe.GetMetadataReader ();
foreach (var handle in reader.ManifestResources) {
var resource = reader.GetManifestResource (handle);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,78 @@ public async Task GuavaListenableFuture ()
var expected = new [] { "Xamarin.Google.Guava.ListenableFuture.dll" };
CollectionAssert.AreEqual (expected, actual);
}

[Test]
public void NativeDll_Skipped ()
{
// Create a minimal valid PE file without CLI metadata (a native DLL)
var nativeDll = Path.Combine (tempDirectory, "native.dll");
CreateNativePE (nativeDll);
var actual = Run (nativeDll);
CollectionAssert.IsEmpty (actual, "Native DLLs without CLI metadata should be skipped.");
}

/// <summary>
/// Creates a minimal valid PE file without CLI metadata, simulating a native DLL.
/// </summary>
static void CreateNativePE (string path)
{
using var fs = File.Create (path);
using var writer = new BinaryWriter (fs);

// DOS header: 'MZ' magic + padding to e_lfanew at offset 0x3C
writer.Write ((ushort) 0x5A4D); // e_magic = 'MZ'
writer.Write (new byte [58]); // pad to offset 0x3C
writer.Write ((uint) 0x80); // e_lfanew = 0x80

// Pad to PE signature at offset 0x80
writer.Write (new byte [0x80 - 0x40]);

// PE signature: 'PE\0\0'
writer.Write ((uint) 0x00004550);

// COFF header (20 bytes)
writer.Write ((ushort) 0x14C); // Machine = IMAGE_FILE_MACHINE_I386
writer.Write ((ushort) 0); // NumberOfSections = 0
writer.Write ((uint) 0); // TimeDateStamp
writer.Write ((uint) 0); // PointerToSymbolTable
writer.Write ((uint) 0); // NumberOfSymbols
writer.Write ((ushort) 0xE0); // SizeOfOptionalHeader (PE32)
writer.Write ((ushort) 0x2102); // Characteristics = DLL | EXECUTABLE_IMAGE | LARGE_ADDRESS_AWARE

// Optional header (PE32) — minimal, no CLI header directory entry
writer.Write ((ushort) 0x10B); // Magic = PE32
writer.Write ((byte) 0); // MajorLinkerVersion
writer.Write ((byte) 0); // MinorLinkerVersion
writer.Write ((uint) 0); // SizeOfCode
writer.Write ((uint) 0); // SizeOfInitializedData
writer.Write ((uint) 0); // SizeOfUninitializedData
writer.Write ((uint) 0); // AddressOfEntryPoint
writer.Write ((uint) 0); // BaseOfCode
writer.Write ((uint) 0); // BaseOfData
writer.Write ((uint) 0x10000); // ImageBase
writer.Write ((uint) 0x1000); // SectionAlignment
writer.Write ((uint) 0x200); // FileAlignment
writer.Write ((ushort) 4); // MajorOperatingSystemVersion
writer.Write ((ushort) 0); // MinorOperatingSystemVersion
writer.Write ((ushort) 0); // MajorImageVersion
writer.Write ((ushort) 0); // MinorImageVersion
writer.Write ((ushort) 4); // MajorSubsystemVersion
writer.Write ((ushort) 0); // MinorSubsystemVersion
writer.Write ((uint) 0); // Win32VersionValue
writer.Write ((uint) 0x1000); // SizeOfImage
writer.Write ((uint) 0x200); // SizeOfHeaders
writer.Write ((uint) 0); // CheckSum
writer.Write ((ushort) 3); // Subsystem = WINDOWS_CUI
writer.Write ((ushort) 0); // DllCharacteristics
writer.Write ((uint) 0x100000); // SizeOfStackReserve
writer.Write ((uint) 0x1000); // SizeOfStackCommit
writer.Write ((uint) 0x100000); // SizeOfHeapReserve
writer.Write ((uint) 0x1000); // SizeOfHeapCommit
writer.Write ((uint) 0); // LoaderFlags
writer.Write ((uint) 16); // NumberOfRvaAndSizes
// Data directories (16 entries × 8 bytes = 128 bytes), all zeroed — no CLI header
writer.Write (new byte [128]);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ public MetadataReader GetAssemblyReader (string assemblyName)
{
var assemblyPath = Resolve (assemblyName);
if (!cache.TryGetValue (assemblyPath, out PEReader reader)) {
cache.Add (assemblyPath, reader = new PEReader (File.OpenRead (assemblyPath)));
reader = new PEReader (File.OpenRead (assemblyPath));
if (!reader.HasMetadata) {
reader.Dispose ();
throw new InvalidOperationException ($"Assembly '{assemblyPath}' is not a .NET assembly.");
}
cache.Add (assemblyPath, reader);
}
return reader.GetMetadataReader ();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@ public static bool HasMonoAndroidReference (ITaskItem assembly)
return true;

using var pe = new PEReader (File.OpenRead (assembly.ItemSpec));
if (!pe.HasMetadata) {
return false; // not a .NET assembly (no CLI metadata)
}
var reader = pe.GetMetadataReader ();
return HasMonoAndroidReference (reader);
}
Expand All @@ -374,6 +377,10 @@ public static bool IsReferenceAssembly (string assembly, TaskLoggingHelper log)
{
using (var stream = File.OpenRead (assembly))
using (var pe = new PEReader (stream)) {
if (!pe.HasMetadata) {
log.LogDebugMessage ($"Skipping non-.NET assembly: {assembly}");
return false;
}
var reader = pe.GetMetadataReader ();
var assemblyDefinition = reader.GetAssemblyDefinition ();
foreach (var handle in assemblyDefinition.GetCustomAttributes ()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ public void CreateImportMethods (IEnumerable<ITaskItem> libraries)
primary.Members.Add (method);
foreach (var assemblyPath in libraries) {
using (var pe = new PEReader (File.OpenRead (assemblyPath.ItemSpec))) {
if (!pe.HasMetadata) {
Log.LogDebugMessage ($"Skipping non-.NET assembly: {assemblyPath.ItemSpec}");
continue;
}
var reader = pe.GetMetadataReader ();
var resourceDesignerName = GetResourceDesignerClass (reader);
if (string.IsNullOrEmpty (resourceDesignerName)) {
Expand Down