Check for throw or rethrow in a try block

Thank you David ...I have another question....

How can I check if there is any sentence in a block ... for example i want to check an empty catch and I do this:

public override ProblemCollection Check(Member member)

{

Method method = member as Method;

bool isCatchExists = false;

bool isThrowExists = false;

if (method == null)

return null;

InstructionList iList = method.Instructions;

for (int i = 0; i < iList.Length; i++)

{

if (iListIdea.OpCode == OpCode._Catch)

{

isCatchExists = true;

}

if (isCatchExists)

{

if ((iListIdea.OpCode == OpCode.Throw)||(iListIdea.OpCode ==OpCode.Rethrow))

{

isThrowExists = true;

}

}

}

if (isCatchExists)

{

if (!isThrowExists)

{

string text1 = "No se pueden declarar bloques catch vacios: ";

string[] st = new string[] { text1, method.Name.Name};

Resolution resol = new Resolution("{0}{1}", st);

Problems.Add(new Problem(resol));

}

}

return Problems;

}

but the problem is I want to check if in a try block there is a throw or a rethrow or a sentence

But if there is a sentence i don't know how to check it.




Answer this question

Check for throw or rethrow in a try block

  • weirdbeardmt

    Anybody knows if it's possible to get that information (previous post)



  • Avi Gershon

    Oops. I'll fix it.
  • RibTickler

    These are the set of instructions that I chose to allow in a catch block and still consider it empty. The issue is that an empty catch block in C# can be represented in more than one way in IL, but it must at least remove the exception from the stack and leave the handler. To remove the exception from the stack, it could just pop it, but it could also store it in a local. And nop -> No op -> "do nothing", so it's ok for it to appear in empty blocks.

    It looks like I forgot to add the extra stloc and leave instructions to the original code that I posted, so I'll edit the code to include all of them.

    Nick


  • Christian_42

    Hi,

    The code above should be corrected already. Are you seeing another issue

    This sentence from my original post explains the approach:

    "... the simplest algorithm for this sort of thing is to find each OpCode.Catch, and then walk all successive instructions until the OpCode._EndHandler whose value is the original catch instruction looking for whatever pattern you're seeking."

    Basically, each Instruction has an OpCode and a Value. When the OpCode is _EndHandler, the value is the catch instruction which started the handler. For every catch, you can then scan until the corresponding endhandler and examine the instructions in between to implement your rule. In the case of "empty" handlers, the code above uses a heuristic which allows only a fixed set of instructions which are known to appear in IL for empty C# catch blocks. Any other instruction between the catch and the corresponding endhandler leads to the conclusion that the catch block is non-empty.

    Thanks

    Nick


  • dollinz

    Do you have any idea what's the problem with the code cause it doesn't work:

    Displays this error:

    Error 2 Control cannot fall through from one case label ('case 65279:') to another.

    Thanks.



  • AJMazurek

    Thanks ;

    Yes, but there’s the same problem in the method Rethrows you have any idea



  • Petar Petrov

    hi,

    i too have to write a custom rule that checks for empty catch block. Could you explain me how can that be written. It would be fine if i get the corrected code and a few lines about how it works.

    Thanks



  • dean gross

    Hi, I want to know what recognize each case sentence.

    I mean what controls the first case(OpCode Pop), the second(OpCode.Nop) and so on...

    Thank you, regards...



  • Andreas_R

    Yes, I made an error, I'll correct it.

    Nick


  • BFDS.BIZ

    It looks like you have two questions here:

    1) How to detect catch blocks which throw or rethrow
    2) How to detect empty catch blocks

    Using the current version of FxCop, the simplest algorithm for this sort of thing is to find each OpCode.Catch, and then walk all successive instructions until the OpCode._EndHandler whose value is the original catch instruction looking for whatever pattern you're seeking. This is only approximately correct for some scenarios as you may want to skip nested try/catch blocks while scanning the outer blocks, but this is tough to get right. We're working on a simpler tree-based IR representation for exception handling that makes this sort of check easier to implement. In the meantime, here's the outline of the approach I suggest above. I haven't tested the code below, so you might need to rework it a bit.



    InstructionList instructions = method.Instructions;
    for (int i = 0, n = instructions.Length; i < n; i++)
    {
        Instruction instruction = instructions[ i ];
        if (instruction.OpCode == OpCode.Catch)
        {
            if (Rethrows(instructions, i))
            {
                // found a catch block which throws or rethrows
            }
           
            if (IsEmpty(instructions, i))
            {
               // found an empty catch block
            }
        }

    }

    bool Rethrows(InstructionList instructions, int catchOffset)
    {
        Instruction catchInstruction= instructions[ catchOffset ];
        for (int i = catchOffset + 1, n = instructions.Length; i < n; i++)
        {
           Instruction instruction = instructions[ i ];
           switch (instruction.OpCode)
           {
               case OpCode.Throw:
               case OpCode.Rethrow:
                  return true;
               case OpCode._EndHandler:
                  if (instruction.Value == catchInstruction)
                    return false;
                 break;

           }
        }
        return false;
    }

    bool IsEmpty(InstructionList instructions, int catchOffset)
    {
        Instruction catchInstruction= instructions[ catchOffset ];
        for (int i = catchOffset + 1, n = instructions.Length; i < n; i++)
        {
           Instruction instruction = instructions[ i ];
           switch (instruction.OpCode)
           {   
               // Note: this is fragile, it's just based on the instructions
               // I found in ildasm from the C# compiler's code emit. It's
               // possible that other instructions could appear in empty catch
               // blocks and you'll have to refine the heuristic.
               case OpCode.Pop:
               case OpCode.Nop:
               case OpCode.Stloc_0:
               case OpCode.Stloc_1:
               case OpCode.Stloc_2:
               case OpCode.Stloc_3:
               case OpCode.Stloc_S:
               case OpCode.Stloc:
               case OpCode.Leave_S:
               case OpCode.Leave:
                   break;

               case OpCode._EndHandler:
                   if (instruction.Value == catchInstruction)
                       return true;
                   break;
              
    default:
                   return false;
            }
        }
        return true;
    }


     

    Thanks
    Nick


  • Check for throw or rethrow in a try block