📄 verifier.c
字号:
/* * Copyright (c) 1998-2002 Sun Microsystems, Inc. All Rights Reserved. * * This software is the confidential and proprietary information of Sun * Microsystems, Inc. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. * * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING * THIS SOFTWARE OR ITS DERIVATIVES. * * Use is subject to license terms. *//* * NOTICE: * This file is considered "Shared Part" under the CLDC SCSL * and commercial licensing terms, and is therefore not to * be modified by licensees. For definition of the term * "Shared Part", please refer to the CLDC SCSL license * attachment E, Section 2.1 (Definitions) paragraph "e", * or your commercial licensing terms as applicable. *//*========================================================================= * KVM *========================================================================= * SYSTEM: KVM * SUBSYSTEM: Class file verifier (runtime part) * FILE: verifier.c * OVERVIEW: KVM has a two-phase class file verifier. In order to * run in the KVM, class files must first be processed with * a special "pre-verifier" tool. This phase is typically * done on the development workstation. During execution, * the runtime verifier (defined in this file) of the KVM * performs the actual class file verification based on * both runtime information and pre-verification information. * AUTHORS: Sheng Liang, Frank Yellin, restructured by Nik Shaylor *=======================================================================*//*========================================================================= * Include files *=======================================================================*/#include "verifierUtil.h"/*========================================================================= * Functions *=======================================================================*//*========================================================================= * FUNCTION: Vfy_verifyMethodOrAbort * TYPE: private operation on methods. * OVERVIEW: Perform byte-code verification of a given method. * * INTERFACE: * parameters: vMethod: method to be verified. * returns: Normally if verification succeeds, otherwise longjmp * is called (in Vfy_throw) to return control to a handler * in the calling code. *=======================================================================*/void Vfy_verifyMethodOrAbort(const METHOD vMethod) { /* * The following variables are constant in this function */ const CLASS vClass = Mth_getClass(vMethod); const CLASS vSuperClass = Cls_getSuper(vClass); const int codeLength = Mth_getBytecodeLength(vMethod); const int handlerCount = Mth_getExceptionTableLength(vMethod); const CONSTANTPOOL vPool = Cls_getPool(vClass); /* * The virtual IP used by the verifier */ IPINDEX ip = 0; /* * The following is set to TRUE where is no direct control * flow from current instruction to the next instruction * in sequence. */ bool_t noControlFlow = FALSE; /* * Pointer to the "current" stackmap entry */ int currentStackMapIndex = 0; /* * Check that a virtual method does not subclass a "final" * method higher up the inheritance chain * * Was bug 4336036 */ if (!Mth_isStatic(vMethod)) { /* * Dont check methods in java.lang.Object. */ if (!Cls_isJavaLangObject(vClass)) { /* * Lookup the method being verified in the superclass */ METHOD superMethod = Cls_lookupMethod(vClass, vSuperClass, vMethod); /* * If it exists then it must not be final */ if (superMethod != NULL && Mth_isFinal(superMethod)) { Vfy_throw(VE_FINAL_METHOD_OVERRIDE); } } } /* * Verify that all exception handlers have a reasonable exception type. */ if (handlerCount > 0) { int i; VERIFIERTYPE exceptionVerifierType; /* * Iterate through the handler table */ for (i = 0; i < handlerCount; i++) { /* * Get the catch type from the exception table */ POOLINDEX catchTypeIndex = Mth_getExceptionTableCatchType(vMethod, i); /* * If the catch type index is zero then this is a try/finally entry * and there is no exception type, If it is not zero then it needs * to be checked. */ if (catchTypeIndex != 0) { /* * Check that the entry is there and that it is a CONSTANT_Class */ Pol_checkTagIsClass(vPool, catchTypeIndex); /* * Get the class key */ exceptionVerifierType = Vfy_toVerifierType(Pol_getClassKey(vPool, catchTypeIndex)); /* * Check that it is subclass of java.lang.Throwable */ if (!Vfy_isAssignable(exceptionVerifierType, Vfy_getThrowableVerifierType())) { Vfy_throw(VE_EXPECT_THROWABLE); } } } } /* * Initialize the local variable type table with the method argumenet types */ Vfy_initializeLocals(); /* * The main loop */ while (ip < codeLength) { /* * Used to hold the current opcode */ int opcode; /* * Used to hold IP address of the next entry in the stackmap table */ IPINDEX nextStackMapIP; /* * Setup the ip used for error messages in case it is needed later */ Vfy_setErrorIp(ip); /* * Output the debug trace message */ Vfy_printVerifyLoopMessage(vMethod, ip); /* * Check that stackmaps are ordered according to offset and that * every offset in stackmaps point to the beginning to an instruction. */ nextStackMapIP = Mth_getStackMapEntryIP(vMethod, currentStackMapIndex); if (nextStackMapIP == ip) { currentStackMapIndex++; /* This offset is good. */ } if (nextStackMapIP < ip) { Vfy_throw(VE_BAD_STACKMAP); /* ip should have met offset. */ } /* * Trace the instruction ip */ Vfy_trace1("Check instruction %ld\n", ip); /* * Merge with the next instruction (note how noControlFlow is used here). */ Vfy_checkCurrentTarget(ip, noControlFlow); /* * Set noControlFlow to its default state */ noControlFlow = FALSE; /* * Look for a possible jump target in one or more exception handlers. * If found the current local variable types must be the same as those * of the handler entrypoint. */ if (handlerCount > 0) { int i; /* * Iterate through the handler table */ for (i = 0 ; i < handlerCount ; i++) { /* * Get the start and end points of the handler entry */ IPINDEX startPC = Mth_getExceptionTableStartPC(vMethod, i); IPINDEX endPC = Mth_getExceptionTableEndPC(vMethod, i); /* * Check to see if the "current" ip falls in between these pointers */ if (ip >= startPC && ip < endPC) { VERIFIERTYPE exceptionVerifierType; /* * Get the ip offset for the exception handler and the catch type index */ IPINDEX handlerPC = Mth_getExceptionTableHandlerPC(vMethod, i); POOLINDEX catchTypeIndex = Mth_getExceptionTableCatchType(vMethod, i); /* * If the catch type index is zero then this is a try/finally entry. * Unlike J2SE (1.3) there are no jsr/ret instructions in J2SE. The * code in a finally block will be copied in to the end of the try * block and an anonymous handler entry is make that points to another * copy of the code. This will only be called if an exception is thrown * in which case there will be an exception object of some kind on the * stack. On the other hand if catch type index is non-zero then it * will indicate a specific throwable type. */ if (catchTypeIndex != 0) { exceptionVerifierType = Vfy_toVerifierType(Pol_getClassKey(vPool, catchTypeIndex)); } else { exceptionVerifierType = Vfy_getThrowableVerifierType(); } /* * Save the current stack types somewhere and re-initialize the stack. */ Vfy_saveStackState(); /* * Push the exception type and check the target has just this one type * on the stack along with the current local variable types. */ Vfy_push(exceptionVerifierType); Vfy_checkHandlerTarget(handlerPC); /* * Restore the old stack types */ Vfy_restoreStackState(); } } } /* * Get the next bytecode */ opcode = Vfy_getOpcode(ip); switch (opcode) { case NOP: { ip++; break; } case ACONST_NULL: { Vfy_push(ITEM_Null); ip++; break; } case ICONST_M1: case ICONST_0: case ICONST_1: case ICONST_2: case ICONST_3: case ICONST_4: case ICONST_5: { Vfy_push(ITEM_Integer); ip++; break; } case LCONST_0: case LCONST_1: { Vfy_push(ITEM_Long); Vfy_push(ITEM_Long_2); ip++; break; }#if IMPLEMENTS_FLOAT case FCONST_0: case FCONST_1: case FCONST_2: { Vfy_push(ITEM_Float); ip++; break; } case DCONST_0: case DCONST_1: { Vfy_push(ITEM_Double); Vfy_push(ITEM_Double_2); ip++; break; }#endif /* IMPLEMENTS_FLOAT */ case BIPUSH: { Vfy_push(ITEM_Integer); ip += 2; break; } case SIPUSH: { ip++; Vfy_push(ITEM_Integer); ip += 2; break; } case LDC: case LDC_W: case LDC2_W: { POOLTAG tag; POOLINDEX index; /* * Get the constant pool index and advance the ip to the next instruction */ if (opcode == LDC) { /* LDC */ index = Vfy_getUByte(ip + 1); ip += 2; } else { /* LDC_W or LDC2_W */ index = Vfy_getUShort(ip + 1); ip += 3; } /* * Get the tag */ tag = Pol_getTag(vPool, index); /* * Check for the right kind of LDC and push the required type */ if (opcode == LDC2_W) { /* LDC2_W */ if (tag == CONSTANT_Long) { Vfy_push(ITEM_Long); Vfy_push(ITEM_Long_2); break; }#if IMPLEMENTS_FLOAT if (tag == CONSTANT_Double) { Vfy_push(ITEM_Double); Vfy_push(ITEM_Double_2); break; }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -