You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostSharp修改CIL后添加指令触发InvalidProgramException问题求助

Why Adding a NOP to PostSharp-Transformed IL Causes InvalidProgramException

Let's break down exactly why this happens and how to fix it:

Core Root Cause

When PostSharp weaves its aspect into your method, it generates IL that includes hardcoded offset values for branch instructions (like switch, leave.s, br.s) and defines strict boundaries for try/catch blocks. When you insert a nop (or any instruction), you shift all subsequent instructions by the size of the inserted code, which invalidates every hardcoded offset in the method. The CLR's IL validator detects these invalid offsets and throws InvalidProgramException.

Detailed Breakdown of the Problem

Looking at the PostSharp-transformed IL, here are the key elements that break when you modify the IL manually:

  1. Switch Instruction with Hardcoded Offsets
    The switch ( IL_00bf, IL_00c1, IL_00bf, IL_00c1, IL_00ca) line uses absolute byte offsets to define where each case should jump. Inserting a 1-byte nop at the start means all these offsets now point to the wrong location (they're 1 byte too early). The CLR can't resolve the jump targets, so it flags the program as invalid.

  2. Try/Catch Block Boundaries
    PostSharp wraps your original method logic in a try block, with leave.s instructions that jump to specific offsets to exit the block. Inserting a nop shifts the end of the try block and the target of leave.s instructions, breaking the exception handling structure the CLR expects.

  3. Branch Target Consistency
    Even simple branches like br.s IL_0079 rely on precise relative offsets. Shifting instructions changes these relative distances, making the branch land on an invalid instruction boundary or the middle of an opcode.

Solutions to Fix This

Instead of manually modifying IL, leverage PostSharp's built-in mechanisms to add your logic:

  • If you need to track object state changes, use FieldInterceptionAspect to intercept field/property setters directly.
  • To add code before/after method execution, extend MethodBoundaryAspect (which is what your existing aspect uses) and override the appropriate methods (OnEntry, OnSuccess, etc.).
  • For more advanced IL manipulation, use PostSharp's IAspectProvider or IAdviceProvider interfaces—these APIs automatically handle offset recalculation and IL validation for you.

2. Manually Recalculate All Branch Offsets (If You Must Modify IL Directly)

If you absolutely need to modify the IL manually, you'll have to:

  • Traverse your ILInstruction list and calculate the exact byte offset of each instruction (accounting for opcode size and operand length).
  • For every branch instruction (br, br.s, leave, leave.s, switch, etc.), update its operand data to point to the new, correct offset of the target instruction.
  • After generating the new IL byte array, run peverify.exe on the modified assembly to catch any remaining validation errors.

3. Avoid Manual IL Modification Altogether

Given your goal of tracking object state changes, consider alternative approaches that don't require IL hacking:

  • Use a proxy library (like Castle DynamicProxy) to wrap objects and track changes.
  • Implement a change-tracking pattern directly in your classes (e.g., using a base class that records property changes).

内容的提问来源于stack exchange,提问作者Amon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 21:47:28