Removing the target instruction for a TryBegin

39 views
Skip to first unread message

Kenneth Skovhede

unread,
Jul 8, 2011, 5:46:14 AM7/8/11
to mono-cecil
I have some function that I load with Mono.Cecil, modify and write
back.
This generally works fine, but if I remove the nop operations, the Try/
Catch handlers
break (the TryBegin target instruction is the nop instruction being
removed).

What appears to happen is that even though I use the ILProcessor to
remove the
instruction, the ExceptionHandler still has a reference to the removed
instruction.

For some reason this works fine for the first execption handler, which
gets the
TryBegin offset 0x0b, but the second exception handler should get
0x2a, but also
gets 0x0b. (In Cecil 0.6.7 it got 0x00).

If google groups mess up the formating, I have also put the code on
pastebin:
http://pastebin.com/HDScfLMw

My question is, is there some easy fixup method/trick to get this
working?
Or do I need to create a fixup function that I execute prior to
instruction removal
that updates the exception handlers?

Regards, Kenneth


[NORMAL]
.method public hidebysig virtual instance float32 Op(float32 a,
float32 b) cil managed
{
// Code size 65 (0x41)
.maxstack 2
.locals init (float32 V_0,
float32 V_1,
float32 V_2)
IL_0000: ldc.i4 0x579223a3
IL_0005: ldc.i4.0
IL_0006: call void EnterMethod(int32, int32)
.try
{
IL_000b: nop
IL_000c: ldarg.0
IL_000d: ldarg.1
IL_000e: sub
IL_000f: stloc.0
IL_0010: leave.s IL_0018
} // end .try
fault
{
IL_0012: call void LeaveMethod()
IL_0017: endfinally
} // end handler
IL_0018: call void LeaveMethod()
IL_001d: ldloc.0
IL_001e: stloc.1
IL_001f: ldc.i4 0x579223a3
IL_0024: ldc.i4.1
IL_0025: call void EnterMethod(int32, int32)
.try
{
IL_002a: nop
IL_002b: ldloc.1
IL_002c: call float32 [mscorlib]System.Math::Abs(float32)
IL_0031: stloc.2
IL_0032: leave.s IL_003a
} // end .try
fault
{
IL_0034: call void LeaveMethod()
IL_0039: endfinally
} // end handler
IL_003a: call void LeaveMethod()
IL_003f: ldloc.2
IL_0040: ret
}


[MODIFIED]
.method public hidebysig virtual instance float32 Op(float32 a,
float32 b) cil managed
{
// Code size 63 (0x3f)
.maxstack 2
.locals init (float32 V_0,
float32 V_1,
float32 V_2)
IL_0000: ldc.i4 0x579223a3
IL_0005: ldc.i4.0
IL_0006: call void EnterMethod(int32, int32)
.try
{
.try
{
IL_000b: ldarg.0
IL_000c: ldarg.1
IL_000d: sub
IL_000e: stloc.0
IL_000f: leave.s IL_0017
} // end .try
fault
{
IL_0011: call void LeaveMethod()
IL_0016: endfinally
} // end handler
IL_0017: call void LeaveMethod()
IL_001c: ldloc.0
IL_001d: stloc.1
IL_001e: ldc.i4 0x579223a3
IL_0023: ldc.i4.1
IL_0024: call void EnterMethod(int32, int32)
IL_0029: ldloc.1
IL_002a: call float32 [mscorlib]System.Math::Abs(float32)
IL_002f: stloc.2
IL_0030: leave.s IL_0038
} // end .try
fault
{
IL_0032: call void LeaveMethod()
IL_0037: endfinally
} // end handler
IL_0038: call void LeaveMethod()
IL_003d: ldloc.2
IL_003e: ret
}

Alex

unread,
Jul 8, 2011, 6:57:37 AM7/8/11
to mono-...@googlegroups.com
Hi Kenneth,

As far as I know, you have to adjust exception handlers manually.
Since Cecil uses references to refer to instructions (as opposed to
offsets), it won't pick anything up if you completely remove an
instruction. Also, internally, Cecil only sets properties on
ExceptionHandler when reading modules.

Regards,
Alex

> --
> --
> mono-cecil

Kenneth Skovhede

unread,
Jul 9, 2011, 11:04:30 AM7/9/11
to mono-cecil
Ok, thanks for the answer.
Here is a quick extension method I wrote that updates the exception
handlers:

public static void SafeRemove(this Mono.Cecil.Cil.ILProcessor
p, Mono.Cecil.Cil.Instruction i)
{
foreach (var eh in p.Body.ExceptionHandlers)
{
if (eh.TryStart == i)
eh.TryStart = i.Next;
if (eh.TryEnd.Previous == i)
eh.TryEnd = i.Previous;
if (eh.HandlerStart == i)
eh.HandlerStart = i.Next;
if (eh.HandlerEnd.Previous == i)
eh.HandlerEnd = i.Previous;
if (eh.FilterStart == i)
eh.FilterStart = i.Next;
}

p.Remove(i);
Reply all
Reply to author
Forward
0 new messages