private static MethodBodyBlock CreateBody(MethodEx methodEx) { if(!methodEx.IsVerified) return null; MethodBodyBlock body; body = Converter.Convert(methodEx); return(body); }
private static void ProcessLeave(int iNum,MethodEx method,StackTypes stack) { CheckCanLeave(method.EHClauses, iNum, (int)method[iNum].Param); ProcessLeave(stack); ProcessBranch(iNum,(int)method[iNum].Param,method,stack); }
private static void ProcessSwitch(int iNum,MethodEx method,StackTypes stack) { int[] INums = (int[])method[iNum].Param; for(int i = 0;i<INums.Length;i++) { CheckSameBlock(method.EHClauses, iNum, INums[i]); ProcessBranch(iNum,INums[i],method,stack); } }
private static void ProcessBr(int iNum,MethodEx method,StackTypes stack) { CheckSameBlock(method.EHClauses, iNum, (int)method[iNum].Param); ProcessBranch(iNum, (int)method[iNum].Param, method, stack); }
private static void ProcessBranch(int iNum,int INum,MethodEx method,StackTypes stack) { Instruction I = method[INum]; if(INum > iNum) I.SetStack(MergeStacks(I.Stack,stack)); else CheckStacks(I.Stack,stack); }
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); //} }
static private void ProcessDelegateConstruction(MethodEx method,int iNum,StackTypes stack) { if(!(IsInstanceDispatch(method,iNum) || IsVirtualDispatch(method,iNum))) throw new VerifierException(); TypeEx intPtr = stack.Pop(); MethodInfo ftn = method[iNum-1].Param as MethodInfo; ConstructorInfo ctor = method[iNum].Param as ConstructorInfo; ProcessDelegateConstruction(stack,ftn,ctor); }
static public bool IsVirtualDispatch(MethodEx body,int iNum) { Instruction i0 = body[iNum-2]; Instruction i1 = body[iNum-1]; Instruction i2 = body[iNum]; if(i2.Code != InstructionCode.NEWOBJ) return(false); if(i1.Code != InstructionCode.LDVIRTFTN) return(false); if(i0.Code != InstructionCode.DUP) return(false); return(true); }
static public bool IsInstanceDispatch(MethodEx body,int iNum) { Instruction i1 = body[iNum-1]; Instruction i2 = body[iNum]; if(i2.Code != InstructionCode.NEWOBJ) return(false); if(i1.Code != InstructionCode.LDFTN) return(false); return(true); }
private static void CheckBlockExits(MethodEx methodRepr) { foreach(EHClause c in methodRepr.EHClauses) { int handlerEnd = c.HandlerStart + c.HandlerLength - 1; int tryEnd = c.TryStart + c.TryLength - 1; if(!IsTryExit(methodRepr[tryEnd].Code)) throw new VerifierException(); if(c.Kind == EHClauseKind.FinallyHandler ? !IsFinallyExit(methodRepr[handlerEnd].Code) : !IsCatchExit(methodRepr[handlerEnd].Code) ) throw new VerifierException(); if(c.Kind == EHClauseKind.UserFilteredHandler) if(!IsFilterExit(methodRepr[c.HandlerStart - 1].Code)) throw new VerifierException(); } }
static internal void FreeStacks(MethodEx method) { foreach(Instruction i in method) i.SetStack(null); }
private static void ProcessMethod(ILGenerator generator, MethodEx methodEx, MethodBase method, MetaDataMapper mapper) { if(method.IsAbstract) return; MethodBodyBlock body = null; if(methodEx == null) throw new ExportException(); body = CreateBody(methodEx); if(body == null) throw new ExportException(); MetaDataResolver.Map(body,mapper); bool verified = CFGVerifier.Check(body); if(!verified) throw new ExportException(); Emitter.Emit(generator,body); }