Can anybody help me to add a try finally block (using block) to my methods?

606 views
Skip to first unread message

Reh Gina

unread,
Jan 8, 2015, 10:09:54 AM1/8/15
to mono-...@googlegroups.com
I try to add a try finally block to my methods but it does not work chrchrchr. Try catch works, but with try finally the unit test cannot load the dll because of 'Common Runtime Language detected invalid program'
What am I doing wrong, PLEASE HELP

//// Start code //////

  med.Body.SimplifyMacros();

 ILProcessor ilProcessor = med.Body.GetILProcessor();

      var firstInstruction = FindFirstInstructionSkipCtor(med);

      var fTraceVar = new VariableDefinition("FTraceVar", mod.Import(typeof(syngo.Common.Diagnostics.Tracing.FTrace)));
      med.Body.Variables.Add(fTraceVar);

      /////////////// Start of try block      
      Instruction loadMethodNameInstr = Instruction.Create(OpCodes.Ldstr, med.Name);
      ilProcessor.InsertAfter(firstInstruction, loadMethodNameInstr); 

      Instruction loadDomainInstruction = Instruction.Create(OpCodes.Ldsfld, fTraceDomainField);
      ilProcessor.InsertBefore(loadMethodNameInstr, loadDomainInstruction); 

      var constructor = 
        typeof(syngo.Common.Diagnostics.Tracing.FTrace).GetConstructor(
        new[]
        {
          typeof(syngo.Common.Diagnostics.Tracing.FTraceDomain), typeof(string)
        });
      var constructorReference = mod.Import(constructor);
      Instruction newConstructorInstruction = Instruction.Create(OpCodes.Newobj, constructorReference);
      ilProcessor.InsertAfter(loadMethodNameInstr, newConstructorInstruction); // create new instance of person

      Instruction popFTraceVariableInstruction = Instruction.Create(OpCodes.Stloc, fTraceVar);
      //Pop a value from stack and store into local variable at index.
      ilProcessor.InsertAfter(newConstructorInstruction, popFTraceVariableInstruction);

  var endFinally = Instruction.Create(OpCodes.Endfinally);
      var leave = Instruction.Create(OpCodes.Leave, endFinally);



      //////// Start Finally block
      Instruction loadFTraceVarInstruction = Instruction.Create(OpCodes.Ldloca, fTraceVar);
      ilProcessor.InsertAfter(med.Body.Instructions.Last(), loadFTraceVarInstruction); //Loads local variable onto stack
      //ilProcessor.InsertBefore(lastInstruction, loadFTraceVarInstruction); //Loads local variable onto stack

      Instruction callDisposeInstruction = Instruction.Create(OpCodes.Call,
        mod.Import(typeof(syngo.Common.Diagnostics.Tracing.FTrace).GetMethod("Dispose")));
      ilProcessor.InsertAfter(loadFTraceVarInstruction, callDisposeInstruction); // calls dispose


      ilProcessor.InsertAfter(callDisposeInstruction, leave);
      ilProcessor.InsertAfter(leave, endFinally);

   
      ///////// End finally block


 var handler = new ExceptionHandler(ExceptionHandlerType.Finally)
      {
        TryStart = med.Body.Instructions.First(),
        TryEnd = callDisposeInstruction,
        HandlerStart = callDisposeInstruction,
        HandlerEnd = endFinally,
        //CatchType = mod.Import(typeof(Exception)),
      };


      med.Body.ExceptionHandlers.Add(handler);
      med.Body.InitLocals = true;
      med.Body.OptimizeMacros();

Jb Evain

unread,
Jan 8, 2015, 10:11:55 AM1/8/15
to mono-...@googlegroups.com
Hi!

What does peverify say when you run it on your modified program?

Thanks,
Jb
> --
> --
> --
> mono-cecil
> ---
> You received this message because you are subscribed to the Google Groups
> "mono-cecil" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to mono-cecil+...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
Message has been deleted

Jb Evain

unread,
Jan 8, 2015, 10:22:31 AM1/8/15
to mono-...@googlegroups.com
You're going to have to help us help you, the peverify output is
cluttered with missing references. Can you run it on the assembly with
the references around to pinpoint the exact issue?

On Thu, Jan 8, 2015 at 4:15 PM, Reh Gina <reh...@online.de> wrote:
>>> I attached the output of PEVerify

Reh Gina

unread,
Jan 8, 2015, 10:25:13 AM1/8/15
to mono-...@googlegroups.com
Now the correct file attached
Verify.txt

Reh Gina

unread,
Jan 8, 2015, 10:27:09 AM1/8/15
to mono-...@googlegroups.com
Something with a return which ist not correct in try block, but how to I remove it. Trying this to get work for almost 2 weeks

Am Donnerstag, 8. Januar 2015 16:25:13 UTC+1 schrieb Reh Gina:
Now the correct file attached

Reh Gina

unread,
Jan 8, 2015, 10:29:52 AM1/8/15
to mono-...@googlegroups.com
Unfortunatly the .NET Reflektor does not complain and shows correct code

Jb Evain

unread,
Jan 8, 2015, 10:35:31 AM1/8/15
to mono-...@googlegroups.com
The error means you can not have a ret instruction inside a protected block.

It means that if you're injecting protected blocks, you must make sure
that rets in them are replaced by into leave opcodes, that are jumping
outside of the protected block where you'll be able to return.

I'm afraid there's nothing built-in for this, you'll have to implement it.

Jb

Reh Gina

unread,
Jan 8, 2015, 10:41:36 AM1/8/15
to mono-...@googlegroups.com
Ok I'll try to replace ret by leave but what do I have to do in case the return value of the method is not void?

Reh Gina

unread,
Jan 8, 2015, 11:08:27 AM1/8/15
to mono-...@googlegroups.com
Now I replace the ret instruction by using following code 
[....]


      Instruction popFTraceVariableInstruction = Instruction.Create(OpCodes.Stloc, fTraceVar);
      //Pop a value from stack and store into local variable at index.
      ilProcessor.InsertAfter(newConstructorInstruction, popFTraceVariableInstruction);

      var endFinally = Instruction.Create(OpCodes.Endfinally);
      var leave = Instruction.Create(OpCodes.Leave, endFinally);
      var ret = Instruction.Create(OpCodes.Ret);

      for (int i = 0; i < med.Body.Instructions.Count; i++)
      {
        Instruction instr = med.Body.Instructions[i];
        //Console.WriteLine(instr.ToString());
        if (instr.OpCode == OpCodes.Ret)
        {
          Instruction previous = instr.Previous;
          ilProcessor.Remove(instr);
          ilProcessor.InsertAfter(previous, Instruction.Create(OpCodes.Leave, ret));
        }
      }
      

      //////// Start Finally block
      Instruction loadFTraceVarInstruction = Instruction.Create(OpCodes.Ldloca, fTraceVar);
      ilProcessor.InsertAfter(med.Body.Instructions.Last(), loadFTraceVarInstruction); //Loads local variable onto stack
      //ilProcessor.InsertBefore(lastInstruction, loadFTraceVarInstruction); //Loads local variable onto stack

[...]
[...]

  ilProcessor.InsertAfter(callDisposeInstruction, endFinally);
      //ilProcessor.InsertAfter(leave, endFinally);
      Instruction nopInstruction = Instruction.Create(OpCodes.Nop);
      ilProcessor.InsertAfter(endFinally, nopInstruction);
      ilProcessor.InsertAfter(nopInstruction, ret);
   
      ///////// End finally block

      var handler = new ExceptionHandler(ExceptionHandlerType.Finally)
      {
        TryStart = med.Body.Instructions.First(),
        TryEnd = callDisposeInstruction,
        HandlerStart = callDisposeInstruction,
        HandlerEnd = nopInstruction,
        //CatchType = mod.Import(typeof(Exception)),
      };
[...]

PEVerify says: 
[IL]: Error: [O:\bin\x64\Debug\MeVis.BizLogic.Applications.LiverAnalysis.Viewing.ViewingCP.dll : MeVis.BizLogic.Applications.LiverAnalysis.Viewing.ViewingCP.AbstractTaskStepBEHandler::Dispose][offset 0x000000A9] Stack underflow.
[IL]: Error: [O:\bin\x64\Debug\MeVis.BizLogic.Applications.LiverAnalysis.Viewing.ViewingCP.dll : MeVis.BizLogic.Applications.LiverAnalysis.Viewing.ViewingCP.AbstractTaskStepBEHandler::set_IsActive][offset 0x00000027] jmp / exception into the middle of an instruction.
[IL]: Error: [O:\bin\x64\Debug\MeVis.BizLogic.Applications.LiverAnalysis.Viewing.ViewingCP.dll :
.....


ARRRRGGGHHHHH

Am Donnerstag, 8. Januar 2015 16:35:31 UTC+1 schrieb Jb Evain:

Reh Gina

unread,
Jan 8, 2015, 11:11:29 AM1/8/15
to mono-...@googlegroups.com
I would like to kill my computer, but for now I will go home and restart tomorrow. Thanks for your help, would it be possible you'll help me a little bit more? 

Jb Evain

unread,
Jan 9, 2015, 3:36:24 AM1/9/15
to mono-...@googlegroups.com
If the method is not void you do need to return a value. I can't tell
you what to return, it depends completely on what you're doing.
Preserving the existing logic of the method you're manipulating would
be a good start :)

Jb

Jb Evain

unread,
Jan 9, 2015, 3:37:38 AM1/9/15
to mono-...@googlegroups.com
Hi,

If this group is all for helping people use Cecil, its purpose is not
to debug other people code.

If you want professional services around Cecil you can contact me privately.

Thanks!

Jb

Reh Gina

unread,
Jan 9, 2015, 4:00:40 AM1/9/15
to mono-...@googlegroups.com
Yes, thats clear for me, but I am so desperate. I found some more help on this page

Everything works fine until I do not add some more custom code and only the try finally block. If adding own variables and calls, the il code is not valid anymore.

I will talk to my Dev Manager because of 'professional help'. Thanks :-)

Reh Gina

unread,
Jan 9, 2015, 8:09:28 AM1/9/15
to mono-...@googlegroups.com
JUUUUUUHUUUUUU works now :


Here the code, maybe somebody else needs the snippeds sometime :-)


---------------------------------
 internal class AssemblyTracing
  {
    /// <nn />
    private readonly string _assemblyPath;

    /// <summary>
    /// Constructor taking initializing parameter.
    /// </summary>
    /// <param name="assemblyPath">The path of the assembly where to inject tracing code.</param>
    public AssemblyTracing(string assemblyPath)
    {
      _assemblyPath = assemblyPath;
    }

    /// <summary>
    /// Injects tracing code to the assembly that this class instance has been created for.
    /// </summary>
    public void InjectTracingToAssembly()
    {
      var assemblyDefinition = AssemblyDefinition.ReadAssembly(_assemblyPath);

      Console.WriteLine("Injecting trace code to assembly \"{0}\"", _assemblyPath);
      foreach (var moduleDefinition in assemblyDefinition.Modules)
      {
        foreach (var typeDefinition in moduleDefinition.Types)
        {
          InjectTracingToTypeOfModule(typeDefinition, moduleDefinition);
        }
      }

      assemblyDefinition.Write(_assemblyPath, new WriterParameters { WriteSymbols = true });
    }

    /// <nn />
    private void InjectTracingToTypeOfModule(TypeDefinition type, ModuleDefinition moduleDefinition)
    {
      if (type.IsInterface || type.IsEnum || !type.IsClass)
      {
        return;
      }

      foreach (var typeDefinition in type.NestedTypes)
      {
        InjectTracingToTypeOfModule(typeDefinition, moduleDefinition);
      }

      FieldDefinition fTraceDomainField = AddFTraceDomainFieldToType(type, moduleDefinition);
      MethodDefinition staticConstructor = GetStaticConstructor(type);
      if (staticConstructor == null)
      {
        staticConstructor = AddStaticConstructorForFTraceDomain(type, moduleDefinition);
      }

      AddInitialisationOfFTraceDomainFieldToStaticConstructor(
        moduleDefinition, 
        type, 
        staticConstructor, 
        fTraceDomainField);

      foreach (var methodDefinition in type.Methods)
      {
        if (methodDefinition.IsConstructor /*&& methodDefinition.IsStatic*/)
        {
          continue;
        }

        if (methodDefinition.HasBody)
        {         
          EncapsulateMethodBodyWithTryFinallyBlock(moduleDefinition, methodDefinition, fTraceDomainField);

        }
      }
    }

    /// <nn />
    private static MethodDefinition GetStaticConstructor(TypeDefinition type)
    {
      foreach (var method in type.Methods)
      {
        if (method.IsConstructor && method.IsStatic)
        {
          return method;
        }
      }

      return null;
    }

    /// <nn />
    private static Instruction FindFirstInstructionSkipCtor(MethodDefinition med)
    {
      MethodBody body = med.Body;
      if (med.IsConstructor && !med.IsStatic)
      {
        return body.Instructions.Skip(2).First();
      }

      return body.Instructions.First();
    }

    /// <nn />
    private static Instruction FixReturns(MethodDefinition med, ModuleDefinition mod)
    {
      MethodBody body = med.Body;

      Instruction formallyLastInstruction = body.Instructions.Last();
      Instruction lastLeaveInstruction = null;
      if (med.ReturnType == mod.TypeSystem.Void)
      {
        var instructions = body.Instructions;
        var lastRet = Instruction.Create(OpCodes.Ret);
        instructions.Add(lastRet);

        for (var index = 0; index < instructions.Count - 1; index++)
        {
          var instruction = instructions[index];
          if (instruction.OpCode == OpCodes.Ret)
          {
            Instruction leaveInstruction = Instruction.Create(OpCodes.Leave, lastRet);
            if (instruction == formallyLastInstruction)
            {
              lastLeaveInstruction = leaveInstruction;
            }

            instructions[index] = leaveInstruction;
          }
        }

        FixBranchTargets(lastLeaveInstruction, formallyLastInstruction, body);
        return lastRet;
      }
      else
      {
        var instructions = body.Instructions;
        var returnVariable = new VariableDefinition("methodTimerReturn", med.ReturnType);
        body.Variables.Add(returnVariable);
        var lastLd = Instruction.Create(OpCodes.Ldloc, returnVariable);
        instructions.Add(lastLd);
        instructions.Add(Instruction.Create(OpCodes.Ret));

        for (var index = 0; index < instructions.Count - 2; index++)
        {
          var instruction = instructions[index];
          if (instruction.OpCode == OpCodes.Ret)
          {
            Instruction leaveInstruction = Instruction.Create(OpCodes.Leave, lastLd);
            if (instruction == formallyLastInstruction)
            {
              lastLeaveInstruction = leaveInstruction;
            }

            instructions[index] = leaveInstruction;
            instructions.Insert(index, Instruction.Create(OpCodes.Stloc, returnVariable));
            index++;
          }
        }

        FixBranchTargets(lastLeaveInstruction, formallyLastInstruction, body);
        return lastLd;
      }
    }

    /// <nn />
    private static void FixBranchTargets(
      Instruction lastLeaveInstruction, 
      Instruction formallyLastRetInstruction,
      MethodBody body)
    {
      for (var index = 0; index < body.Instructions.Count - 2; index++)
      {
        var instruction = body.Instructions[index];
        if (instruction.Operand != null && instruction.Operand == formallyLastRetInstruction)
        {
          instruction.Operand = lastLeaveInstruction;
        }
      }
    }

    /// <nn />
    private static void EncapsulateMethodBodyWithTryFinallyBlock(  
      ModuleDefinition mod,
      MethodDefinition med, 
      FieldDefinition fTraceDomainField)
    {

      if (med.Body == null || med.Body.Instructions.Count <= 0)
      {
        Console.WriteLine(med.Name + " has not body or no instructions in body");
        return;
      }


      med.Body.SimplifyMacros();

      

      ILProcessor ilProcessor = med.Body.GetILProcessor();

      var firstInstruction = FindFirstInstructionSkipCtor(med);
      Instruction returnInstruction = FixReturns(med, mod);

      var beforeReturn = Instruction.Create(OpCodes.Endfinally);
      ilProcessor.InsertBefore(returnInstruction, beforeReturn);



      var fTraceVar = new VariableDefinition("FTraceVar", mod.Import(typeof(syngo.Common.Diagnostics.Tracing.FTrace)));
      med.Body.Variables.Add(fTraceVar);

   
      /////////////// Start of try block  
      Instruction nopInstruction1 = Instruction.Create(OpCodes.Nop);
      ilProcessor.InsertBefore(firstInstruction, nopInstruction1);
    
      Instruction loadDomainInstruction = Instruction.Create(OpCodes.Ldsfld, fTraceDomainField);
      ilProcessor.InsertAfter(nopInstruction1 , loadDomainInstruction);

      Instruction loadMethodNameInstr = Instruction.Create(OpCodes.Ldstr, med.Name);
      ilProcessor.InsertAfter(loadDomainInstruction, loadMethodNameInstr);

      var constructor = 
        typeof(syngo.Common.Diagnostics.Tracing.FTrace).GetConstructor(
        new[]
        {
          typeof(syngo.Common.Diagnostics.Tracing.FTraceDomain), typeof(string)
        });
      var constructorReference = mod.Import(constructor);
      Instruction newConstructorInstruction = Instruction.Create(OpCodes.Newobj, constructorReference);
      ilProcessor.InsertAfter(loadMethodNameInstr, newConstructorInstruction); // create new instance of person

      Instruction popFTraceVariableInstruction = Instruction.Create(OpCodes.Stloc, fTraceVar);
      ////Pop a value from stack and store into local variable at index.
      ilProcessor.InsertAfter(newConstructorInstruction, popFTraceVariableInstruction);

 

      //////// Start Finally block
      Instruction nopInstruction2 = Instruction.Create(OpCodes.Nop);
      ilProcessor.InsertBefore(beforeReturn, nopInstruction2);

      Instruction loadFTraceVarInstruction = Instruction.Create(OpCodes.Ldloca, fTraceVar);
      ilProcessor.InsertAfter(nopInstruction2, loadFTraceVarInstruction); //Loads local variable onto stack

      Instruction callDisposeInstruction = Instruction.Create(OpCodes.Call,
        mod.Import(typeof(syngo.Common.Diagnostics.Tracing.FTrace).GetMethod("Dispose")));
      ilProcessor.InsertAfter(loadFTraceVarInstruction, callDisposeInstruction); // calls dispose
      ///////// End finally block
      

      var handler = new ExceptionHandler(ExceptionHandlerType.Finally)
      {
        TryStart = nopInstruction1,
        TryEnd = nopInstruction2,
        HandlerStart = nopInstruction2,
        HandlerEnd = returnInstruction,
      };


      med.Body.ExceptionHandlers.Add(handler);
      med.Body.InitLocals = true;
      med.Body.OptimizeMacros();

    }



    /// <nn />
    private static FieldDefinition AddFTraceDomainFieldToType(TypeDefinition type, ModuleDefinition mod)
    {
      const string FIELDNAME = "FTRACEDOMAIN";

      FieldDefinition fTraceDomain = new FieldDefinition(
        FIELDNAME,
        Mono.Cecil.FieldAttributes.Static | Mono.Cecil.FieldAttributes.InitOnly,
        mod.Import(typeof(syngo.Common.Diagnostics.Tracing.FTraceDomain)));

      type.Fields.Add(fTraceDomain);

      return fTraceDomain;

    }

    /// <nn />
    private static MethodDefinition AddStaticConstructorForFTraceDomain(
      TypeDefinition type,
      ModuleDefinition mod)
    {
      var methodAttributes =
        MethodAttributes.Static | 
        MethodAttributes.HideBySig |
        MethodAttributes.SpecialName | 
        MethodAttributes.RTSpecialName;

      var method = new MethodDefinition(".cctor", methodAttributes, mod.TypeSystem.Void);
      method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
      type.Methods.Add(method);
      return method;
    }

    /// <nn />
    private static void AddInitialisationOfFTraceDomainFieldToStaticConstructor(
      ModuleDefinition mod,
      TypeDefinition type,
      MethodDefinition staticConstructor,
      FieldDefinition fTraceDomainField)
    {
      staticConstructor.Body.SimplifyMacros();
      Instruction firstInstruction = staticConstructor.Body.Instructions.First();
      ILProcessor ilProcessor = staticConstructor.Body.GetILProcessor();

      var writeLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
      var writeLineRef = mod.Import(writeLineMethod);
      Instruction loadInstruction = Instruction.Create(OpCodes.Ldstr, "Static Constructor of class " + type.Name);
      ilProcessor.InsertBefore(firstInstruction, loadInstruction);
      Instruction writeInstruction = Instruction.Create(OpCodes.Call, writeLineRef);
      ilProcessor.InsertAfter(loadInstruction, writeInstruction);

      Instruction loadClassTypeInstruction = Instruction.Create(OpCodes.Ldtoken, type);
      ilProcessor.InsertAfter(writeInstruction, loadClassTypeInstruction);

      Instruction callGetTypeInstruction = Instruction.Create(OpCodes.Call,
      mod.Import(typeof(System.Type).GetMethod("GetTypeFromHandle")));
      ilProcessor.InsertAfter(loadClassTypeInstruction, callGetTypeInstruction);

      var domainConstructor = 
        typeof(syngo.Common.Diagnostics.Tracing.FTraceDomain).GetConstructor(new[] { typeof(Type) });
      var domainConstructorReference = mod.Import(domainConstructor);
      Instruction domainConstructorInstruction = Instruction.Create(OpCodes.Newobj, domainConstructorReference);
      ilProcessor.InsertAfter(callGetTypeInstruction, domainConstructorInstruction); // create new instance of person
      Instruction popFTraceDomainVariableInstruction = Instruction.Create(OpCodes.Stsfld, fTraceDomainField);
      //Pop a value from stack and store into local variable at index.
      ilProcessor.InsertAfter(domainConstructorInstruction, popFTraceDomainVariableInstruction);

      staticConstructor.Body.OptimizeMacros();
    }
   
  }
----------------------------------
Reply all
Reply to author
Forward
0 new messages