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

Aberta Para iniciantes
#7 0 comentários 0 reações 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
2/5
Tempo estimado
1-3 horas
Facilidade para iniciantes
76/100
Tipo de issue
Bug
Clareza
Claramente especificada
Status de atividade
Ativa
Stack de tecnologia
csharp
Domínio
game-dev

Direção de pesquisa

Comece por Mods.AddMetadata e depois acompanhe como ExceptionInfo.GetReport cria os detalhes do mod e como Columns.Column usa os metadados deles. Reproduza o problema com um método de patch Harmony de um assembly dinâmico e uma exceção que passe por ele. O trabalho estará concluído quando abrir o inspector não causar mais exceções repetidas para patches sem metadados do mod.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

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.
Linguagem predominante
C#
Estrelas
10
Forks
2
Métricas de merge de PRs
Nenhum PR com merge em 30d

Preparar o ambiente

Este projeto não oferece contêiner de desenvolvimento, Dockerfile nem guia de contribuição, então a configuração fica por sua conta: comece pelo README e veja nosso guia da primeira contribuição para os passos gerais.

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Issues semelhantes

Mais issues de C#

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.