Locate references to bad compiler generated methods in sandbox

Should help pinpoint issues from params arrays and similar.
This commit is contained in:
PJB3005
2026-01-30 10:19:57 +01:00
parent 72d6a42c27
commit 8449015cf8
3 changed files with 38 additions and 11 deletions

View File

@@ -39,7 +39,7 @@ END TEMPLATE-->
### New features
*None yet*
* If a sandbox error is caused by a compiler-generated method, the engine will now attempt to point out which using code is responsible.
### Bugfixes

View File

@@ -14,12 +14,9 @@ namespace Robust.Shared.ContentPack;
internal sealed partial class AssemblyTypeChecker
{
// This part of the code tries to find the originator of bad sandbox references.
private void ReportBadReferences(PEReader peReader, MetadataReader reader, IEnumerable<EntityHandle> reference)
private IEnumerable<(EntityHandle Referenced, MethodDefinitionHandle SourceMethod, int InstructionOffset)> FindReference(PEReader peReader, MetadataReader reader, params IEnumerable<EntityHandle> handles)
{
_sawmill.Info("Started search for originator of bad references...");
var refs = reference.ToHashSet();
var refs = handles.ToHashSet();
ExpandReferences(reader, refs);
foreach (var methodDefHandle in reader.MethodDefinitions)
@@ -28,8 +25,6 @@ internal sealed partial class AssemblyTypeChecker
if (methodDef.RelativeVirtualAddress == 0)
continue;
var methodName = reader.GetString(methodDef.Name);
var body = peReader.GetMethodBody(methodDef.RelativeVirtualAddress);
var bytes = body.GetILBytes()!;
@@ -41,9 +36,7 @@ internal sealed partial class AssemblyTypeChecker
{
if (refs.Overlaps(ExpandHandle(reader, handle)))
{
var type = GetTypeFromDefinition(reader, methodDef.GetDeclaringType());
_sawmill.Error(
$"Found reference to {DisplayHandle(reader, handle)} in method {type}.{methodName} at IL 0x{prefPosition:X4}");
yield return (handle, methodDefHandle, prefPosition);
}
}
@@ -52,6 +45,19 @@ internal sealed partial class AssemblyTypeChecker
}
}
private void ReportBadReferences(PEReader peReader, MetadataReader reader, IEnumerable<EntityHandle> reference)
{
foreach (var (referenced, method, ilOffset) in FindReference(peReader, reader, reference))
{
var methodDef = reader.GetMethodDefinition(method);
var methodName = reader.GetString(methodDef.Name);
var type = GetTypeFromDefinition(reader, methodDef.GetDeclaringType());
_sawmill.Error(
$"Found reference to {DisplayHandle(reader, referenced)} in method {type}.{methodName} at IL 0x{ilOffset:X4}");
}
}
private static string DisplayHandle(MetadataReader reader, EntityHandle handle)
{
switch (handle.Kind)

View File

@@ -227,6 +227,8 @@ namespace Robust.Shared.ContentPack
#if TOOLS
if (!badRefs.IsEmpty)
{
_sawmill.Info("Started search for originator of bad references...");
ReportBadReferences(peReader, reader, badRefs);
}
#endif
@@ -298,6 +300,9 @@ namespace Robust.Shared.ContentPack
verifyErrors = true;
_sawmill.Error(msg);
if (!res.Method.IsNil)
PrintCompilerGeneratedMethodUsage(peReader, reader, res.Method);
}
_sawmill.Debug($"{name}: Verified IL in {sw.Elapsed.TotalMilliseconds}ms");
@@ -310,6 +315,22 @@ namespace Robust.Shared.ContentPack
return true;
}
private void PrintCompilerGeneratedMethodUsage(
PEReader peReader,
MetadataReader reader,
MethodDefinitionHandle method)
{
var methodDef = reader.GetMethodDefinition(method);
var type = GetTypeFromDefinition(reader, methodDef.GetDeclaringType());
if (!type.Name.Contains('<'))
return;
_sawmill.Error("Hint: method is compiler-generated. Check for params collections and/or collection expressions:");
ReportBadReferences(peReader, reader, [method]);
}
private static string FormatMethodName(MetadataReader reader, MethodDefinition method)
{
var methodSig = method.DecodeSignature(new TypeProvider(), 0);