private void AddHandlerToTryBlock(ExceptionHandlingLogicalConstruct tryBlockExistingHandler, ExceptionHandler handler)
 {
     if (tryBlockExistingHandler is TryCatchFilterLogicalConstruct)
     {
         if (handler.HandlerType == ExceptionHandlerType.Fault || handler.HandlerType == ExceptionHandlerType.Finally)
         {
             //Fault/finally handlers cannot coexist together with any other type of handler on the same try block. New
             // try block should be defined for each of these.
             throw new Exception("Illegal IL: Non-exclusive Fault/Finally handler found");
         }
         else if (handler.HandlerType == ExceptionHandlerType.Filter)
         {
             (tryBlockExistingHandler as TryCatchFilterLogicalConstruct).AddHandler(CreateFilterHandler(handler));
         }
         else if (handler.HandlerType == ExceptionHandlerType.Catch)
         {
             (tryBlockExistingHandler as TryCatchFilterLogicalConstruct).AddHandler(CreateCatchHandler(handler));
         }
     }
     else if (tryBlockExistingHandler is TryFaultLogicalConstruct || tryBlockExistingHandler is TryFinallyLogicalConstruct)
     {
         //Fault/finally handlers cannot coexist together with any other type of handler on the same try block. New
         // try block should be defined for each of these.
         throw new Exception("Illegal IL: Non-exclusive Fault/Finally handler found");
     }
 }
 private void AddHandlerToTryBlock(ExceptionHandlingLogicalConstruct tryBlockExistingHandler, ExceptionHandler handler)
 {
     if (tryBlockExistingHandler as TryCatchFilterLogicalConstruct == null)
     {
         if (tryBlockExistingHandler as TryFaultLogicalConstruct != null || tryBlockExistingHandler as TryFinallyLogicalConstruct != null)
         {
             throw new Exception("Illegal IL: Non-exclusive Fault/Finally handler found");
         }
     }
     else
     {
         if (handler.get_HandlerType() == 4 || handler.get_HandlerType() == 2)
         {
             throw new Exception("Illegal IL: Non-exclusive Fault/Finally handler found");
         }
         if (handler.get_HandlerType() == 1)
         {
             (tryBlockExistingHandler as TryCatchFilterLogicalConstruct).AddHandler(this.CreateFilterHandler(handler));
             return;
         }
         if (handler.get_HandlerType() == null)
         {
             (tryBlockExistingHandler as TryCatchFilterLogicalConstruct).AddHandler(this.CreateCatchHandler(handler));
             return;
         }
     }
     return;
 }
        public void FindExceptionHandlingConstructs()
        {
            //The CLR searchese top to bottom through the EH table at the end of the method declaration looking for a CATCH or FILTER handlers
            //which guarded(try) block encompasses the spot where the exception occurred (FAULT and FINALLY handlers are compeltely ignored at this pass,
            //no matter whether the exception falls in their guarded(try) blocks). Assuming that CATCH/FILTER handler was found at row N of the EH table
            // the CLR marks it (but it does NOT execute it at this point) and does a second pass through the EH table searching ONLY rows 1 to N this time.
            //On hte second pass only FAULT/FINALLY handlers are considered. Any FAULT/FILTER handler found which guarded block encompasses the instruction causing
            //the exception gets executed at this pass. Only then the CATCH/FILTER handler at row N gets executed.
            //That means that the order in which handlers appear in the EH table has precedence over their hierarchical structure in the IL (i.e. which try block is inside another try block) when determineing
            //their order of execution. Hence given a FAULT/FINALLY handler that completely contains a CATCH/FILTER handler in the IL but whose EH table entry occurs before
            // the CATCH/FILTER  handler EH table entry in the LogicalConstruct tree the CATCH/FILTER handler will be parent of the FAULT/FINALLY handler (complete reverse of theri relationship in the IL)
            //since the FAULT/FINALLY handler will be executed before the CATCH/FILTER one.


            foreach (ExceptionHandler handler in context.CFG.RawExceptionHandlers)
            {
                BlockRange tryBlockRange = GetBlockRangeFromInstructions(handler.TryStart, handler.TryEnd);

                ExceptionHandlingLogicalConstruct tryBlockExistingHandler = null;
                if (tryBlocksFound.TryGetValue(tryBlockRange, out tryBlockExistingHandler))
                {
                    AddHandlerToTryBlock(tryBlockExistingHandler, handler);
                }
                else
                {
                    BlockLogicalConstruct             theTryBlock  = CreateExceptionhandlingBlock(tryBlockRange);
                    ExceptionHandlingLogicalConstruct guardedBlock = null;

                    switch (handler.HandlerType)
                    {
                    case ExceptionHandlerType.Catch:
                        guardedBlock = new TryCatchFilterLogicalConstruct(theTryBlock, CreateCatchHandler(handler));
                        break;

                    case ExceptionHandlerType.Filter:
                        guardedBlock = new TryCatchFilterLogicalConstruct(theTryBlock, CreateFilterHandler(handler));
                        break;

                    case ExceptionHandlerType.Fault:
                        BlockRange faultBlockRange = GetBlockRangeFromInstructions(handler.HandlerStart, handler.HandlerEnd);
                        guardedBlock = new TryFaultLogicalConstruct(theTryBlock, CreateExceptionhandlingBlock(faultBlockRange));
                        break;

                    case ExceptionHandlerType.Finally:
                        BlockRange finallyBlockRange = GetBlockRangeFromInstructions(handler.HandlerStart, handler.HandlerEnd);
                        guardedBlock = new TryFinallyLogicalConstruct(theTryBlock, CreateExceptionhandlingBlock(finallyBlockRange));
                        break;
                    }

                    tryBlocksFound.Add(tryBlockRange, guardedBlock);
                }
            }
        }
Exemple #4
0
 internal static CFGBlockLogicalConstruct FindGuardedBlockCFGFollowNode(ExceptionHandlingLogicalConstruct construct, HashSet <CFGBlockLogicalConstruct> outOfconsideration)
 {
     V_0 = new Dictionary <CFGBlockLogicalConstruct, uint>();
     GuardedBlocksFollowNodesFinder.AddSuccessorsToCount(construct.get_Try(), V_0);
     V_1 = 1;
     if (construct as TryCatchFilterLogicalConstruct == null)
     {
         if (construct as TryFaultLogicalConstruct == null)
         {
             if (construct as TryFinallyLogicalConstruct != null)
             {
                 GuardedBlocksFollowNodesFinder.AddSuccessorsToCount((construct as TryFinallyLogicalConstruct).get_Finally(), V_0);
                 V_1 = V_1 + 1;
             }
         }
         else
         {
             GuardedBlocksFollowNodesFinder.AddSuccessorsToCount((construct as TryFaultLogicalConstruct).get_Fault(), V_0);
             V_1 = V_1 + 1;
         }
     }
     else
     {
         V_5 = (construct as TryCatchFilterLogicalConstruct).get_Handlers();
         V_6 = 0;
         while (V_6 < (int)V_5.Length)
         {
             GuardedBlocksFollowNodesFinder.AddSuccessorsToCount(V_5[V_6], V_0);
             V_1 = V_1 + 1;
             V_6 = V_6 + 1;
         }
     }
     V_7 = outOfconsideration.GetEnumerator();
     try
     {
         while (V_7.MoveNext())
         {
             V_8 = V_7.get_Current();
             if (!V_0.ContainsKey(V_8))
             {
                 continue;
             }
             dummyVar0 = V_0.Remove(V_8);
         }
     }
     finally
     {
         ((IDisposable)V_7).Dispose();
     }
     if (V_0.get_Count() == 0)
     {
         return(null);
     }
     V_2       = new HashSet <CFGBlockLogicalConstruct>();
     V_3       = V_0.get_Keys().FirstOrDefault <CFGBlockLogicalConstruct>();
     dummyVar1 = V_2.Add(V_3);
     V_4       = V_0.get_Item(V_3);
     V_9       = V_0.get_Keys().GetEnumerator();
     try
     {
         while (V_9.MoveNext())
         {
             V_10 = V_9.get_Current();
             if (V_0.get_Item(V_10) <= V_4)
             {
                 if (V_0.get_Item(V_10) != V_4)
                 {
                     continue;
                 }
                 dummyVar3 = V_2.Add(V_10);
             }
             else
             {
                 V_4 = V_0.get_Item(V_10);
                 V_2.Clear();
                 dummyVar2 = V_2.Add(V_10);
             }
         }
     }
     finally
     {
         ((IDisposable)V_9).Dispose();
     }
     if (V_2.get_Count() == 1)
     {
         return(V_2.FirstOrDefault <CFGBlockLogicalConstruct>());
     }
     V_11 = new HashSet <CFGBlockLogicalConstruct>();
     V_12 = 0;
     V_7  = V_2.GetEnumerator();
     try
     {
         while (V_7.MoveNext())
         {
             V_14 = V_7.get_Current();
             V_15 = 0;
             V_16 = construct.get_CFGBlocks();
             V_17 = V_14.get_CFGPredecessors().GetEnumerator();
             try
             {
                 while (V_17.MoveNext())
                 {
                     V_18 = V_17.get_Current();
                     if (!V_16.Contains(V_18))
                     {
                         continue;
                     }
                     V_15 = V_15 + 1;
                 }
             }
             finally
             {
                 ((IDisposable)V_17).Dispose();
             }
             if (V_15 < V_12)
             {
                 continue;
             }
             if (V_15 > V_12)
             {
                 V_12 = V_15;
                 V_11.Clear();
             }
             dummyVar4 = V_11.Add(V_14);
         }
     }
     finally
     {
         ((IDisposable)V_7).Dispose();
     }
     V_13 = V_11.FirstOrDefault <CFGBlockLogicalConstruct>();
     if (V_13.get_Index() < construct.get_Entry().get_Index())
     {
         V_19 = null;
         V_7  = V_11.GetEnumerator();
         try
         {
             while (V_7.MoveNext())
             {
                 V_20 = V_7.get_Current();
                 if (V_20.get_Index() <= construct.get_Entry().get_Index() || V_19 != null && V_19.get_Index() < V_20.get_Index())
                 {
                     continue;
                 }
                 V_19 = V_20;
             }
         }
         finally
         {
             ((IDisposable)V_7).Dispose();
         }
         if (V_19 != null)
         {
             V_13 = V_19;
         }
     }
     return(V_13);
 }
        internal static CFGBlockLogicalConstruct FindGuardedBlockCFGFollowNode(ExceptionHandlingLogicalConstruct construct, HashSet <CFGBlockLogicalConstruct> outOfconsideration)
        {
            //TODO: Don't consider leaves to blocks that end with return. The return can simpy be copied to the place where the leave originates by
            // the statement decompielr or the goto elimination later.


            //find all the targets the try/catch/filter/fault/finally blocks in the construct jump/leave to
            //record the number of leaves to each target
            Dictionary <CFGBlockLogicalConstruct, uint> numberOfHandlersLeavingToBlock = new Dictionary <CFGBlockLogicalConstruct, uint>();

            AddSuccessorsToCount(construct.Try, numberOfHandlersLeavingToBlock);
            uint leavableConstructsCount = 1;

            if (construct is TryCatchFilterLogicalConstruct)
            {
                TryCatchFilterLogicalConstruct tcf = construct as TryCatchFilterLogicalConstruct;
                foreach (IFilteringExceptionHandler handler in tcf.Handlers)
                {
                    AddSuccessorsToCount(handler, numberOfHandlersLeavingToBlock);
                    leavableConstructsCount++;
                }
            }
            else if (construct is TryFaultLogicalConstruct)
            {
                AddSuccessorsToCount((construct as TryFaultLogicalConstruct).Fault, numberOfHandlersLeavingToBlock);
                leavableConstructsCount++;
            }
            else if (construct is TryFinallyLogicalConstruct)
            {
                AddSuccessorsToCount((construct as TryFinallyLogicalConstruct).Finally, numberOfHandlersLeavingToBlock);
                leavableConstructsCount++;
            }

            //remove the leave targets taht should nto be considered
            foreach (CFGBlockLogicalConstruct ooc in outOfconsideration)
            {
                if (numberOfHandlersLeavingToBlock.ContainsKey(ooc))
                {
                    numberOfHandlersLeavingToBlock.Remove(ooc);
                }
            }

            if (numberOfHandlersLeavingToBlock.Count == 0)
            {
                return(null);
            }

            //find the leave targets that greatest number of exception handling blocks (try/catch/filter/fault/finally) jump to
            HashSet <CFGBlockLogicalConstruct> mostBlocksExitTo  = new HashSet <CFGBlockLogicalConstruct>();
            CFGBlockLogicalConstruct           randomLeaveTarget = numberOfHandlersLeavingToBlock.Keys.FirstOrDefault <CFGBlockLogicalConstruct>();

            mostBlocksExitTo.Add(randomLeaveTarget);
            uint maxNumberOfLeaveTargetPredecessors = numberOfHandlersLeavingToBlock[randomLeaveTarget];

            foreach (CFGBlockLogicalConstruct leaveTarget in numberOfHandlersLeavingToBlock.Keys)
            {
                if (numberOfHandlersLeavingToBlock[leaveTarget] > maxNumberOfLeaveTargetPredecessors)
                {
                    maxNumberOfLeaveTargetPredecessors = numberOfHandlersLeavingToBlock[leaveTarget];
                    mostBlocksExitTo.Clear();
                    mostBlocksExitTo.Add(leaveTarget);
                }
                else if (numberOfHandlersLeavingToBlock[leaveTarget] == maxNumberOfLeaveTargetPredecessors)
                {
                    mostBlocksExitTo.Add(leaveTarget);
                }
            }

            //use various heuristics to determine the best follow node
            //the follow node that will result in the smallest number of gotos is considered superior
            //the follow node could be changed once loops are created if it turns out loop condition was chosen as a follow node (i.e. we chose a continue edge)
            if (mostBlocksExitTo.Count == 1)
            {
                return(mostBlocksExitTo.FirstOrDefault <CFGBlockLogicalConstruct>());
            }
            else
            {
                HashSet <CFGBlockLogicalConstruct> mostLeavesPointTo = new HashSet <CFGBlockLogicalConstruct>();
                uint maxLeavesToSingleTarget = 0;
                foreach (CFGBlockLogicalConstruct leaveTarget in mostBlocksExitTo)
                {
                    uint leavesToThisTarget = 0;
                    HashSet <CFGBlockLogicalConstruct> constructCFGBlocks = construct.CFGBlocks;
                    foreach (CFGBlockLogicalConstruct leaveTargetpredecessor in leaveTarget.CFGPredecessors)
                    {
                        if (constructCFGBlocks.Contains(leaveTargetpredecessor))
                        {
                            leavesToThisTarget++;
                        }
                    }

                    if (leavesToThisTarget >= maxLeavesToSingleTarget)
                    {
                        if (leavesToThisTarget > maxLeavesToSingleTarget)
                        {
                            maxLeavesToSingleTarget = leavesToThisTarget;
                            mostLeavesPointTo.Clear();
                        }
                        mostLeavesPointTo.Add(leaveTarget);
                    }
                }

                //TODO: Try anoher heuristics here to chose the follow node that will minimize the number of gotos

                CFGBlockLogicalConstruct result = mostLeavesPointTo.FirstOrDefault <CFGBlockLogicalConstruct>();
                //HEURISTICS: Of all possible follow nodes we try to chose the one which start index is greater than the index of the exception construct start
                //but less than the start indexes of all other possible candidates. We rely on the assumption that the control flow closely resembles the ordering of
                // the IL instructions, i.e. if Instr. A  comes before Instr. B the chances are that Instr. A will have to be executed before Instr. B in any workflow.
                // That might not be the case but it's a good assumption since the compilers will try to express teh control flow in the least amount of jumps possible
                // for performance reasons.
                if (result.Index < construct.Entry.Index)
                {
                    CFGBlockLogicalConstruct closestAfterConstruct = null;
                    foreach (CFGBlockLogicalConstruct candidate in mostLeavesPointTo)
                    {
                        if (candidate.Index > construct.Entry.Index)
                        {
                            if (closestAfterConstruct != null && closestAfterConstruct.Index < candidate.Index)
                            {
                                continue;
                            }
                            closestAfterConstruct = candidate;
                        }
                    }

                    if (closestAfterConstruct != null)
                    {
                        result = closestAfterConstruct;
                    }
                }
                return(result);
            }
        }
		private void AddHandlerToTryBlock(ExceptionHandlingLogicalConstruct tryBlockExistingHandler, ExceptionHandler handler)
		{

			if (tryBlockExistingHandler is TryCatchFilterLogicalConstruct)
			{
				if (handler.HandlerType == ExceptionHandlerType.Fault || handler.HandlerType == ExceptionHandlerType.Finally)
				{
					//Fault/finally handlers cannot coexist together with any other type of handler on the same try block. New
					// try block should be defined for each of these.
					throw new Exception("Illegal IL: Non-exclusive Fault/Finally handler found");
				}
				else if (handler.HandlerType == ExceptionHandlerType.Filter)
				{
					(tryBlockExistingHandler as TryCatchFilterLogicalConstruct).AddHandler(CreateFilterHandler(handler));
				}
				else if (handler.HandlerType == ExceptionHandlerType.Catch)
				{
					(tryBlockExistingHandler as TryCatchFilterLogicalConstruct).AddHandler(CreateCatchHandler(handler));
				}
			}
			else if (tryBlockExistingHandler is TryFaultLogicalConstruct || tryBlockExistingHandler is TryFinallyLogicalConstruct)
			{
				//Fault/finally handlers cannot coexist together with any other type of handler on the same try block. New
				// try block should be defined for each of these.
				throw new Exception("Illegal IL: Non-exclusive Fault/Finally handler found");
			}
		}
		internal static CFGBlockLogicalConstruct FindGuardedBlockCFGFollowNode(ExceptionHandlingLogicalConstruct construct, HashSet<CFGBlockLogicalConstruct> outOfconsideration)
		{
			//TODO: Don't consider leaves to blocks that end with return. The return can simpy be copied to the place where the leave originates by
			// the statement decompielr or the goto elimination later.


			//find all the targets the try/catch/filter/fault/finally blocks in the construct jump/leave to
			//record the number of leaves to each target
			Dictionary<CFGBlockLogicalConstruct, uint> numberOfHandlersLeavingToBlock = new Dictionary<CFGBlockLogicalConstruct, uint>();
			AddSuccessorsToCount(construct.Try, numberOfHandlersLeavingToBlock);
			uint leavableConstructsCount = 1;

			if (construct is TryCatchFilterLogicalConstruct)
			{
				TryCatchFilterLogicalConstruct tcf = construct as TryCatchFilterLogicalConstruct;
				foreach (IFilteringExceptionHandler handler in tcf.Handlers)
				{
					AddSuccessorsToCount(handler, numberOfHandlersLeavingToBlock);
					leavableConstructsCount++;
				}
			}
			else if (construct is TryFaultLogicalConstruct)
			{
				AddSuccessorsToCount((construct as TryFaultLogicalConstruct).Fault, numberOfHandlersLeavingToBlock);
				leavableConstructsCount++;
			}
			else if (construct is TryFinallyLogicalConstruct)
			{
				AddSuccessorsToCount((construct as TryFinallyLogicalConstruct).Finally, numberOfHandlersLeavingToBlock);
				leavableConstructsCount++;
			}

			//remove the leave targets taht should nto be considered
			foreach (CFGBlockLogicalConstruct ooc in outOfconsideration)
			{
				if (numberOfHandlersLeavingToBlock.ContainsKey(ooc))
				{
					numberOfHandlersLeavingToBlock.Remove(ooc);
				}
			}

			if(numberOfHandlersLeavingToBlock.Count == 0)
			{
				return null;
			}

			//find the leave targets that greatest number of exception handling blocks (try/catch/filter/fault/finally) jump to
			HashSet<CFGBlockLogicalConstruct> mostBlocksExitTo = new HashSet<CFGBlockLogicalConstruct>();
			CFGBlockLogicalConstruct randomLeaveTarget = numberOfHandlersLeavingToBlock.Keys.FirstOrDefault<CFGBlockLogicalConstruct>();
			mostBlocksExitTo.Add(randomLeaveTarget);
			uint maxNumberOfLeaveTargetPredecessors = numberOfHandlersLeavingToBlock[randomLeaveTarget];
			foreach (CFGBlockLogicalConstruct leaveTarget in numberOfHandlersLeavingToBlock.Keys)
			{
				if (numberOfHandlersLeavingToBlock[leaveTarget] > maxNumberOfLeaveTargetPredecessors)
				{
					maxNumberOfLeaveTargetPredecessors = numberOfHandlersLeavingToBlock[leaveTarget];
					mostBlocksExitTo.Clear();
					mostBlocksExitTo.Add(leaveTarget);
				}
				else if (numberOfHandlersLeavingToBlock[leaveTarget] == maxNumberOfLeaveTargetPredecessors)
				{
					mostBlocksExitTo.Add(leaveTarget);
				}
			}

			//use various heuristics to determine the best follow node
			//the follow node that will result in the smallest number of gotos is considered superior
			//the follow node could be changed once loops are created if it turns out loop condition was chosen as a follow node (i.e. we chose a continue edge)
			if (mostBlocksExitTo.Count == 1)
			{
				return mostBlocksExitTo.FirstOrDefault<CFGBlockLogicalConstruct>();
			}
			else
			{
				HashSet<CFGBlockLogicalConstruct> mostLeavesPointTo = new HashSet<CFGBlockLogicalConstruct>();
				uint maxLeavesToSingleTarget = 0;
				foreach (CFGBlockLogicalConstruct leaveTarget in mostBlocksExitTo)
				{
					uint leavesToThisTarget = 0;
                    HashSet<CFGBlockLogicalConstruct> constructCFGBlocks = construct.CFGBlocks;
					foreach (CFGBlockLogicalConstruct leaveTargetpredecessor in leaveTarget.CFGPredecessors)
					{
						if (constructCFGBlocks.Contains(leaveTargetpredecessor))
						{
							leavesToThisTarget++;
						}
					}

					if (leavesToThisTarget >= maxLeavesToSingleTarget)
					{
						if (leavesToThisTarget > maxLeavesToSingleTarget)
						{
							maxLeavesToSingleTarget = leavesToThisTarget;
							mostLeavesPointTo.Clear();
						}
						mostLeavesPointTo.Add(leaveTarget);
					}
				}

				//TODO: Try anoher heuristics here to chose the follow node that will minimize the number of gotos

				CFGBlockLogicalConstruct result = mostLeavesPointTo.FirstOrDefault<CFGBlockLogicalConstruct>();
				//HEURISTICS: Of all possible follow nodes we try to chose the one which start index is greater than the index of the exception construct start
				//but less than the start indexes of all other possible candidates. We rely on the assumption that the control flow closely resembles the ordering of
 				// the IL instructions, i.e. if Instr. A  comes before Instr. B the chances are that Instr. A will have to be executed before Instr. B in any workflow.
				// That might not be the case but it's a good assumption since the compilers will try to express teh control flow in the least amount of jumps possible
				// for performance reasons.
				if(result.Index < construct.Entry.Index)
				{
					CFGBlockLogicalConstruct closestAfterConstruct = null;
					foreach (CFGBlockLogicalConstruct candidate in mostLeavesPointTo)
					{
						if (candidate.Index > construct.Entry.Index)
						{
							if (closestAfterConstruct != null && closestAfterConstruct.Index < candidate.Index)
							{
								continue;
							}
							closestAfterConstruct = candidate;
						}
					}

					if (closestAfterConstruct != null)
					{
						result = closestAfterConstruct;
					}
				}
				return result;
			}
		}