public void Scan(MethodBody methodBody) { MethodDefinition thisMethod = methodBody.Method; Dictionary <VariableDefinition, ValueBasicBlockPair> locals = new Dictionary <VariableDefinition, ValueBasicBlockPair> (methodBody.Variables.Count); Dictionary <int, Stack <StackSlot> > knownStacks = new Dictionary <int, Stack <StackSlot> > (); Stack <StackSlot> currentStack = new Stack <StackSlot> (methodBody.MaxStackSize); ScanExceptionInformation(knownStacks, methodBody); BasicBlockIterator blockIterator = new BasicBlockIterator(methodBody); MethodReturnValue = null; foreach (Instruction operation in methodBody.Instructions) { int curBasicBlock = blockIterator.MoveNext(operation); if (knownStacks.ContainsKey(operation.Offset)) { if (currentStack == null) { // The stack copy constructor reverses the stack currentStack = new Stack <StackSlot> (knownStacks[operation.Offset].Reverse()); } else { currentStack = MergeStack(currentStack, knownStacks[operation.Offset]); } } if (currentStack == null) { currentStack = new Stack <StackSlot> (methodBody.MaxStackSize); } switch (operation.OpCode.Code) { case Code.Add: case Code.Add_Ovf: case Code.Add_Ovf_Un: case Code.And: case Code.Div: case Code.Div_Un: case Code.Mul: case Code.Mul_Ovf: case Code.Mul_Ovf_Un: case Code.Or: case Code.Rem: case Code.Rem_Un: case Code.Sub: case Code.Sub_Ovf: case Code.Sub_Ovf_Un: case Code.Xor: case Code.Cgt: case Code.Cgt_Un: case Code.Clt: case Code.Clt_Un: case Code.Shl: case Code.Shr: case Code.Shr_Un: case Code.Ceq: PopUnknown(currentStack, 2, methodBody, operation.Offset); PushUnknown(currentStack); break; case Code.Dup: currentStack.Push(currentStack.Peek()); break; case Code.Ldnull: currentStack.Push(new StackSlot(NullValue.Instance)); break; case Code.Ldc_I4_0: case Code.Ldc_I4_1: case Code.Ldc_I4_2: case Code.Ldc_I4_3: case Code.Ldc_I4_4: case Code.Ldc_I4_5: case Code.Ldc_I4_6: case Code.Ldc_I4_7: case Code.Ldc_I4_8: { int value = operation.OpCode.Code - Code.Ldc_I4_0; ConstIntValue civ = new ConstIntValue(value); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case Code.Ldc_I4_M1: { ConstIntValue civ = new ConstIntValue(-1); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case Code.Ldc_I4: { int value = (int)operation.Operand; ConstIntValue civ = new ConstIntValue(value); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case Code.Ldc_I4_S: { int value = (sbyte)operation.Operand; ConstIntValue civ = new ConstIntValue(value); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case Code.Arglist: case Code.Ldftn: case Code.Sizeof: case Code.Ldc_I8: case Code.Ldc_R4: case Code.Ldc_R8: PushUnknown(currentStack); break; case Code.Ldarg: case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: case Code.Ldarg_S: case Code.Ldarga: case Code.Ldarga_S: ScanLdarg(operation, currentStack, thisMethod, methodBody); break; case Code.Ldloc: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: case Code.Ldloc_S: case Code.Ldloca: case Code.Ldloca_S: ScanLdloc(operation, currentStack, methodBody, locals); break; case Code.Ldstr: { StackSlot slot = new StackSlot(new KnownStringValue((string)operation.Operand)); currentStack.Push(slot); } break; case Code.Ldtoken: ScanLdtoken(operation, currentStack); break; case Code.Ldind_I: case Code.Ldind_I1: case Code.Ldind_I2: case Code.Ldind_I4: case Code.Ldind_I8: case Code.Ldind_R4: case Code.Ldind_R8: case Code.Ldind_U1: case Code.Ldind_U2: case Code.Ldind_U4: case Code.Ldlen: case Code.Ldvirtftn: case Code.Localloc: case Code.Refanytype: case Code.Refanyval: case Code.Conv_I1: case Code.Conv_I2: case Code.Conv_I4: case Code.Conv_Ovf_I1: case Code.Conv_Ovf_I1_Un: case Code.Conv_Ovf_I2: case Code.Conv_Ovf_I2_Un: case Code.Conv_Ovf_I4: case Code.Conv_Ovf_I4_Un: case Code.Conv_Ovf_U: case Code.Conv_Ovf_U_Un: case Code.Conv_Ovf_U1: case Code.Conv_Ovf_U1_Un: case Code.Conv_Ovf_U2: case Code.Conv_Ovf_U2_Un: case Code.Conv_Ovf_U4: case Code.Conv_Ovf_U4_Un: case Code.Conv_U1: case Code.Conv_U2: case Code.Conv_U4: case Code.Conv_I8: case Code.Conv_Ovf_I8: case Code.Conv_Ovf_I8_Un: case Code.Conv_Ovf_U8: case Code.Conv_Ovf_U8_Un: case Code.Conv_U8: case Code.Conv_I: case Code.Conv_Ovf_I: case Code.Conv_Ovf_I_Un: case Code.Conv_U: case Code.Conv_R_Un: case Code.Conv_R4: case Code.Conv_R8: case Code.Ldind_Ref: case Code.Ldobj: case Code.Mkrefany: case Code.Unbox: case Code.Unbox_Any: case Code.Box: case Code.Neg: case Code.Not: PopUnknown(currentStack, 1, methodBody, operation.Offset); PushUnknown(currentStack); break; case Code.Isinst: case Code.Castclass: // We can consider a NOP because the value doesn't change. // It might change to NULL, but for the purposes of dataflow analysis // it doesn't hurt much. break; case Code.Ldfld: case Code.Ldsfld: case Code.Ldflda: case Code.Ldsflda: ScanLdfld(operation, currentStack, thisMethod, methodBody); break; case Code.Newarr: { StackSlot count = PopUnknown(currentStack, 1, methodBody, operation.Offset); currentStack.Push(new StackSlot(new ArrayValue(count.Value, (TypeReference)operation.Operand))); } break; case Code.Stelem_I: case Code.Stelem_I1: case Code.Stelem_I2: case Code.Stelem_I4: case Code.Stelem_I8: case Code.Stelem_R4: case Code.Stelem_R8: case Code.Stelem_Any: case Code.Stelem_Ref: ScanStelem(operation, currentStack, methodBody, curBasicBlock); break; case Code.Ldelem_I: case Code.Ldelem_I1: case Code.Ldelem_I2: case Code.Ldelem_I4: case Code.Ldelem_I8: case Code.Ldelem_R4: case Code.Ldelem_R8: case Code.Ldelem_U1: case Code.Ldelem_U2: case Code.Ldelem_U4: case Code.Ldelem_Any: case Code.Ldelem_Ref: case Code.Ldelema: ScanLdelem(operation, currentStack, methodBody, curBasicBlock); break; case Code.Cpblk: case Code.Initblk: PopUnknown(currentStack, 3, methodBody, operation.Offset); break; case Code.Stfld: case Code.Stsfld: ScanStfld(operation, currentStack, thisMethod, methodBody); break; case Code.Cpobj: PopUnknown(currentStack, 2, methodBody, operation.Offset); break; case Code.Stind_I: case Code.Stind_I1: case Code.Stind_I2: case Code.Stind_I4: case Code.Stind_I8: case Code.Stind_R4: case Code.Stind_R8: case Code.Stind_Ref: case Code.Stobj: ScanIndirectStore(operation, currentStack, methodBody); break; case Code.Initobj: case Code.Pop: PopUnknown(currentStack, 1, methodBody, operation.Offset); break; case Code.Starg: case Code.Starg_S: ScanStarg(operation, currentStack, thisMethod, methodBody); break; case Code.Stloc: case Code.Stloc_S: case Code.Stloc_0: case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: ScanStloc(operation, currentStack, methodBody, locals, curBasicBlock); break; case Code.Constrained: case Code.No: case Code.Readonly: case Code.Tail: case Code.Unaligned: case Code.Volatile: break; case Code.Brfalse: case Code.Brfalse_S: case Code.Brtrue: case Code.Brtrue_S: PopUnknown(currentStack, 1, methodBody, operation.Offset); NewKnownStack(knownStacks, ((Instruction)operation.Operand).Offset, currentStack); break; case Code.Calli: { var signature = (CallSite)operation.Operand; if (signature.HasThis && !signature.ExplicitThis) { PopUnknown(currentStack, 1, methodBody, operation.Offset); } // Pop arguments PopUnknown(currentStack, signature.Parameters.Count, methodBody, operation.Offset); // Pop function pointer PopUnknown(currentStack, 1, methodBody, operation.Offset); // Push return value if (signature.ReturnType.MetadataType != MetadataType.Void) { PushUnknown(currentStack); } } break; case Code.Call: case Code.Callvirt: case Code.Newobj: HandleCall(methodBody, operation, currentStack, curBasicBlock); break; case Code.Jmp: // Not generated by mainstream compilers break; case Code.Br: case Code.Br_S: NewKnownStack(knownStacks, ((Instruction)operation.Operand).Offset, currentStack); ClearStack(ref currentStack); break; case Code.Leave: case Code.Leave_S: ClearStack(ref currentStack); NewKnownStack(knownStacks, ((Instruction)operation.Operand).Offset, new Stack <StackSlot> (methodBody.MaxStackSize)); break; case Code.Endfilter: case Code.Endfinally: case Code.Rethrow: case Code.Throw: ClearStack(ref currentStack); break; case Code.Ret: { bool hasReturnValue = methodBody.Method.ReturnType.MetadataType != MetadataType.Void; if (currentStack.Count != (hasReturnValue ? 1 : 0)) { WarnAboutInvalidILInMethod(methodBody, operation.Offset); } if (hasReturnValue) { StackSlot retValue = PopUnknown(currentStack, 1, methodBody, operation.Offset); MethodReturnValue = MergePointValue.MergeValues(MethodReturnValue, retValue.Value); } ClearStack(ref currentStack); break; } case Code.Switch: { PopUnknown(currentStack, 1, methodBody, operation.Offset); Instruction[] targets = (Instruction[])operation.Operand; foreach (Instruction target in targets) { NewKnownStack(knownStacks, target.Offset, currentStack); } break; } case Code.Beq: case Code.Beq_S: case Code.Bne_Un: case Code.Bne_Un_S: case Code.Bge: case Code.Bge_S: case Code.Bge_Un: case Code.Bge_Un_S: case Code.Bgt: case Code.Bgt_S: case Code.Bgt_Un: case Code.Bgt_Un_S: case Code.Ble: case Code.Ble_S: case Code.Ble_Un: case Code.Ble_Un_S: case Code.Blt: case Code.Blt_S: case Code.Blt_Un: case Code.Blt_Un_S: PopUnknown(currentStack, 2, methodBody, operation.Offset); NewKnownStack(knownStacks, ((Instruction)operation.Operand).Offset, currentStack); break; } } }
public void Scan(MethodIL methodBody) { MethodDesc thisMethod = methodBody.OwningMethod; ValueBasicBlockPair[] locals = new ValueBasicBlockPair[methodBody.GetLocals().Length]; Dictionary <int, Stack <StackSlot> > knownStacks = new Dictionary <int, Stack <StackSlot> >(); Stack <StackSlot> currentStack = new Stack <StackSlot>(methodBody.MaxStack); ScanExceptionInformation(knownStacks, methodBody); BasicBlockIterator blockIterator = new BasicBlockIterator(methodBody); MethodReturnValue = null; ILReader reader = new ILReader(methodBody.GetILBytes()); while (reader.HasNext) { int curBasicBlock = blockIterator.MoveNext(reader.Offset); if (knownStacks.ContainsKey(reader.Offset)) { if (currentStack == null) { // The stack copy constructor reverses the stack currentStack = new Stack <StackSlot>(knownStacks[reader.Offset].Reverse()); } else { currentStack = MergeStack(currentStack, knownStacks[reader.Offset]); } } if (currentStack == null) { currentStack = new Stack <StackSlot>(methodBody.MaxStack); } int offset = reader.Offset; ILOpcode opcode = reader.ReadILOpcode(); switch (opcode) { case ILOpcode.add: case ILOpcode.add_ovf: case ILOpcode.add_ovf_un: case ILOpcode.and: case ILOpcode.div: case ILOpcode.div_un: case ILOpcode.mul: case ILOpcode.mul_ovf: case ILOpcode.mul_ovf_un: case ILOpcode.or: case ILOpcode.rem: case ILOpcode.rem_un: case ILOpcode.sub: case ILOpcode.sub_ovf: case ILOpcode.sub_ovf_un: case ILOpcode.xor: case ILOpcode.cgt: case ILOpcode.cgt_un: case ILOpcode.clt: case ILOpcode.clt_un: case ILOpcode.shl: case ILOpcode.shr: case ILOpcode.shr_un: case ILOpcode.ceq: PopUnknown(currentStack, 2, methodBody, offset); PushUnknown(currentStack); reader.Skip(opcode); break; case ILOpcode.dup: currentStack.Push(currentStack.Peek()); break; case ILOpcode.ldnull: currentStack.Push(new StackSlot(NullValue.Instance)); break; case ILOpcode.ldc_i4_0: case ILOpcode.ldc_i4_1: case ILOpcode.ldc_i4_2: case ILOpcode.ldc_i4_3: case ILOpcode.ldc_i4_4: case ILOpcode.ldc_i4_5: case ILOpcode.ldc_i4_6: case ILOpcode.ldc_i4_7: case ILOpcode.ldc_i4_8: { int value = opcode - ILOpcode.ldc_i4_0; ConstIntValue civ = new ConstIntValue(value); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case ILOpcode.ldc_i4_m1: { ConstIntValue civ = new ConstIntValue(-1); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case ILOpcode.ldc_i4: { int value = (int)reader.ReadILUInt32(); ConstIntValue civ = new ConstIntValue(value); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case ILOpcode.ldc_i4_s: { int value = (sbyte)reader.ReadILByte(); ConstIntValue civ = new ConstIntValue(value); StackSlot slot = new StackSlot(civ); currentStack.Push(slot); } break; case ILOpcode.arglist: case ILOpcode.ldftn: case ILOpcode.sizeof_: case ILOpcode.ldc_i8: case ILOpcode.ldc_r4: case ILOpcode.ldc_r8: PushUnknown(currentStack); reader.Skip(opcode); break; case ILOpcode.ldarg: case ILOpcode.ldarg_0: case ILOpcode.ldarg_1: case ILOpcode.ldarg_2: case ILOpcode.ldarg_3: case ILOpcode.ldarg_s: case ILOpcode.ldarga: case ILOpcode.ldarga_s: ScanLdarg(opcode, opcode switch { ILOpcode.ldarg => reader.ReadILUInt16(), ILOpcode.ldarga => reader.ReadILUInt16(), ILOpcode.ldarg_s => reader.ReadILByte(), ILOpcode.ldarga_s => reader.ReadILByte(), _ => opcode - ILOpcode.ldarg_0 }, currentStack, thisMethod); break;