Open maxkatz6 opened 8 months ago
Also, unrelated to the original issue, and could be my misunderstanding, but I can't really run this code:
var filePath = args[0];
var asm = AssemblyDef.Load(filePath);
...
asm.Write(filePath, writerParameters);
as it will fail with System.IO.IOException: The requested operation cannot be performed on a file with a user-mapped section open.
. Does dnLib hold file open after loading while trying to write to the same file?
It's memory mapped and you're using Windows which doesn't allow writing to the file until it's closed. You could instead read all bytes from the file and pass in the byte[] to the Load() method to load it that way and nothing gets memory mapped.
I think you need to add an assembly resolver to fix this. See the README on how to do that.
It's memory mapped and you're using Windows which doesn't allow writing to the file until it's closed. You could instead read all bytes from the file and pass in the byte[] to the Load() method to load it that way and nothing gets memory mapped.
Yeah, reading from byte array works fine. That's what I also did in the sample.
I think you need to add an assembly resolver to fix this. See the README on how to do that.
Hm. In my actual project I did use an assembly resolver, where I initially found this issue. I trimmed everything down until I got this minimal sample.
I can try to update the repro of the issue, but it still fails with resolver. And removing const
magically solves the issue.
Make sure the assembly resolver finds the assembly with the enum CompareOptions and any other assemblies it references, if any.
I met this issue, too. Could we just skip this error? Sometimes we cannot find every dll reference, but we still want some pdb info kept. However with this issue we can only get an empty pdb.
I have written some simple code to bypass this but I don't know if it will cause more problems, like making this pdb unusable.
case ElementType.Class when value is not byte[] && value is not null:
var realElementType = ConstantUser.GetElementType(value);
if (realElementType != ElementType.End) {
writer.WriteByte((byte)realElementType);
WritePrimitiveValue(writer, realElementType, value);
WriteTypeDefOrRef(writer, type.ToTypeDefOrRef());
return;
}
break;
As a workaround, you can remove the "invalid" constants from the PDB:
foreach (MethodDef method in new MemberFinder().FindAll(module).MethodDefs.Keys)
{
IList<PdbConstant>? constants = method.Body?.PdbMethod?.Scope?.Constants;
if (constants is not null)
{
for (int i = constants.Count - 1; i >= 0; i--)
{
// workaround for https://github.com/0xd4d/dnlib/issues/550
// remove any constant with a reference type where the value is not a byte[] or null.
PdbConstant constant = constants[i];
if (constant.Type?.ElementType is ElementType.Class &&
constant.Value is not null and not byte[])
{
constants.RemoveAt(i);
}
}
}
}
I noticed this issue only happens when I used "local const" in the code, specifically when const type is an enum from another assembly. For example, this method:
Simply replacing
const CompareOptions options
withCompareOptions options
will fix the problem, so we have a workaround, though this bug is confusing. Repro project (both dll project and executable console app):ClassLibrary1.zip