/* * public static bool ClrSetTypedReference(TypedReference target, * Object value); */ ILBool _IL_TypedReference_ClrSetTypedReference(ILExecThread *_thread, ILTypedRef target, ILObject *value) { ILType *type; if(target.type == 0 || target.value == 0) { /* This is an invalid typed reference */ return 0; } type = ILClassToType(target.type); if(ILType_IsPrimitive(type) || ILType_IsValueType(type)) { if(!ILExecThreadUnbox(_thread, type, value, target.value)) { return 0; } return 1; } else if(ILTypeAssignCompatible (ILProgramItem_Image(_thread->method), (value ? ILClassToType(GetObjectClass(value)) : 0), type)) { *((ILObject **)(target.value)) = value; return 1; } else { return 0; } }
/* * Get the full size information for a class and its members. */ static void GetClassSize(ILSizeInfo *info, ILClass *classInfo) { ILImage *image = ILProgramItem_Image(classInfo); ILImplements *impl; ILClassLayout *layout; ILMember *member; int hasEvents, hasProperties; ILFieldLayout *fieldLayout; ILFieldRVA *fieldRVA; ILConstant *constant; ILUInt32 type; /* Get the size information for the class itself */ GetMetadataSizeWithAttrs(info, ILToProgramItem(classInfo)); /* Collect up size information for the interface declarations */ impl = 0; while((impl = ILClassNextImplements(classInfo, impl)) != 0) { GetMetadataSize(info, ILToProgramItem(impl)); } /* Account for class layout information */ layout = ILClassLayoutGetFromOwner(classInfo); if(layout) { GetMetadataSize(info, ILToProgramItem(layout)); } /* Account for the nested class declaration */ if(ILClass_NestedParent(classInfo) != 0) { info->meta += image->tokenSize[IL_META_TOKEN_NESTED_CLASS >> 24]; info->loadedMeta += sizeof(ILNestedInfo); }
/* * Get blob size information. */ static void GetBlobSize(ILSizeInfo *info, ILProgramItem *item, ILUInt32 offset) { ILUInt32 len; unsigned char lenbuf[IL_META_COMPRESS_MAX_SIZE]; if(ILImageGetBlob(ILProgramItem_Image(item), offset, &len)) { info->meta += len; info->meta += (unsigned long)(long)ILMetaCompressData(lenbuf, len); } }
/* * private static Assembly LoadFromName(String name, out int error, * Assembly parent); */ ILObject *_IL_AppDomain_LoadFromName(ILExecThread *thread, ILObject *appDomain, ILString *name, ILInt32 *error, ILObject *parent) { if(!IsAppDomainUnloaded(thread, (ILExecProcess *)appDomain)) { ILProgramItem *item = (ILProgramItem *)_ILClrFromObject(thread, parent); ILImage *image = ((item != 0) ? ILProgramItem_Image(item) : 0); char *str = ILStringToUTF8(thread, name); if(image && str) { int len; int loadError; ILImage *newImage; len = strlen(str); if(len > 4 && str[len - 4] == '.' && (str[len - 3] == 'd' || str[len - 3] == 'D') && (str[len - 2] == 'l' || str[len - 2] == 'L') && (str[len - 1] == 'l' || str[len - 1] == 'L')) { /* Remove ".dll", to get the assembly name */ str[len - 4] = '\0'; } loadError = ILImageLoadAssembly(str, ((ILExecProcess *)appDomain)->context, image, &newImage); if(loadError == 0) { return ImageToAssembly(thread, newImage); } else if(loadError == -1) { *error = LoadError_FileNotFound; return 0; } else if(loadError == IL_LOADERR_MEMORY) { ILExecThreadThrowOutOfMemory(thread); return 0; } else { *error = LoadError_BadImage; return 0; } } else { *error = LoadError_FileNotFound; return 0; } } return 0; }
/* * Inner version of "_ILConvertMethod", which detects the type of * exception to throw, but does not throw it. * This method is invoked only during on demand compilation of a jitted IL method * and is secured through libjit. */ static unsigned char *ConvertMethod(ILExecThread *thread, ILMethod *method, int *errorCode, const char **errorInfo) { ILMethodCode code; ILCoder *coder = thread->process->coder; unsigned char *start; #ifndef IL_CONFIG_VARARGS /* Vararg methods are not supported */ if((ILMethod_CallConv(method) & IL_META_CALLCONV_MASK) == IL_META_CALLCONV_VARARG) { *errorCode = IL_CONVERT_NOT_IMPLEMENTED; return 0; } #endif /* Get the method code */ if(!ILMethodGetCode(method, &code)) { code.code = 0; } /* The conversion is different depending upon whether the method is written in IL or not */ if(code.code) { /* Use the bytecode verifier and coder to convert the method */ if(!_ILVerify(coder, &start, method, &code, ILImageIsSecure(ILProgramItem_Image(method)), thread)) { *errorCode = IL_CONVERT_VERIFY_FAILED; return 0; } } else { /* All other cases should be handled in the jit coder. */ *errorCode = IL_CONVERT_OUT_OF_MEMORY; return 0; } /* The method is converted now */ *errorCode = IL_CONVERT_OK; return (unsigned char *)1; }
int _ILVerify(ILCoder *coder, unsigned char **start, ILMethod *method, ILMethodCode *code, int unsafeAllowed, ILExecThread *thread) { TempAllocator allocator; ILCoderExceptions coderExceptions; ILCoderExceptionBlock *coderException; ILCoderExceptionBlock *currentCoderException; int numHandlers; int extraCodeLen; unsigned long *jumpMask; unsigned char *pc; ILUInt32 len; int result; unsigned opcode; ILUInt32 insnSize; int isStatic, isSynchronized; int insnType; ILUInt32 offset = 0; ILEngineStackItem *stack; ILUInt32 stackSize; #ifdef IL_VERIFY_DEBUG const ILOpcodeInfo *insn = 0; #define MAIN_OPCODE_TABLE ILMainOpcodeTable #define PREFIX_OPCODE_TABLE ILPrefixOpcodeTable #else const ILOpcodeSmallInfo *insn = 0; #define MAIN_OPCODE_TABLE ILMainOpcodeSmallTable #define PREFIX_OPCODE_TABLE ILPrefixOpcodeSmallTable #endif ILType *signature; ILType *type; ILUInt32 numArgs; ILUInt32 numLocals; ILType *localVars; int lastWasJump; ILException *exceptions; ILException *exception; int hasRethrow; int tryInlineType; int coderFlags; unsigned int tryInlineOpcode; unsigned char *tryInlinePc; ILUInt32 optimizationLevel; ILBool lastInsnWasPrefix; ILCoderPrefixInfo prefixInfo; #ifdef IL_CONFIG_DEBUG_LINES int haveDebug = ILDebugPresent(ILProgramItem_Image(method)); #else int haveDebug = 0; #endif /* Include local variables that are required by the include files */ #define IL_VERIFY_LOCALS #include "verify_var.c" #include "verify_const.c" #include "verify_arith.c" #include "verify_conv.c" #include "verify_stack.c" #include "verify_ptr.c" #include "verify_obj.c" #include "verify_call.c" #include "verify_branch.c" #include "verify_except.c" #include "verify_ann.c" #undef IL_VERIFY_LOCALS /* Get the exception list */ if(!ILMethodGetExceptions(method, code, &exceptions)) { return 0; } /* Clear the exception management structure */ ILMemZero(&coderExceptions, sizeof(ILCoderExceptions)); /* * Initialize the size of the additional code generated for * synchronization. */ extraCodeLen = 0; /* And set the last label to the code length */ coderExceptions.lastLabel = code->codeLen; /* Initialize the memory allocator that is used for temporary allocation during bytecode verification */ ILMemZero(allocator.buffer, sizeof(allocator.buffer)); allocator.posn = 0; allocator.overflow = 0; coderFlags = ILCoderGetFlags(coder); optimizationLevel = ILCoderGetOptimizationLevel(coder); isStatic = ILMethod_IsStatic(method); isSynchronized = ILMethod_IsSynchronized(method); result = 0; if(exceptions || isSynchronized) { numHandlers = 0; exception = exceptions; while(exception) { ++numHandlers; exception = exception->next; } if(isSynchronized) { /* We'll need an extra try and fault block for synchronization */ ++numHandlers; } /* * Allocate memory for the exception infos. * There might be create 3 coder exception blocks for one * IL exception. * So we allocate memory for the worst case here. */ coderExceptions.blocks = ILCalloc(sizeof(ILCoderExceptionBlock), numHandlers * 3); if(!coderExceptions.blocks) { return 0; } /* Now setup the exception structure */ exception = exceptions; while(exception) { switch(_ILCoderAddExceptionBlock(&coderExceptions, method, exception)) { case IL_CODER_BRANCH_ERR: { VERIFY_BRANCH_ERROR(); } break; case IL_CODER_TYPE_ERR: { VERIFY_TYPE_ERROR(); } break; } exception = exception->next; } /* * Now check if all exception block limits are in the code. */ len = code->codeLen; coderException = coderExceptions.firstBlock; if(coderException) { /* * Check the start offset of the first exception block in the * lowest list. */ if(coderException->startOffset > len) { VERIFY_BRANCH_ERROR(); } /* * Look for the last exception block in the lowest list. */ while(coderException->nextNested) { coderException = coderException->nextNested; } /* * Check the end offset of the last exception block in the * lowest list. * All other exceprion blocks end at or before this offset. */ if(coderException->endOffset > len) { VERIFY_BRANCH_ERROR(); } } if(isSynchronized) { /* * Wrap the whole function in a try block with a fault handler. */ ILException tempException; tempException.flags = IL_META_EXCEPTION_FAULT; tempException.tryOffset = 0; tempException.tryLength = len; tempException.handlerOffset = len; tempException.handlerLength = 1; tempException.extraArg = 0; tempException.userData = 0; tempException.ptrUserData = 0; tempException.next = 0; switch(_ILCoderAddExceptionBlock(&coderExceptions, method, &tempException)) { case IL_CODER_BRANCH_ERR: { VERIFY_BRANCH_ERROR(); } break; case IL_CODER_TYPE_ERR: { VERIFY_TYPE_ERROR(); } break; } extraCodeLen = 2; } } restart: result = 0; labelList = 0; hasRethrow = 0; /* Reset the prefix information */ ILMemZero(&prefixInfo, sizeof(ILCoderPrefixInfo)); /* Allocate the jump target mask */ jumpMask = (unsigned long *)TempAllocate (&allocator, BYTES_FOR_MASK(code->codeLen + extraCodeLen)); if(!jumpMask) { VERIFY_MEMORY_ERROR(); } /* Scan the code looking for all jump targets, and validating that all instructions are more or less valid */ pc = code->code; len = code->codeLen; while(len > 0) { /* Mark this position in the jump mask as an instruction start */ MarkInsnStart(jumpMask, (ILUInt32)(pc - (unsigned char *)(code->code))); /* Fetch the instruction size and type */ opcode = (unsigned)(pc[0]); if(opcode != IL_OP_PREFIX) { /* Regular opcode */ insnSize = (ILUInt32)(MAIN_OPCODE_TABLE[opcode].size); if(len < insnSize) { VERIFY_TRUNCATED(); } insnType = MAIN_OPCODE_TABLE[opcode].args; } else { /* Prefixed opcode */ if(len < 2) { VERIFY_TRUNCATED(); } opcode = (unsigned)(pc[1]); insnSize = (ILUInt32)(PREFIX_OPCODE_TABLE[opcode].size); if(len < insnSize) { VERIFY_TRUNCATED(); } insnType = PREFIX_OPCODE_TABLE[opcode].args; if(opcode == IL_PREFIX_OP_RETHROW) { hasRethrow = 1; } opcode += IL_OP_PREFIX; } /* Determine how to handle this type of instruction */ switch(insnType) { case IL_OPCODE_ARGS_SHORT_JUMP: { /* 8-bit jump offset */ offset = (ILUInt32)((pc + insnSize) - (unsigned char *)(code->code)) + (ILUInt32)(ILInt32)(ILInt8)(pc[1]); if(offset >= code->codeLen) { VERIFY_BRANCH_ERROR(); } MarkJumpTarget(jumpMask, offset); } break; case IL_OPCODE_ARGS_LONG_JUMP: { /* 32-bit jump offset */ offset = (ILUInt32)((pc + insnSize) - (unsigned char *)(code->code)) + (ILUInt32)(IL_READ_INT32(pc + 1)); if(offset >= code->codeLen) { VERIFY_BRANCH_ERROR(); } MarkJumpTarget(jumpMask, offset); } break; case IL_OPCODE_ARGS_SWITCH: { /* Switch statement */ if(len < 5) { VERIFY_TRUNCATED(); } numArgs = IL_READ_UINT32(pc + 1); insnSize = 5 + numArgs * 4; if(numArgs >= 0x20000000 || len < insnSize) { VERIFY_TRUNCATED(); } while(numArgs > 0) { --numArgs; offset = (ILUInt32)((pc + insnSize) - (unsigned char *)(code->code)) + (ILUInt32)(IL_READ_INT32(pc + 5 + numArgs * 4)); if(offset >= code->codeLen) { VERIFY_BRANCH_ERROR(); } MarkJumpTarget(jumpMask, offset); } } break; case IL_OPCODE_ARGS_ANN_DATA: { /* Variable-length annotation data */ if(opcode == IL_OP_ANN_DATA_S) { if(len < 2) { VERIFY_TRUNCATED(); } insnSize = (((ILUInt32)(pc[1])) & 0xFF) + 2; if(len < insnSize) { VERIFY_TRUNCATED(); } } else { if(len < 6) { VERIFY_TRUNCATED(); } insnSize = (IL_READ_UINT32(pc + 2) + 6); if(len < insnSize) { VERIFY_TRUNCATED(); } } } break; case IL_OPCODE_ARGS_ANN_PHI: { /* Variable-length annotation data */ if(len < 3) { VERIFY_TRUNCATED(); } insnSize = ((ILUInt32)IL_READ_UINT16(pc + 1)) * 2 + 3; if(len < insnSize) { VERIFY_TRUNCATED(); } } break; case IL_OPCODE_ARGS_INVALID: { VERIFY_INSN_ERROR(); } break; default: break; } /* Advance to the next instruction */ pc += insnSize; len -= insnSize; } /* Mark the start and end of exception blocks as special jump targets */ numHandlers = 0; while(numHandlers < coderExceptions.numBlocks) { coderException = &(coderExceptions.blocks[numHandlers]); MarkJumpTarget(jumpMask, coderException->startOffset); MarkSpecialJumpTarget(jumpMask, coderException->startOffset); MarkJumpTarget(jumpMask, coderException->endOffset); MarkSpecialJumpTarget(jumpMask, coderException->endOffset); switch(coderException->flags) { case IL_CODER_HANDLER_TYPE_TRY: { /* Nothing to do here */ } break; case IL_CODER_HANDLER_TYPE_CATCH: { /* This is a typed catch block */ classInfo = coderException->un.handlerBlock.exceptionClass; /* * This block will be called with an object of the given * type on the stack. */ SET_TARGET_STACK(coderException->startOffset, classInfo); } break; case IL_CODER_HANDLER_TYPE_FINALLY: case IL_CODER_HANDLER_TYPE_FAULT: { /* This is a finally or fault clause */ /* The clause will be called with nothing on the stack */ SET_TARGET_STACK_EMPTY(coderException->startOffset); } break; case IL_CODER_HANDLER_TYPE_FILTER: case IL_CODER_HANDLER_TYPE_FILTEREDCATCH: { /* This is an exception filter or the corresponding catch block */ /* * The block will be called with an object on the stack, * so record that in the label list for later */ classInfo = ILClassResolveSystem(ILProgramItem_Image(method), 0, "Object", "System"); if(!classInfo) { /* Ran out of memory trying to create "System.Object" */ VERIFY_MEMORY_ERROR(); } SET_TARGET_STACK(coderException->startOffset, classInfo); } break; } ++numHandlers; } /* Make sure that all jump targets are instruction starts */ len = code->codeLen; while(len > 0) { --len; if(IsJumpTarget(jumpMask, len) && !IsInsnStart(jumpMask, len)) { VERIFY_BRANCH_ERROR(); } } /* Create the stack. We need two extra "slop" items to allow for stack expansion during object construction. See "verify_call.c" for further details */ stack = (ILEngineStackItem *)TempAllocate (&allocator, sizeof(ILEngineStackItem) * (code->maxStack + 2)); if(!stack) { VERIFY_MEMORY_ERROR(); } stackSize = 0; /* Get the method signature, plus the number of arguments and locals */ signature = ILMethod_Signature(method); numArgs = ILTypeNumParams(signature); if(ILType_HasThis(signature)) { /* Account for the "this" argument */ ++numArgs; } if(code->localVarSig) { localVars = ILStandAloneSigGetType(code->localVarSig); numLocals = ILTypeNumLocals(localVars); if(ILTypeNeedsInstantiation(localVars) && ILMember_IsGenericInstance(method)) { ILType *classTypeArgs = ILMethodGetClassTypeArguments(method); ILType *methodTypeArgs = ILMethodGetMethodTypeArguments(method); localVars = ILTypeInstantiate(ILImageToContext(ILProgramItem_Image(method)), localVars, classTypeArgs, methodTypeArgs); } } else { localVars = 0; numLocals = 0; } /* Set up the coder to process the method */ if(!ILCoderSetup(coder, start, method, code, &coderExceptions, hasRethrow)) { VERIFY_MEMORY_ERROR(); } if((coderFlags & IL_CODER_FLAG_METHOD_PROFILE) != 0) { ILCoderProfileStart(coder); } /* Verify the code */ pc = code->code; len = code->codeLen; lastWasJump = 0; /* If the method is synchronized then generate the Monitor.Enter call */ if (isSynchronized) { PUSH_SYNC_OBJECT(); ILCoderCallInlineable(coder, IL_INLINEMETHOD_MONITOR_ENTER, 0, 0); } lastInsnWasPrefix = 0; while(len > 0) { /* Fetch the instruction information block */ offset = (ILUInt32)(pc - (unsigned char *)(code->code)); opcode = pc[0]; if(opcode != IL_OP_PREFIX) { insn = &(MAIN_OPCODE_TABLE[opcode]); } else { opcode = pc[1]; insn = &(PREFIX_OPCODE_TABLE[opcode]); opcode += IL_OP_PREFIX; } insnSize = (ILUInt32)(insn->size); /* Is this a jump target? */ if(IsJumpTarget(jumpMask, offset)) { /* Validate the stack information */ VALIDATE_TARGET_STACK(offset); /* Notify the coder of a label at this position */ #ifdef IL_USE_JIT ILCoderStackRefresh(coder, stack, stackSize); ILCoderLabel(coder, offset); #else ILCoderLabel(coder, offset); ILCoderStackRefresh(coder, stack, stackSize); #endif } else if(lastWasJump) { /* An instruction just after an opcode that jumps to somewhere else in the flow of control. As this isn't a jump target, we assume that the stack must be empty at this point. The validate code will ensure that this is checked */ VALIDATE_TARGET_STACK(offset); /* Reset the coder's notion of the stack to empty */ ILCoderStackRefresh(coder, stack, stackSize); } /* Mark this offset if the method has debug information */ if(haveDebug) { ILCoderMarkBytecode(coder, offset); } /* Validate the stack height changes */ if(stackSize < ((ILUInt32)(insn->popped)) || (stackSize - ((ILUInt32)(insn->popped)) + ((ILUInt32)(insn->pushed))) > code->maxStack) { VERIFY_STACK_ERROR(); } /* * Check if all prefix flags are zero, otherwise an invalid prefix * was used for the last instruction. */ if(!lastInsnWasPrefix) { if((prefixInfo.prefixFlags != 0) || (prefixInfo.noFlags != 0)) { VERIFY_PREFIX_ERROR(); } } /* Verify the instruction */ lastWasJump = 0; lastInsnWasPrefix = 0; switch(opcode) { case IL_OP_NOP: break; /* IL breakpoints are ignored - the coder inserts its own breakpoint handlers where required */ case IL_OP_BREAK: break; #define IL_VERIFY_CODE #include "verify_var.c" #include "verify_const.c" #include "verify_arith.c" #include "verify_conv.c" #include "verify_stack.c" #include "verify_ptr.c" #include "verify_obj.c" #include "verify_branch.c" #include "verify_call.c" #include "verify_except.c" #include "verify_ann.c" #undef IL_VERIFY_CODE } /* Advance to the next instruction */ pc += insnSize; len -= insnSize; } /* If the last instruction was not a jump, then the code may fall off the end of the method */ if(!lastWasJump) { VERIFY_INSN_ERROR(); } /* * Generate the code for the fault block for synchronization. */ if(isSynchronized) { coderException = _ILCoderFindExceptionBlock(&coderExceptions, code->codeLen); /* * This check is for catching bugs. */ if(!coderException || ((coderException->flags & IL_CODER_HANDLER_TYPE_FINALLY) == 0)) { VERIFY_BRANCH_ERROR(); } /* * Insert the start label for the fault handler. */ ILCoderLabel(coder, code->codeLen); /* * Call the Monitor.Exit method. */ PUSH_SYNC_OBJECT(); ILCoderCallInlineable(coder, IL_INLINEMETHOD_MONITOR_EXIT, 0, 0); /* * Leave the fault block. */ ILCoderRetFromFinally(coder); /* * Insert the end label for the fault handler. */ ILCoderLabel(coder, code->codeLen + 1); } /* Mark the end of the method */ ILCoderMarkEnd(coder); /* Output the exception handler table, if necessary */ if(coderExceptions.numBlocks > 0) { ILCoderOutputExceptionTable(coder, &coderExceptions); } /* Finish processing using the coder */ result = ILCoderFinish(coder); /* Do we need to restart due to cache exhaustion in the coder? */ if(result == IL_CODER_END_RESTART) { TempAllocatorDestroy(&allocator); /* Reinitialize the memory allocator that is used for temporary allocation during bytecode verification */ ILMemZero(allocator.buffer, sizeof(allocator.buffer)); allocator.posn = 0; allocator.overflow = 0; /* * Reset the userdata in the exception blocks. */ numHandlers = 0; while(numHandlers < coderExceptions.numBlocks) { coderException = &(coderExceptions.blocks[numHandlers]); coderException->userData = 0; coderException->ptrUserData = 0; ++numHandlers; } goto restart; } #ifdef IL_VERIFY_DEBUG else if(result == IL_CODER_END_TOO_BIG) { ILMethodCode code; ILMethodGetCode(method,&code); fprintf(stderr, "%s::%s - method is too big to be converted (%d%s bytes)\n", ILClass_Name(ILMethod_Owner(method)), ILMethod_Name(method), code.codeLen, (code.moreSections != 0) ? "+" : ""); } #endif result = (result == IL_CODER_END_OK); /* Clean up and exit */ cleanup: TempAllocatorDestroy(&allocator); if(exceptions) { ILMethodFreeExceptions(exceptions); } if(coderExceptions.blocks) { ILFree(coderExceptions.blocks); } return result; }
/* * Determine if a stack item is assignment-compatible with * a particular memory slot (argument, local, field, etc). */ static int AssignCompatible(ILMethod *method, ILEngineStackItem *item, ILType *type, int unsafeAllowed) { ILImage *image; ILClass *classInfo; ILClass *classInfo2; ILMethod *methodRef; ILType *objType; /* Check for safe and unsafe pointer assignments */ if(item->engineType == ILEngineType_I) { methodRef = MethodRefToMethod(item->typeInfo); if(methodRef) { /* Assigning a method reference, obtained via "ldftn" or "ldvirtftn", to a method pointer destination */ if(ILTypeIdentical(ILMethod_Signature(methodRef), type)) { return 1; } } else if(item->typeInfo != 0 && ILType_IsComplex(item->typeInfo)) { /* May be trying to assign a method pointer to a method type */ if(ILType_IsMethod(item->typeInfo)) { if(ILTypeIdentical(item->typeInfo, type)) { return 1; } } } if(unsafeAllowed) { if(type != 0 && ILType_IsComplex(type)) { if((ILType_Kind(type) & IL_TYPE_COMPLEX_METHOD) != 0 || ILType_Kind(type) == IL_TYPE_COMPLEX_PTR) { return 1; } } } } /* Check for regular assignments */ if(item->engineType == ILEngineType_I4 || item->engineType == ILEngineType_I) { type = ILTypeGetEnumType(type); switch((unsigned long)type) { case (unsigned long)ILType_Boolean: case (unsigned long)ILType_Int8: case (unsigned long)ILType_UInt8: case (unsigned long)ILType_Int16: case (unsigned long)ILType_UInt16: case (unsigned long)ILType_Char: case (unsigned long)ILType_Int32: case (unsigned long)ILType_UInt32: case (unsigned long)ILType_Int: case (unsigned long)ILType_UInt: return 1; default: break; } if(!unsafeAllowed) { return 0; } /* Allow a native int to be assigned to a complex type */ if(type != 0 && ILType_IsComplex(type) && item->engineType == ILEngineType_I) { if(ILType_Kind(type) == IL_TYPE_COMPLEX_PTR || ILType_Kind(type) == IL_TYPE_COMPLEX_BYREF) { return 1; } } return 0; } else if(item->engineType == ILEngineType_I8) { type = ILTypeGetEnumType(type); return (type == ILType_Int64 || type == ILType_UInt64); } else if(item->engineType == ILEngineType_F) { return (type == ILType_Float32 || type == ILType_Float64 || type == ILType_Float); } else if(item->engineType == ILEngineType_O) { if(!(item->typeInfo)) { /* A "null" constant was pushed, which is compatible with any object reference type */ return IsObjectRef(type); } if(!IsObjectRef(type) || !IsObjectRef(item->typeInfo)) { /* Both types must be object references */ return 0; } /* make a copy to avoid unecessary complications */ objType=item->typeInfo; if(ILType_IsArray(type) && ILType_IsArray(objType) && (ILTypeGetRank(type) == ILTypeGetRank(objType))) { objType=ILTypeGetElemType(objType); type=ILTypeGetElemType(type); } image = ILProgramItem_Image(method); classInfo = ILClassResolve(ILClassFromType(image, 0, type, 0)); classInfo2 = ILClassResolve (ILClassFromType(image, 0, objType, 0)); if(classInfo && classInfo2) { /* Is the type a regular class or an interface? */ if(!ILClass_IsInterface(classInfo)) { /* Regular class: the value must inherit from the type */ if(ILClassInheritsFrom(classInfo2, classInfo)) { return 1; } /* If "classInfo2" is an interface, then the conversion is OK if "type" is "System.Object", because all interfaces inherit from "System.Object", even though the metadata doesn't explicitly say so */ if(ILClass_IsInterface(classInfo2)) { return ILTypeIsObjectClass(type); } /* The conversion is not OK */ return 0; } else { /* Interface which the value must implement or inherit from */ return ILClassImplements(classInfo2, classInfo) || ILClassInheritsFrom(classInfo2, classInfo); } } else { return 0; } } else if(item->engineType == ILEngineType_MV) { /* Can only assign managed values to an exact type destination */ return ILTypeIdentical(item->typeInfo, type); } else if(item->engineType == ILEngineType_TypedRef) { /* The type must be "typedref" */ return (type == ILType_TypedRef); } else if(item->engineType == ILEngineType_M || item->engineType == ILEngineType_T) { /* Cannot assign managed pointers to variables or fields, unless we are in "unsafe" mode */ if(!unsafeAllowed) { return 0; } /* Allow an assignment to any pointer, reference, or native destination, regardless of type. This allows C/C++ code to arbitrarily cast pointers via assignment */ if(type != 0 && ILType_IsComplex(type)) { if(ILType_Kind(type) == IL_TYPE_COMPLEX_PTR || ILType_Kind(type) == IL_TYPE_COMPLEX_BYREF || (ILType_Kind(type) & IL_TYPE_COMPLEX_METHOD) != 0) { return 1; } } else if(type == ILType_Int || type == ILType_UInt) { return 1; } return 0; } else { /* Invalid type: never assignment-compatible with anything */ return 0; } }
/* * Get the metadata size information for a program item, * both on-disk and in-memory. */ static void GetMetadataSize(ILSizeInfo *info, ILProgramItem *item) { ILImage *image = ILProgramItem_Image(item); if(!item) { return; } info->meta += image->tokenSize[ILProgramItem_Token(item) >> 24]; switch(ILProgramItem_Token(item) & IL_META_TOKEN_MASK) { case IL_META_TOKEN_MODULE: GetStringSize(info, ILModule_Name((ILModule *)item)); info->meta += 16; /* GUID size */ info->loadedMeta += sizeof(ILModule); break; case IL_META_TOKEN_MODULE_REF: GetStringSize(info, ILModule_Name((ILModule *)item)); info->loadedMeta += sizeof(ILModule); break; case IL_META_TOKEN_TYPE_REF: info->loadedMeta += sizeof(ILClass); info->loadedMeta += sizeof(ILProgramItemLink); GetClassNameSize(info, (ILClass *)item); break; case IL_META_TOKEN_TYPE_DEF: info->loadedMeta += sizeof(ILClass); GetClassNameSize(info, (ILClass *)item); break; case IL_META_TOKEN_FIELD_DEF: info->loadedMeta += sizeof(ILField); GetStringSize(info, ILMember_Name(item)); GetBlobSize(info, item, ((ILMember *)item)->signatureBlob); GetTypeSize(info, ILMember_Signature(item)); break; case IL_META_TOKEN_METHOD_DEF: info->loadedMeta += sizeof(ILMethod); GetStringSize(info, ILMember_Name(item)); GetBlobSize(info, item, ((ILMember *)item)->signatureBlob); GetTypeSize(info, ILMember_Signature(item)); break; case IL_META_TOKEN_PARAM_DEF: info->loadedMeta += sizeof(ILParameter); GetStringSize(info, ILParameter_Name((ILParameter *)item)); break; case IL_META_TOKEN_INTERFACE_IMPL: info->loadedMeta += sizeof(ILImplements); break; case IL_META_TOKEN_MEMBER_REF: if(ILMemberGetKind((ILMember *)item) == IL_META_MEMBERKIND_METHOD) { info->loadedMeta += sizeof(ILMethod); } else { info->loadedMeta += sizeof(ILField); } info->loadedMeta += sizeof(ILProgramItemLink); GetStringSize(info, ILMember_Name(item)); GetBlobSize(info, item, ((ILMember *)item)->signatureBlob); GetTypeSize(info, ILMember_Signature(item)); break; case IL_META_TOKEN_CONSTANT: info->loadedMeta += sizeof(ILConstant); GetBlobSize(info, item, ((ILConstant *)item)->value); break; case IL_META_TOKEN_CUSTOM_ATTRIBUTE: info->loadedMeta += sizeof(ILAttribute); GetBlobSize(info, item, ((ILAttribute *)item)->value); break; case IL_META_TOKEN_FIELD_MARSHAL: info->loadedMeta += sizeof(ILFieldMarshal); GetBlobSize(info, item, ((ILFieldMarshal *)item)->type); break; case IL_META_TOKEN_DECL_SECURITY: info->loadedMeta += sizeof(ILDeclSecurity); GetBlobSize(info, item, ((ILDeclSecurity *)item)->blob); break; case IL_META_TOKEN_CLASS_LAYOUT: info->loadedMeta += sizeof(ILClassLayout); break; case IL_META_TOKEN_FIELD_LAYOUT: info->loadedMeta += sizeof(ILFieldLayout); break; case IL_META_TOKEN_STAND_ALONE_SIG: info->loadedMeta += sizeof(ILStandAloneSig); GetBlobSize(info, item, ((ILStandAloneSig *)item)->typeBlob); GetTypeSize(info, ((ILStandAloneSig *)item)->type); break; case IL_META_TOKEN_EVENT_MAP: info->loadedMeta += sizeof(ILEventMap); break; case IL_META_TOKEN_EVENT: info->loadedMeta += sizeof(ILEvent); break; case IL_META_TOKEN_PROPERTY_MAP: info->loadedMeta += sizeof(ILPropertyMap); break; case IL_META_TOKEN_PROPERTY: info->loadedMeta += sizeof(ILProperty); break; case IL_META_TOKEN_METHOD_SEMANTICS: info->loadedMeta += sizeof(ILMethodSem); break; case IL_META_TOKEN_METHOD_IMPL: info->loadedMeta += sizeof(ILOverride); break; case IL_META_TOKEN_TYPE_SPEC: info->loadedMeta += sizeof(ILTypeSpec); GetBlobSize(info, item, ((ILTypeSpec *)item)->typeBlob); GetTypeSize(info, ((ILTypeSpec *)item)->type); break; case IL_META_TOKEN_IMPL_MAP: info->loadedMeta += sizeof(ILPInvoke); GetStringSize(info, ILPInvoke_Alias((ILPInvoke *)item)); break; case IL_META_TOKEN_FIELD_RVA: info->loadedMeta += sizeof(ILFieldRVA); break; case IL_META_TOKEN_ASSEMBLY: info->loadedMeta += sizeof(ILAssembly); GetStringSize(info, ILAssembly_Name((ILAssembly *)item)); GetStringSize(info, ILAssembly_Locale((ILAssembly *)item)); break; case IL_META_TOKEN_ASSEMBLY_REF: info->loadedMeta += sizeof(ILAssembly); info->loadedMeta += sizeof(ILProgramItemLink); GetStringSize(info, ILAssembly_Name((ILAssembly *)item)); GetStringSize(info, ILAssembly_Locale((ILAssembly *)item)); break; case IL_META_TOKEN_PROCESSOR_DEF: case IL_META_TOKEN_PROCESSOR_REF: info->loadedMeta += sizeof(ILProcessorInfo); break; case IL_META_TOKEN_OS_DEF: case IL_META_TOKEN_OS_REF: info->loadedMeta += sizeof(ILOSInfo); break; case IL_META_TOKEN_FILE: info->loadedMeta += sizeof(ILFileDecl); GetStringSize(info, ILFileDecl_Name((ILFileDecl *)item)); GetBlobSize(info, item, ((ILFileDecl *)item)->hash); break; case IL_META_TOKEN_EXPORTED_TYPE: info->loadedMeta += sizeof(ILExportedType); info->loadedMeta += sizeof(ILProgramItemLink); GetClassNameSize(info, (ILClass *)item); break; case IL_META_TOKEN_MANIFEST_RESOURCE: info->loadedMeta += sizeof(ILManifestRes); GetStringSize(info, ILManifestRes_Name((ILManifestRes *)item)); break; case IL_META_TOKEN_NESTED_CLASS: info->loadedMeta += sizeof(ILNestedInfo); break; case IL_META_TOKEN_GENERIC_PAR: info->loadedMeta += sizeof(ILGenericPar); GetStringSize(info, ILGenericPar_Name((ILGenericPar *)item)); break; case IL_META_TOKEN_METHOD_SPEC: info->loadedMeta += sizeof(ILMethodSpec); GetBlobSize(info, item, ((ILMethodSpec *)item)->typeBlob); GetTypeSize(info, ((ILMethodSpec *)item)->type); break; } }
/* * Inner version of "_ILConvertMethod", which detects the type of * exception to throw, but does not throw it. */ static unsigned char *ConvertMethod(ILExecThread *thread, ILMethod *method, int *errorCode, const char **errorInfo) { ILMethodCode code; ILPInvoke *pinv; ILCoder *coder = thread->process->coder; unsigned char *start; void *cif; void *ctorcif; int isConstructor; #ifdef IL_CONFIG_PINVOKE ILModule *module; const char *name; void *moduleHandle; #endif int result; ILInternalInfo fnInfo; ILInternalInfo ctorfnInfo; /* We need the metadata write lock */ METADATA_WRLOCK(thread); /* Handle locked methods while cctors are executed. */ if((start = (unsigned char *)ILCoderHandleLockedMethod(coder, method))) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_OK; return start; } /* Is the method already converted? */ if((start = (unsigned char *)(method->userData)) != 0) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_OK; return start; } #ifndef IL_CONFIG_VARARGS /* Vararg methods are not supported */ if((ILMethod_CallConv(method) & IL_META_CALLCONV_MASK) == IL_META_CALLCONV_VARARG) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_NOT_IMPLEMENTED; return 0; } #endif /* Make sure that we can lay out the method's class */ if(!_ILLayoutClass(_ILExecThreadProcess(thread), ILMethod_Owner(method))) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_TYPE_INIT; return 0; } /* Get the method code */ if(!ILMethodGetCode(method, &code)) { code.code = 0; } /* The conversion is different depending upon whether the method is written in IL or not */ if(code.code) { /* Use the bytecode verifier and coder to convert the method */ if(!_ILVerify(coder, &start, method, &code, ILImageIsSecure(ILProgramItem_Image(method)), thread)) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_VERIFY_FAILED; return 0; } } else { /* This is a "PInvoke", "internalcall", or "runtime" method */ pinv = ILPInvokeFind(method); fnInfo.func = 0; fnInfo.marshal = 0; ctorfnInfo.func = 0; ctorfnInfo.marshal = 0; isConstructor = ILMethod_IsConstructor(method); switch(method->implementAttrs & (IL_META_METHODIMPL_CODE_TYPE_MASK | IL_META_METHODIMPL_INTERNAL_CALL | IL_META_METHODIMPL_JAVA)) { case IL_META_METHODIMPL_IL: case IL_META_METHODIMPL_OPTIL: { /* If we don't have a PInvoke record, then we don't know what to map this method call to */ if(!pinv) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_ENTRY_POINT; return 0; } #ifdef IL_CONFIG_PINVOKE /* Find the module for the PInvoke record */ module = ILPInvoke_Module(pinv); if(!module) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_ENTRY_POINT; return 0; } name = ILModule_Name(module); if(!name || *name == '\0') { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_ENTRY_POINT; return 0; } moduleHandle = LocateExternalModule (thread->process, name, pinv); if(!moduleHandle) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_DLL_NOT_FOUND; *errorInfo = name; return 0; } /* Get the name of the function within the module */ name = ILPInvoke_Alias(pinv); if(!name || *name == '\0') { name = ILMethod_Name(method); } #ifdef IL_WIN32_PLATFORM if(!(pinv->member.attributes & IL_META_PINVOKE_NO_MANGLE)) { /* We have to append an A or W to the function */ /* name depending on the characterset used. */ /* On Windows we have only either Ansi or Utf16 */ int nameLength = strlen(name); ILUInt32 charSetUsed = ILPInvokeGetCharSet(pinv, method); char newName[nameLength + 2]; strcpy(newName, name); if(charSetUsed == IL_META_MARSHAL_UTF16_STRING) { newName[nameLength] = 'W'; } else { newName[nameLength] = 'A'; } newName[nameLength + 1] = '\0'; /* Look up the method within the module */ fnInfo.func = ILDynLibraryGetSymbol(moduleHandle, newName); } if(!fnInfo.func) { /* Look up the method within the module */ fnInfo.func = ILDynLibraryGetSymbol(moduleHandle, name); } #else /* !IL_WIN32_PLATFORM */ /* Look up the method within the module */ fnInfo.func = ILDynLibraryGetSymbol(moduleHandle, name); #endif /* !IL_WIN32_PLATFORM */ #else /* !IL_CONFIG_PINVOKE */ METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_NOT_IMPLEMENTED; return 0; #endif /* IL_CONFIG_PINVOKE */ } break; case IL_META_METHODIMPL_RUNTIME: case IL_META_METHODIMPL_IL | IL_META_METHODIMPL_INTERNAL_CALL: { /* "internalcall" and "runtime" methods must not have PInvoke records associated with them */ if(pinv) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_VERIFY_FAILED; return 0; } /* Look up the internalcall function details */ if(!_ILFindInternalCall(ILExecThreadGetProcess(thread), method, 0, &fnInfo)) { if(isConstructor) { if(!_ILFindInternalCall(ILExecThreadGetProcess(thread), method, 1, &ctorfnInfo)) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_NOT_IMPLEMENTED; return 0; } } else { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_NOT_IMPLEMENTED; return 0; } } else if(isConstructor) { _ILFindInternalCall(ILExecThreadGetProcess(thread), method, 1, &ctorfnInfo); } } break; default: { /* No idea how to invoke this method */ METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_VERIFY_FAILED; return 0; } /* Not reached */ } /* Bail out if we did not find the underlying native method */ if(!(fnInfo.func) && !(ctorfnInfo.func)) { METADATA_UNLOCK(thread); if(pinv) *errorCode = IL_CONVERT_ENTRY_POINT; else *errorCode = IL_CONVERT_NOT_IMPLEMENTED; return 0; } #if defined(HAVE_LIBFFI) /* Generate a "cif" structure to handle the native call details */ if(fnInfo.func) { /* Make the "cif" structure for the normal method entry */ cif = _ILMakeCifForMethod(_ILExecThreadProcess(thread), method, (pinv == 0)); if(!cif) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_OUT_OF_MEMORY; return 0; } } else { cif = 0; } if(ctorfnInfo.func) { /* Make the "cif" structure for the allocating constructor */ ctorcif = _ILMakeCifForConstructor(_ILExecThreadProcess(thread), method, (pinv == 0)); if(!ctorcif) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_OUT_OF_MEMORY; return 0; } } else { ctorcif = 0; } #else /* Use the marshalling function pointer as the cif if no libffi */ cif = fnInfo.marshal; ctorcif = ctorfnInfo.marshal; #endif /* Generate the coder stub for marshalling the call */ if(!isConstructor) { /* We only need the method entry point */ if(!ILCoderSetupExtern(coder, &start, method, fnInfo.func, cif, (pinv == 0))) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_OUT_OF_MEMORY; return 0; } while((result = ILCoderFinish(coder)) != IL_CODER_END_OK) { /* Do we need a coder restart due to cache overflow? */ if(result != IL_CODER_END_RESTART) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_OUT_OF_MEMORY; return 0; } if(!ILCoderSetupExtern(coder, &start, method, fnInfo.func, cif, (pinv == 0))) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_OUT_OF_MEMORY; return 0; } } } else { /* We need both the method and constructor entry points */ if(!ILCoderSetupExternCtor(coder, &start, method, fnInfo.func, cif, ctorfnInfo.func, ctorcif, (pinv == 0))) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_OUT_OF_MEMORY; return 0; } while((result = ILCoderFinish(coder)) != IL_CODER_END_OK) { /* Do we need a coder restart due to cache overflow? */ if(result != IL_CODER_END_RESTART) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_OUT_OF_MEMORY; return 0; } if(!ILCoderSetupExternCtor(coder, &start, method, fnInfo.func, cif, ctorfnInfo.func, ctorcif, (pinv == 0))) { METADATA_UNLOCK(thread); *errorCode = IL_CONVERT_OUT_OF_MEMORY; return 0; } } } } /* The method is converted now */ /* Run the needed cctors and unlock the metadata too */ ILCoderRunCCtors(coder, start); *errorCode = IL_CONVERT_OK; return start; }
/* * Output a table of exception matching directives. * Each table entry specifies a region of code for the * directive. Whenever an exception occurs in this * region, the method will jump to the instructions * contained in the table entry. These instructions * will typically call "finally" handlers, and then * attempt to match the exception against the rules. */ static void OutputExceptionTable(ILCoder *coder, ILMethod *method, ILException *exceptions, int hasRethrow) { ILUInt32 offset; ILUInt32 end; int isStatic; ILException *exception; ILClass *classInfo; /* Process all regions in the method */ offset = 0; for(;;) { /* Find the end of the region that starts at "offset" */ end = IL_MAX_UINT32; exception = exceptions; while(exception != 0) { if(offset < exception->tryOffset) { /* We are in the code before this exception region */ if(end > exception->tryOffset) { end = exception->tryOffset; } } else if(offset >= exception->tryOffset && offset < (exception->tryOffset + exception->tryLength)) { /* We are in code in the middle of this exception region */ if(end > (exception->tryOffset + exception->tryLength)) { end = exception->tryOffset + exception->tryLength; } } exception = exception->next; } if(end == IL_MAX_UINT32) { break; } /* Output the region information to the table */ ILCoderTryHandlerStart(coder, offset, end); /* Output exception matching code for this region */ exception = exceptions; while(exception != 0) { if(offset >= exception->tryOffset && offset < (exception->tryOffset + exception->tryLength)) { if((exception->flags & (IL_META_EXCEPTION_FINALLY | IL_META_EXCEPTION_FAULT)) != 0) { /* Call a "finally" or "fault" clause */ ILCoderFinally(coder, exception, exception->handlerOffset); } else if((exception->flags & IL_META_EXCEPTION_FILTER) == 0) { /* Match against a "catch" clause */ classInfo = ILProgramItemToClass ((ILProgramItem *)ILImageTokenInfo (ILProgramItem_Image(method), exception->extraArg)); ILCoderCatch(coder, exception, classInfo, hasRethrow); } else { /* TODO: handle a "filter" clause */ } } exception = exception->next; } /* If execution falls off the end of the matching code, then throw the exception to the calling method */ ILCoderThrow(coder, 0); /* Mark the end of the handler */ ILCoderTryHandlerEnd(coder); /* Advance to the next region within the code */ offset = end; } /* If execution gets here, then there were no applicable catch blocks, so we always throw the exception to the calling method */ ILCoderTryHandlerStart(coder, 0, IL_MAX_UINT32); if (ILMethod_IsSynchronized(method)) { /* Exit the sync lock before throwing to the calling method */ isStatic = ILMethod_IsStatic(method); PUSH_SYNC_OBJECT(); ILCoderCallInlineable(coder, IL_INLINEMETHOD_MONITOR_EXIT, 0); } ILCoderThrow(coder, 0); ILCoderTryHandlerEnd(coder); }
return 0; } } /* * Emit code to throw a system-level exception. */ static void _ThrowSystem(ILCoder *coder, ILMethod *method, int hasExceptions, const char *name, const char *namespace) { ILClass *classInfo; ILMethod *ctor; ILCoderMethodInfo callInfo; /* Find the no-argument constructor for the class */ classInfo = ILClassResolveSystem(ILProgramItem_Image(method), 0, name, namespace); if(!classInfo) { return; } ctor = 0; while((ctor = (ILMethod *)ILClassNextMemberByKind (classInfo, (ILMember *)ctor, IL_META_MEMBERKIND_METHOD)) != 0) { if(ILMethod_IsConstructor(ctor) && ILTypeNumParams(ILMethod_Signature(ctor)) == 0) { break; } }