public static void ProcessCallOrNewobj(MethodInfoExtention method,StackTypes stack, bool isNewObj) { for(int i = method.ArgCount-1; i >= (isNewObj ? 1 : 0); i--) { //when we are creating a new object `this` is not on stack TypeEx sourceType = stack.Pop(); TypeEx targetType = method.GetArgType(i); TypeChecker.CheckAssignment(targetType, sourceType); } TypeEx returnType = method.GetReturnType(); if(isNewObj) stack.Push(method.DeclaringType); //Wow! Value-types can be created on stack with NEWOBJ instruction -- not boxed else if(!returnType.type.Equals(typeof(void))) stack.Push(returnType); }
internal static bool Check(MethodEx methodRepr) { //Attention: the `null` value on stack means a null reference that is of any object type //As `typeof(object)` is the most general Type, so `null` is the most exact object type FreeStacks(methodRepr); try { Instruction lastI = methodRepr[methodRepr.Count-1]; if( lastI.Code != InstructionCode.RET && lastI.Code != InstructionCode.BR && lastI.Code != InstructionCode.THROW && lastI.Code != InstructionCode.RETHROW && lastI.Code != InstructionCode.LEAVE && lastI.Code != InstructionCode.ENDFINALLY && lastI.Code != InstructionCode.ENDFILTER ) throw new VerifierException(); MethodInfoExtention method = new MethodInfoExtention(methodRepr.Method); StackTypes stack = new StackTypes(); //initially the stack is empty int nextHandler = FindNextHandler(-1,methodRepr.EHClauses); CheckBlockExits(methodRepr); for (int iNum = 0; iNum < methodRepr.Count ; iNum ++) { Instruction i = methodRepr[iNum]; i.SetStack(MergeStacks(i.Stack,stack)); if(nextHandler == iNum) { PushExceptionOnStack(iNum,i.Stack,methodRepr.EHClauses); nextHandler = FindNextHandler(iNum,methodRepr.EHClauses); } stack = i.Stack.Clone() as StackTypes; switch(i.Code) { case InstructionCode.DUP : { stack.Push(stack.Peek()); } break; case InstructionCode.LDARG : { stack.Push(method.GetArgType((Int32)i.Param)); } break; case InstructionCode.LDARGA : { TypeEx t = method.GetArgType((Int32)i.Param).BuildRefType(); stack.Push(t); } break; case InstructionCode.LDLOCA : { TypeEx t = new TypeEx(TypeEx.BuildRefType(methodRepr.Locals[(Int32)i.Param])); stack.Push(t); } break; case InstructionCode.LDLOC : { stack.Push(new TypeEx(methodRepr.Locals[(Int32)i.Param])); } break; case InstructionCode.LDIND : { ProcessLdInd(i.TypeBySuffixOrParam(), stack); } break; case InstructionCode.LDC: { stack.Push(new TypeEx(i.TypeBySuffixOrParam())); } break; case InstructionCode.LDNULL: { stack.Push(new TypeEx(null));//see `Attention` at the top of the method. } break; case InstructionCode.LDFLD: { ProcessLdFld(stack, i.Param as FieldInfo,false); } break; case InstructionCode.LDFLDA: { ProcessLdFld(stack, i.Param as FieldInfo,true); } break; case InstructionCode.LDSFLD: { stack.Push(new TypeEx((i.Param as FieldInfo).FieldType)); } break; case InstructionCode.LDSFLDA: { stack.Push(TypeEx.BuildRefType((i.Param as FieldInfo).FieldType)); } break; case InstructionCode.LDELEM: { ProcessLdElem(stack, new TypeEx(i.TypeBySuffixOrParam()), false); } break; case InstructionCode.LDELEMA: { ProcessLdElem(stack, new TypeEx(i.TypeBySuffixOrParam()), true); } break; case InstructionCode.LDLEN : { ProcessLdLen(stack); } break; case InstructionCode.LDOBJ : { ProcessLdObj(stack, i.Param as Type); } break; case InstructionCode.LDSTR: { if(!(i.Param is string)) throw new VerifierException(); stack.Push(typeof(string)); } break; case InstructionCode.LDFTN: { stack.Push(new TypeEx(typeof(IntPtr))); } break; case InstructionCode.LDVIRTFTN: { TypeEx obj = stack.Pop(); MethodInfo methodInfo = i.Param as MethodInfo; if(!methodInfo.IsVirtual) throw new VerifierException(); TypeChecker.CheckAssignment(new TypeEx(methodInfo.DeclaringType , true), obj); stack.Push(typeof(IntPtr)); } break; case InstructionCode.LDTOKEN: { if(i.Param is Type) stack.Push(typeof(System.RuntimeTypeHandle)); else if(i.Param is MethodBase) stack.Push(typeof(System.RuntimeMethodHandle)); else if(i.Param is FieldInfo) stack.Push(typeof(System.RuntimeFieldHandle)); else throw new VerifierException(); } break; case InstructionCode.SIZEOF : { ProcessSizeOf(stack,i.Param as Type); } break; case InstructionCode.CLT: case InstructionCode.CGT: case InstructionCode.CEQ: { ProcessBinOp(OpType.Compare,stack); } break; case InstructionCode.BLE: case InstructionCode.BLT: case InstructionCode.BGE: case InstructionCode.BGT: case InstructionCode.BEQ: case InstructionCode.BNE: { TypeEx t1 = stack.Pop(); TypeEx t2 = stack.Pop(); Arithmetics.CheckTypes(t1,t2); ProcessBr(iNum,methodRepr,stack); stack = stack.Clone() as StackTypes; //Andrew: mb wrong, we may let equal stacks to be the same object } break; case InstructionCode.BRTRUE: case InstructionCode.BRFALSE: { ProcessBrTrueFalse(stack); ProcessBr(iNum,methodRepr,stack); stack = stack.Clone() as StackTypes; //Andrew: mb wrong, we may let equal stacks to be the same object } break; case InstructionCode.BR : { ProcessBr(iNum,methodRepr,stack); stack = null; } break; case InstructionCode.SWITCH: { ProcessSwitch(stack); ProcessSwitch(iNum,methodRepr,stack); stack = stack.Clone() as StackTypes; } break; case InstructionCode.THROW : { ProcessThrow(stack); stack = null; }break; case InstructionCode.RETHROW : { if(GetNearestBlock(methodRepr.EHClauses,iNum).type != BlockType.Catch) throw new VerifierException(); stack = null; }break; case InstructionCode.LEAVE : { BlockType blockType = GetNearestBlock(methodRepr.EHClauses,iNum).type; if(blockType != BlockType.Catch && blockType != BlockType.Try) throw new VerifierException(); ProcessLeave(iNum,methodRepr,stack); stack = null; } break; case InstructionCode.ENDFINALLY : { if(GetNearestBlock(methodRepr.EHClauses,iNum).type != BlockType.Finally) throw new VerifierException(); ProcessLeave(stack); stack = null; } break; case InstructionCode.ENDFILTER : { if(GetNearestBlock(methodRepr.EHClauses,iNum).type != BlockType.Filter) throw new VerifierException(); ProcessEndFilter(stack); stack = null; } break; case InstructionCode.NOT: { ProcessNot(stack); } break; case InstructionCode.NEG: { ProcessNeg(stack); } break; case InstructionCode.CKFINITE : { ProcessCkFinite(stack); } break; case InstructionCode.CONV: { ProcessConv(i.TypeBySuffixOrParam(), stack); } break; case InstructionCode.SUB: case InstructionCode.ADD: case InstructionCode.MUL: case InstructionCode.DIV: case InstructionCode.REM: case InstructionCode.XOR: case InstructionCode.OR: case InstructionCode.AND: { ProcessBinOp(IsFloatOperation(i) ? OpType.FloatOrInt : OpType.Int , stack); } break; case InstructionCode.SHL: case InstructionCode.SHR: { ProcessBinOp(OpType.Shift , stack); } break; case InstructionCode.CPOBJ : { ProcessCpObj(stack, i.Param as Type); } break; case InstructionCode.STARG : { ProcessSt(method.GetArgType((Int32)i.Param) , stack); } break; case InstructionCode.STLOC : { ProcessSt(new TypeEx(methodRepr.Locals[(Int32)i.Param]) , stack); } break; case InstructionCode.STIND : { ProcessStInd(i.TypeBySuffixOrParam() , stack); } break; case InstructionCode.STFLD: { ProcessStFld(stack, i.Param as FieldInfo); } break; case InstructionCode.STSFLD: { ProcessStSFld(stack, i.Param as FieldInfo); } break; case InstructionCode.STELEM: { ProcessStElem(stack, new TypeEx(i.TypeBySuffixOrParam())); } break; case InstructionCode.STOBJ : { ProcessStObj(stack, i.Param as Type); } break; case InstructionCode.RET : { if(GetNearestBlock(methodRepr.EHClauses,iNum).type != BlockType.Global) throw new VerifierException(); ProcessRet(method.GetReturnType(), stack); stack = null; } break; case InstructionCode.CALL : case InstructionCode.CALLVIRT : case InstructionCode.NEWOBJ : { //constructor may be invoked using either CALL or NEWOBJ instructions MethodBase callee = i.Param as MethodBase; if(i.Code == InstructionCode.NEWOBJ && callee.IsConstructor && IsDelegate(callee.DeclaringType)) ProcessDelegateConstruction(methodRepr,iNum,stack); else ProcessCallOrNewobj(new MethodInfoExtention(callee,i.Code == InstructionCode.CALLVIRT), stack, i.Code == InstructionCode.NEWOBJ); if(i.HasTail && methodRepr[iNum+1].Code != InstructionCode.RET) throw new VerifierException(); } break; case InstructionCode.INITOBJ : { ProcessInitObj(stack, i.Param as Type); } break; case InstructionCode.NEWARR : { ProcessNewArr(stack, i.Param as Type); } break; case InstructionCode.ISINST : case InstructionCode.CASTCLASS : { ProcessCastClass(stack, new TypeEx(i.Param as Type , true)); } break; case InstructionCode.BOX : { ProcessBox(stack, i.Param as Type); } break; case InstructionCode.UNBOX : { ProcessUnBox(stack, i.Param as Type); } break; case InstructionCode.POP : { stack.Pop(); } break; case InstructionCode.NOP : case InstructionCode.BREAK : break; default: { throw new VerifierException(); //Instruction is not supported yet... } } } return(true); } catch(VerifierException ) { FreeStacks(methodRepr); return(false); } //catch(NullReferenceException ) //Andrew: ZaLyaPa :( waiting for Sergey to patch NEWOBJ (delegate construction) //{ // FreeStacks(methodRepr); // return(false); //} }