ExceptionInspector throws NullReferenceException every frame when a patch method belongs to no mod (dynamic assembly)

Abierto Apto para principiantes
#7 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
76/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
csharp
Área
game-dev

Línea de trabajo

Empieza con Mods.AddMetadata y luego sigue cómo ExceptionInfo.GetReport crea los detalles del mod y cómo Columns.Column usa sus metadatos. Reproduce el problema con un método de parche de Harmony de un ensamblado dinámico y una excepción que pase por él. El trabajo estará terminado cuando abrir el inspector ya no provoque excepciones repetidas para los parches sin metadatos del mod.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Summary

When a captured exception has a stack frame whose method carries a Harmony patch from an assembly that no mod owns (for example a runtime-generated assembly), the inspector window throws a NullReferenceException on every frame. The log fills with thousands of errors and the window cannot be used.

Seen with Visual Exceptions 1.5.0.0 on RimWorld 1.7.5005, Harmony 3.

Cause

Mods.AddMetadata creates a ModInfo for every patch method, also when GetModMetaData(assembly) returns null:

static IEnumerable<ModInfo> AddMetadata(IEnumerable<MethodInfo> methods)
{
    return methods.Select(method =>
    {
        var assembly = method.DeclaringType.Assembly;
        var metaData = GetModMetaData(assembly);
        return new ModInfo { method = method, metaData = metaData };
    });
}

ExceptionInfo.GetReport then adds an ExceptionDetails.Mod with meta == null, and Columns.Column(this ExceptionDetails.Mod mod) dereferences it:

var name = mod.meta.Name.Truncate(200, truncatedModNamesCache);

Stack frames do not have this problem, because GetMetadataIfMod returns null for non-mod code and GetAllMethods skips those. Only patches are missing the check.

How it showed up

A player ran the Overclock mod with "Parallel pawn ticks (experimental)" on. That feature builds its prefix classes at runtime with AssemblyBuilder.DefineDynamicAssembly (types named IdPrefix_<n>_<method> and IdState_<n>) and patches thousands of mod methods with them. Those types are in no mod's loadedAssemblies.

During loading, another mod requested a graphic with a null texture path, which throws ArgumentNullException in ContentFinder<Texture2D>.Get. One frame of that exception had such a generated prefix on it. Once the inspector opened at the main menu:

Exception filling window for VisualExceptions.ExceptionInspector: System.NullReferenceException: Object reference not set to an instance of an object.
   at VisualExceptions.Columns.Column_Patch1(Mod mod)
   at VisualExceptions.ExceptionInspector.<>c.<DoWindowContents>b__9_2(Mod mod)
   at System.Linq.Enumerable.ListSelectIterator`2.MoveNext()
   at System.Linq.Enumerable.MaxFloat[TSource,TResult](IEnumerable`1 source, Func`2 selector)
   at VisualExceptions.Columns.MaxWidth(IEnumerable`1 drawers)
   at VisualExceptions.ExceptionInspector.DoWindowContents_Patch1(ExceptionInspector this, Rect inRect)
   at Verse.Window.InnerWindowOnGUI_Patch3(Window this, Int32 x)

This repeated 2,515 times in under a minute.

Steps to reproduce

  1. Have any Harmony patch whose patch method is declared in a dynamic assembly, on a method of a mod.
  2. Throw an exception that passes through that method and is caught by one of the handlers Visual Exceptions instruments.
  3. Open the inspector.
Lenguaje dominante
C#
Estrellas
10
Forks
2
Métricas de merge de PR
Sin PR fusionados en 30 d

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Issues similares

Más issues de C#

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.