使用Pose库拦截Task中Debug.WriteLine遇栈溢出问题求助
问题描述
我创建了如下Shim:
using Pose; Shim consoleShim = Shim.Replace(() => Debug.WriteLine(Is.A<string>())).With( delegate (string s) { Debug.WriteLine($"Hijacked: {s}"); });
以下代码可正常运行并输出“Hijacked: Test Debug”:
PoseContext.Isolate(() => { Debug.WriteLine("Test Debug"); }, consoleShim);
但以下代码执行时会触发栈溢出错误:
PoseContext.Isolate(() => { _ = Task.Run(() => { Debug.WriteLine("In different task"); }); }, consoleShim);
错误栈信息如下:
Stack overflow. at System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException[[System.Int32, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](Int32) at System.Collections.Generic.Dictionary`2[[System.Int32, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Reflection.Emit.Label, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TryInsert(Int32, System.Reflection.Emit.Label, System.Collections.Generic.InsertionBehavior) at Pose.Extensions.DictionaryExtensions.TryAdd[[System.Int32, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Reflection.Emit.Label, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.Collections.Generic.Dictionary`2<Int32,System.Reflection.Emit.Label>, Int32, System.Reflection.Emit.Label) at Pose.IL.MethodRewriter.Rewrite() at DynamicClass.stub_System.Collections.Generic.List`1[System.String]_LastIndexOf(System.Collections.Generic.List`1<System.String>, System.String, Int32, Int32, System.RuntimeMethodHandle, System.RuntimeTypeHandle) at DynamicClass.dynamic_System.Collections.Generic.List`1[System.String]_LastIndexOf(System.Collections.Generic.List`1<System.String>, System.String) at DynamicClass.stub_virt_System.Collections.Generic.List`1[System.String]_LastIndexOf(System.Collections.Generic.List`1<System.String>, System.String, System.RuntimeMethodHandle, System.RuntimeTypeHandle) at DynamicClass.dynamic_System.SR_InternalGetResourceString(System.String) at DynamicClass.stub_System.SR_InternalGetResourceString(System.String, System.RuntimeMethodHandle, System.RuntimeTypeHandle) at DynamicClass.dynamic_System.SR_GetResourceString(System.String) at DynamicClass.stub_System.SR_GetResourceString(System.String, System.RuntimeMethodHandle, System.RuntimeTypeHandle) at DynamicClass.stub_System.SR_get_Arg_InvalidOperationException(System.RuntimeMethodHandle, System.RuntimeTypeHandle) at DynamicClass.dynamic_System.InvalidOperationException_.ctor(System.InvalidOperationException) at DynamicClass.stub_ctor_System.InvalidOperationException_.ctor(System.RuntimeMethodHandle, System.RuntimeTypeHandle) at DynamicClass.dynamic_System.Runtime.CompilerServices.RuntimeHelpers_IsBitwiseEquatable() at DynamicClass.stub_System.Runtime.CompilerServices.RuntimeHelpers_IsBitwiseEquatable(System.RuntimeMethodHandle, System.RuntimeTypeHandle) at DynamicClass.dynamic_System.Array_LastIndexOf(System.String[], System.String, Int32, Int32) at DynamicClass.stub_System.Array_LastIndexOf(System.String[], System.String, Int32, Int32, System.RuntimeMethodHandle, System.RuntimeTypeHandle) at DynamicClass.dynamic_System.Collections.Generic.List`1[System.String]_LastIndexOf(System.Collections.Generic.List`1<System.String>, System.String, Int32, Int32) at DynamicClass.stub_System.Collections.Generic.List`1[System.String]_LastIndexOf(System.Collections.Generic.List`1<System.String>, System.String, Int32, Int32, System.RuntimeMethodHandle, System.RuntimeTypeHandle) at DynamicClass.dynamic_System.Collections.Generic.List`1[System.String]_LastIndexOf(System.Collections.Generic.List`1<System.String>, System.String) at DynamicClass.stub_virt_System.Collections.Generic.List`1[System.String]_LastIndexOf(System.Collections.Generic.List`1<System.String>, System.String, System.RuntimeMethodHandle, System.RuntimeTypeHandle) at DynamicClass.dynamic_System.SR_InternalGetResourceString(System.String) at DynamicClass.stub_System.SR_InternalGetResourceString(System.String, System.RuntimeMethodHandle, System.RuntimeTypeHandle) at DynamicClass.dynamic_System.SR_GetResourceString(System.String)...
请问这是Pose库的固有限制,还是存在可行的解决办法?
解决方案
这是Pose库的线程隔离固有限制导致的问题。PoseContext.Isolate仅对当前执行线程生效,当在隔离上下文内启动新线程(比如Task.Run)时,新线程无法继承原线程的Shim配置,反而会触发Pose的方法重写逻辑进入无限循环,最终导致栈溢出。
可行的解决办法有三种:
1. 在新线程内重新创建隔离上下文
将目标方法调用放在新线程的PoseContext.Isolate中,确保Shim在新线程内生效:
PoseContext.Isolate(() => { _ = Task.Run(() => { PoseContext.Isolate(() => { Debug.WriteLine("In different task"); }, consoleShim); }); }, consoleShim);
2. 缩小Shim的匹配范围
栈溢出的根源是Pose在处理新线程的系统方法时进入循环,可通过精确匹配目标方法而非泛型匹配,避免意外重写系统方法:
// 精确匹配Debug.WriteLine(string)方法 Shim consoleShim = Shim.Replace(() => Debug.WriteLine(It.IsAny<string>())).With( (string s) => Debug.WriteLine($"Hijacked: {s}"));
3. 同步等待任务完成(仅适用于允许同步的场景)
使用Wait()等待任务执行完毕,确保原线程的隔离上下文覆盖整个任务周期:
PoseContext.Isolate(() => { Task.Run(() => { Debug.WriteLine("In different task"); }).Wait(); }, consoleShim);
内容的提问来源于stack exchange,提问作者Matthew Conradie
相关产品推荐
相关产品推荐

