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

未關閉 適合新手
#7 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

評估

難度
2/5
預估耗時
1-3 小時
新手友好度
76/100
Issue 類型
缺陷
描述清晰度
描述清楚
活躍度
活躍
技術堆疊
csharp
領域
game-dev

研究方向

從 Mods.AddMetadata 開始,接著追蹤 ExceptionInfo.GetReport 如何建立 mod 詳細資訊,以及 Columns.Column 如何使用其中繼資料。使用動態組件中的 Harmony 修補方法,以及一個經過該方法的例外來重現問題。開啟 inspector 時,沒有 mod 中繼資料的修補不再反覆擲出例外,即為完成。

由索引模型根據 Issue 內容生成。

描述

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.
主要語言
C#
星號
10
分支
2
PR 合併指標
30 天內沒有已合併 PR

環境準備

這個專案沒有提供開發容器、Dockerfile 或貢獻指南,環境需要你自己搭建:先看它的 README,通用步驟見我們的新手貢獻指南。

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

相似的 Issue

更多 C# Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。