Ejemplo n.º 1
0
        static void InsertEmptyStateUpdate(CFGContext ctx, ControlFlowBlock block)
        {
            var body = ctx.Graph.Body;
            var key = ctx.Keys[block.Id];
            if (key.EntryState == key.ExitState)
                return;

            Instruction first = null;
            // Cannot use graph.IndexOf because instructions has been modified.
            int targetIndex = body.Instructions.IndexOf(block.Header);

            CFGState entry;
            if (!ctx.StatesMap.TryGetValue(key.EntryState, out entry)) {
                Debug.Assert(key.Type == BlockKeyType.Explicit);
                key.Type = BlockKeyType.Explicit;
            }

            if (key.Type == BlockKeyType.Incremental) {
                // Incremental

                CFGState exit;
                if (!ctx.StatesMap.TryGetValue(key.ExitState, out exit)) {
                    // Create new exit state
                    // Update one of the entry states to be exit state
                    exit = entry;
                    int updateId = ctx.Random.NextInt32(3);
                    uint targetValue = ctx.Random.NextUInt32();
                    exit.UpdateExplicit(updateId, targetValue);

                    int getId = ctx.Random.NextInt32(3);
                    var fl = CFGState.EncodeFlag(false, updateId, getId);
                    var incr = entry.GetIncrementalUpdate(updateId, targetValue);

                    body.Instructions.Insert(targetIndex++, first = Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                    body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                    body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)incr));
                    body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));
                    body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Pop));

                    ctx.StatesMap[key.ExitState] = exit;
                }
                else {
                    // Scan for updated state
                    var headerIndex = targetIndex;
                    for (int stateId = 0; stateId < 4; stateId++) {
                        if (entry.Get(stateId) == exit.Get(stateId))
                            continue;

                        uint targetValue = exit.Get(stateId);
                        int getId = ctx.Random.NextInt32(3);
                        var fl = CFGState.EncodeFlag(false, stateId, getId);
                        var incr = entry.GetIncrementalUpdate(stateId, targetValue);

                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)incr));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Pop));
                    }
                    first = body.Instructions[headerIndex];
                }
            }
            else {
                // Explicit

                CFGState exit;
                if (!ctx.StatesMap.TryGetValue(key.ExitState, out exit)) {
                    // Create new exit state from random seed
                    var seed = ctx.Random.NextUInt32();
                    exit = new CFGState(seed);
                    body.Instructions.Insert(targetIndex++, first = Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                    body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)seed));
                    body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxCtor));

                    ctx.StatesMap[key.ExitState] = exit;
                }
                else {
                    // Scan for updated state
                    var headerIndex = targetIndex;
                    for (int stateId = 0; stateId < 4; stateId++) {
                        uint targetValue = exit.Get(stateId);
                        int getId = ctx.Random.NextInt32(3);
                        var fl = CFGState.EncodeFlag(true, stateId, getId);

                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)targetValue));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Pop));
                    }
                    first = body.Instructions[headerIndex];
                }
            }

            ctx.Graph.Body.ReplaceReference(block.Header, first);
        }
Ejemplo n.º 2
0
        static void ReplaceCFG(MethodDef method, List<Tuple<Instruction, uint, IMethod>> instrs, CEContext ctx)
        {
            InjectStateType(ctx);

            var graph = ControlFlowGraph.Construct(method.Body);
            var sequence = KeySequence.ComputeKeys(graph, null);

            var cfgCtx = new CFGContext {
                Ctx = ctx,
                Graph = graph,
                Keys = sequence,
                StatesMap = new Dictionary<uint, CFGState>(),
                Random = ctx.Random
            };

            cfgCtx.StateVariable = new Local(ctx.CfgCtxType.ToTypeSig());
            method.Body.Variables.Add(cfgCtx.StateVariable);
            method.Body.InitLocals = true;

            var blockReferences = new Dictionary<int, SortedList<int, Tuple<Instruction, uint, IMethod>>>();
            foreach (var instr in instrs) {
                var index = graph.IndexOf(instr.Item1);
                var block = graph.GetContainingBlock(index);

                SortedList<int, Tuple<Instruction, uint, IMethod>> list;
                if (!blockReferences.TryGetValue(block.Id, out list))
                    list = blockReferences[block.Id] = new SortedList<int, Tuple<Instruction, uint, IMethod>>();

                list.Add(index, instr);
            }

            // Update state for blocks not in use
            for (int i = 0; i < graph.Count; i++) {
                if (blockReferences.ContainsKey(i))
                    continue;
                InsertEmptyStateUpdate(cfgCtx, graph[i]);
            }

            // Update references
            foreach (var blockRef in blockReferences) {
                var key = sequence[blockRef.Key];
                CFGState currentState;
                if (!cfgCtx.StatesMap.TryGetValue(key.EntryState, out currentState)) {
                    Debug.Assert((graph[blockRef.Key].Type & ControlFlowBlockType.Entry) != 0);
                    Debug.Assert(key.Type == BlockKeyType.Explicit);

                    // Create new entry state
                    uint blockSeed = ctx.Random.NextUInt32();
                    currentState = new CFGState(blockSeed);
                    cfgCtx.StatesMap[key.EntryState] = currentState;

                    var index = graph.Body.Instructions.IndexOf(graph[blockRef.Key].Header);
                    Instruction newHeader;
                    method.Body.Instructions.Insert(index++, newHeader = Instruction.Create(OpCodes.Ldloca, cfgCtx.StateVariable));
                    method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)blockSeed));
                    method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.CfgCtxCtor));
                    method.Body.ReplaceReference(graph[blockRef.Key].Header, newHeader);
                    key.Type = BlockKeyType.Incremental;
                }
                var type = key.Type;

                for (int i = 0; i < blockRef.Value.Count; i++) {
                    var refEntry = blockRef.Value.Values[i];

                    CFGState? targetState = null;
                    if (i == blockRef.Value.Count - 1) {
                        CFGState exitState;
                        if (cfgCtx.StatesMap.TryGetValue(key.ExitState, out exitState))
                            targetState = exitState;
                    }

                    var index = graph.Body.Instructions.IndexOf(refEntry.Item1) + 1;
                    var value = InsertStateGetAndUpdate(cfgCtx, ref index, type, ref currentState, targetState);

                    refEntry.Item1.OpCode = OpCodes.Ldc_I4;
                    refEntry.Item1.Operand = (int)(refEntry.Item2 ^ value);
                    method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Xor));
                    method.Body.Instructions.Insert(index, Instruction.Create(OpCodes.Call, refEntry.Item3));

                    if (i == blockRef.Value.Count - 1 && targetState == null) {
                        cfgCtx.StatesMap[key.ExitState] = currentState;
                    }

                    type = BlockKeyType.Incremental;
                }
            }
        }
Ejemplo n.º 3
0
        static uint InsertStateGetAndUpdate(CFGContext ctx, ref int index, BlockKeyType type, ref CFGState currentState, CFGState? targetState)
        {
            var body = ctx.Graph.Body;

            if (type == BlockKeyType.Incremental) {
                // Incremental

                if (targetState == null) {
                    // Randomly update and get state
                    int updateId = ctx.Random.NextInt32(3);
                    uint targetValue = ctx.Random.NextUInt32();

                    int getId = ctx.Random.NextInt32(3);
                    var fl = CFGState.EncodeFlag(false, updateId, getId);
                    var incr = currentState.GetIncrementalUpdate(updateId, targetValue);
                    currentState.UpdateExplicit(updateId, targetValue);

                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)incr));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));

                    return currentState.Get(getId);
                }
                // Scan for updated state
                int[] stateIds = { 0, 1, 2, 3 };
                ctx.Random.Shuffle(stateIds);
                int i = 0;
                uint getValue = 0;
                foreach (var stateId in stateIds) {
                    // There must be at least one update&get
                    if (currentState.Get(stateId) == targetState.Value.Get(stateId) &&
                        i != stateIds.Length - 1) {
                        i++;
                        continue;
                    }

                    uint targetValue = targetState.Value.Get(stateId);
                    int getId = ctx.Random.NextInt32(3);
                    var fl = CFGState.EncodeFlag(false, stateId, getId);
                    var incr = currentState.GetIncrementalUpdate(stateId, targetValue);
                    currentState.UpdateExplicit(stateId, targetValue);

                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)incr));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));

                    i++;
                    if (i == stateIds.Length)
                        getValue = currentState.Get(getId);
                    else
                        body.Instructions.Insert(index++, Instruction.Create(OpCodes.Pop));
                }
                return getValue;
            }
            else {
                // Explicit

                if (targetState == null) {
                    // Create new exit state from random seed
                    var seed = ctx.Random.NextUInt32();
                    currentState = new CFGState(seed);
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Dup));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)seed));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxCtor));

                    // Randomly get state
                    int updateId = ctx.Random.NextInt32(3);
                    uint targetValue = ctx.Random.NextUInt32();

                    int getId = ctx.Random.NextInt32(3);
                    var fl = CFGState.EncodeFlag(false, updateId, getId);
                    var incr = currentState.GetIncrementalUpdate(updateId, targetValue);
                    currentState.UpdateExplicit(updateId, targetValue);

                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)incr));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));

                    return currentState.Get(getId);
                }
                else {
                    // Scan for updated state
                    int[] stateIds = { 0, 1, 2, 3 };
                    ctx.Random.Shuffle(stateIds);
                    int i = 0;
                    uint getValue = 0;
                    foreach (var stateId in stateIds) {
                        uint targetValue = targetState.Value.Get(stateId);
                        int getId = ctx.Random.NextInt32(3);
                        var fl = CFGState.EncodeFlag(true, stateId, getId);
                        currentState.UpdateExplicit(stateId, targetValue);

                        body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                        body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                        body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)targetValue));
                        body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));

                        i++;
                        if (i == stateIds.Length)
                            getValue = targetState.Value.Get(getId);
                        else
                            body.Instructions.Insert(index++, Instruction.Create(OpCodes.Pop));
                    }
                    return getValue;
                }
            }
        }
Ejemplo n.º 4
0
        static void ReplaceCFG(MethodDef method, List <Tuple <Instruction, uint, IMethod> > instrs, CEContext ctx)
        {
            InjectStateType(ctx);

            var graph    = ControlFlowGraph.Construct(method.Body);
            var sequence = KeySequence.ComputeKeys(graph, null);

            var cfgCtx = new CFGContext {
                Ctx       = ctx,
                Graph     = graph,
                Keys      = sequence,
                StatesMap = new Dictionary <uint, CFGState>(),
                Random    = ctx.Random
            };

            cfgCtx.StateVariable = new Local(ctx.CfgCtxType.ToTypeSig());
            method.Body.Variables.Add(cfgCtx.StateVariable);
            method.Body.InitLocals = true;

            var blockReferences = new Dictionary <int, SortedList <int, Tuple <Instruction, uint, IMethod> > >();

            foreach (var instr in instrs)
            {
                var index = graph.IndexOf(instr.Item1);
                var block = graph.GetContainingBlock(index);

                SortedList <int, Tuple <Instruction, uint, IMethod> > list;
                if (!blockReferences.TryGetValue(block.Id, out list))
                {
                    list = blockReferences[block.Id] = new SortedList <int, Tuple <Instruction, uint, IMethod> >();
                }

                list.Add(index, instr);
            }

            // Update state for blocks not in use
            for (int i = 0; i < graph.Count; i++)
            {
                var block = graph[i];
                if (blockReferences.ContainsKey(block.Id))
                {
                    continue;
                }
                InsertEmptyStateUpdate(cfgCtx, block);
            }

            // Update references
            foreach (var blockRef in blockReferences)
            {
                var      key = sequence[blockRef.Key];
                CFGState currentState;
                if (!cfgCtx.StatesMap.TryGetValue(key.EntryState, out currentState))
                {
                    Debug.Assert((graph[blockRef.Key].Type & ControlFlowBlockType.Entry) != 0);
                    Debug.Assert(key.Type == BlockKeyType.Explicit);

                    // Create new entry state
                    uint blockSeed = ctx.Random.NextUInt32();
                    currentState = new CFGState(blockSeed);
                    cfgCtx.StatesMap[key.EntryState] = currentState;

                    var         index = graph.Body.Instructions.IndexOf(graph[blockRef.Key].Header);
                    Instruction newHeader;
                    method.Body.Instructions.Insert(index++, newHeader = Instruction.Create(OpCodes.Ldloca, cfgCtx.StateVariable));
                    method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)blockSeed));
                    method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.CfgCtxCtor));
                    method.Body.ReplaceReference(graph[blockRef.Key].Header, newHeader);
                    key.Type = BlockKeyType.Incremental;
                }
                var type = key.Type;

                for (int i = 0; i < blockRef.Value.Count; i++)
                {
                    var refEntry = blockRef.Value.Values[i];

                    CFGState?targetState = null;
                    if (i == blockRef.Value.Count - 1)
                    {
                        CFGState exitState;
                        if (cfgCtx.StatesMap.TryGetValue(key.ExitState, out exitState))
                        {
                            targetState = exitState;
                        }
                    }

                    var index = graph.Body.Instructions.IndexOf(refEntry.Item1) + 1;
                    var value = InsertStateGetAndUpdate(cfgCtx, ref index, type, ref currentState, targetState);

                    refEntry.Item1.OpCode  = OpCodes.Ldc_I4;
                    refEntry.Item1.Operand = (int)(refEntry.Item2 ^ value);
                    method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)refEntry.Item2 - new Random().Next(1, 7000)));
                    method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)(refEntry.Item2 ^ value)));
                    method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, new Random().Next(1, 7000)));

                    if (i == blockRef.Value.Count - 1 && targetState == null)
                    {
                        cfgCtx.StatesMap[key.ExitState] = currentState;
                    }

                    type = BlockKeyType.Incremental;
                }
            }
        }
Ejemplo n.º 5
0
        static uint InsertStateGetAndUpdate(CFGContext ctx, ref int index, BlockKeyType type, ref CFGState currentState, CFGState?targetState)
        {
            var body = ctx.Graph.Body;

            if (type == BlockKeyType.Incremental)
            {
                // Incremental

                if (targetState == null)
                {
                    // Randomly update and get state
                    int  updateId    = ctx.Random.NextInt32(3);
                    uint targetValue = ctx.Random.NextUInt32();

                    int getId = ctx.Random.NextInt32(3);
                    var fl    = CFGState.EncodeFlag(false, updateId, getId);
                    var incr  = currentState.GetIncrementalUpdate(updateId, targetValue);
                    currentState.UpdateExplicit(updateId, targetValue);

                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)incr));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));

                    return(currentState.Get(getId));
                }
                // Scan for updated state
                int[] stateIds = { 0, 1, 2, 3 };
                ctx.Random.Shuffle(stateIds);
                int  i        = 0;
                uint getValue = 0;
                foreach (var stateId in stateIds)
                {
                    // There must be at least one update&get
                    if (currentState.Get(stateId) == targetState.Value.Get(stateId) &&
                        i != stateIds.Length - 1)
                    {
                        i++;
                        continue;
                    }

                    uint targetValue = targetState.Value.Get(stateId);
                    int  getId       = ctx.Random.NextInt32(3);
                    var  fl          = CFGState.EncodeFlag(false, stateId, getId);
                    var  incr        = currentState.GetIncrementalUpdate(stateId, targetValue);
                    currentState.UpdateExplicit(stateId, targetValue);

                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)incr));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));

                    i++;
                    if (i == stateIds.Length)
                    {
                        getValue = currentState.Get(getId);
                    }
                    else
                    {
                        body.Instructions.Insert(index++, Instruction.Create(OpCodes.Pop));
                    }
                }
                return(getValue);
            }
            else
            {
                // Explicit

                if (targetState == null)
                {
                    // Create new exit state from random seed
                    var seed = ctx.Random.NextUInt32();
                    currentState = new CFGState(seed);
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Dup));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)seed));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxCtor));

                    // Randomly get state
                    int  updateId    = ctx.Random.NextInt32(3);
                    uint targetValue = ctx.Random.NextUInt32();

                    int getId = ctx.Random.NextInt32(3);
                    var fl    = CFGState.EncodeFlag(false, updateId, getId);
                    var incr  = currentState.GetIncrementalUpdate(updateId, targetValue);
                    currentState.UpdateExplicit(updateId, targetValue);

                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)incr));
                    body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));

                    return(currentState.Get(getId));
                }
                else
                {
                    // Scan for updated state
                    int[] stateIds = { 0, 1, 2, 3 };
                    ctx.Random.Shuffle(stateIds);
                    int  i        = 0;
                    uint getValue = 0;
                    foreach (var stateId in stateIds)
                    {
                        uint targetValue = targetState.Value.Get(stateId);
                        int  getId       = ctx.Random.NextInt32(3);
                        var  fl          = CFGState.EncodeFlag(true, stateId, getId);
                        currentState.UpdateExplicit(stateId, targetValue);

                        body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                        body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                        body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)targetValue));
                        body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));

                        i++;
                        if (i == stateIds.Length)
                        {
                            getValue = targetState.Value.Get(getId);
                        }
                        else
                        {
                            body.Instructions.Insert(index++, Instruction.Create(OpCodes.Pop));
                        }
                    }
                    return(getValue);
                }
            }
        }
Ejemplo n.º 6
0
        static void InsertEmptyStateUpdate(CFGContext ctx, ControlFlowBlock block)
        {
            var body = ctx.Graph.Body;
            var key  = ctx.Keys[block.Id];

            if (key.EntryState == key.ExitState)
            {
                return;
            }

            Instruction first = null;

            int targetIndex = body.Instructions.IndexOf(block.Header);

            CFGState entry;

            if (!ctx.StatesMap.TryGetValue(key.EntryState, out entry))
            {
                key.Type = BlockKeyType.Explicit;
            }


            if (key.Type == BlockKeyType.Incremental)
            {
                CFGState exit;
                if (!ctx.StatesMap.TryGetValue(key.ExitState, out exit))
                {
                    exit = entry;
                    int  updateId    = ctx.Random.NextInt32(3);
                    uint targetValue = ctx.Random.NextUInt32();
                    exit.UpdateExplicit(updateId, targetValue);

                    int getId = ctx.Random.NextInt32(3);
                    var fl    = CFGState.EncodeFlag(false, updateId, getId);
                    var incr  = entry.GetIncrementalUpdate(updateId, targetValue);

                    body.Instructions.Insert(targetIndex++, first = Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                    body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                    body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)incr));
                    body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));
                    body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Pop));

                    ctx.StatesMap[key.ExitState] = exit;
                }
                else
                {
                    var headerIndex = targetIndex;
                    for (int stateId = 0; stateId < 4; stateId++)
                    {
                        if (entry.Get(stateId) == exit.Get(stateId))
                        {
                            continue;
                        }

                        uint targetValue = exit.Get(stateId);
                        int  getId       = ctx.Random.NextInt32(3);
                        var  fl          = CFGState.EncodeFlag(false, stateId, getId);
                        var  incr        = entry.GetIncrementalUpdate(stateId, targetValue);

                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)incr));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Pop));
                    }
                    first = body.Instructions[headerIndex];
                }
            }
            else
            {
                CFGState exit;
                if (!ctx.StatesMap.TryGetValue(key.ExitState, out exit))
                {
                    var seed = ctx.Random.NextUInt32();
                    exit = new CFGState(seed);
                    body.Instructions.Insert(targetIndex++, first = Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                    body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)seed));
                    body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxCtor));

                    ctx.StatesMap[key.ExitState] = exit;
                }
                else
                {
                    var headerIndex = targetIndex;
                    for (int stateId = 0; stateId < 4; stateId++)
                    {
                        uint targetValue = exit.Get(stateId);
                        int  getId       = ctx.Random.NextInt32(3);
                        var  fl          = CFGState.EncodeFlag(true, stateId, getId);

                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)targetValue));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext));
                        body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Pop));
                    }
                    first = body.Instructions[headerIndex];
                }
            }

            ctx.Graph.Body.ReplaceReference(block.Header, first);
        }