📄 verifierutil.c
字号:
/* * Copyright (c) 1998-2001 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. *//*========================================================================= * SYSTEM: KVM * SUBSYSTEM: Class file verifier (runtime part) * FILE: verifierUtil.c * OVERVIEW: Implementation-specific parts of the KVM verifier. * AUTHORS: Sheng Liang, Frank Yellin, restructured by Nik Shaylor *=======================================================================*//*========================================================================= * Include files *=======================================================================*/#include "stddef.h"#include "verifierUtil.h"/*========================================================================= * Global variables and definitions *=======================================================================*//* * This is always the method being verified. (The verifier cannot be called * recursively) */METHOD methodBeingVerified;/* * Pointer to the bytecodes */unsigned char *bytecodesBeingVerified;/* * Holds the return signature */static unsigned char *returnSig;/* * Global variables used by the verifier. */VERIFIERTYPE *vStack;VERIFIERTYPE *vLocals;unsigned long *NEWInstructions;bool_t vNeedInitialization; /* must call a this.<init> or super. */unsigned short vMaxStack;unsigned short vFrameSize;unsigned short vSP;#if INCLUDEDEBUGCODEstatic int vErrorIp;#endif/*========================================================================= * Old verifier functions (inherited from KVM 1.0.3) *=======================================================================*//*========================================================================= * FUNCTION: initializeVerifier * TYPE: public global operation * OVERVIEW: Initialize the bytecode verifier * * INTERFACE: * parameters: <nothing> * returns: <nothing> *=======================================================================*/void InitializeVerifier(void) {}/*========================================================================= * FUNCTION: vIsAssignable * TYPE: private operation on type keys * OVERVIEW: Check if a value of one type key can be converted to a * value of another type key. * * INTERFACE: * parameters: fromKey: from type * toKey: to type * mergedKeyP: pointer to merged type * returns: TRUE: can convert. * FALSE: cannot convert. *=======================================================================*/bool_t vIsAssignable(VERIFIERTYPE fromKey, VERIFIERTYPE toKey, VERIFIERTYPE *mergedKeyP) { if (mergedKeyP) { /* Most of the time merged type is toKey */ *mergedKeyP = toKey; } if (fromKey == toKey) /* trivial case */ return TRUE; if (toKey == ITEM_Bogus) return TRUE; if (toKey == ITEM_Reference) { return fromKey == ITEM_Null || fromKey > 255 || fromKey == ITEM_InitObject || (fromKey & ITEM_NewObject_Flag); } if ((toKey & ITEM_NewObject_Flag) || (fromKey & ITEM_NewObject_Flag)) { return FALSE; } if (fromKey == ITEM_Null && toKey > 255) { return TRUE; } if (fromKey > 255 && toKey > 255) { CLASS fromClass = change_Key_to_CLASS(Vfy_toClassKey(fromKey)); CLASS toClass = change_Key_to_CLASS(Vfy_toClassKey(toKey)); bool_t res = isAssignableTo(fromClass, toClass); /* Interfaces are treated like java.lang.Object in the verifier. */ if (toClass->accessFlags & ACC_INTERFACE) { /* Set mergedKey to fromKey for interfaces */ if (mergedKeyP) { *mergedKeyP = Vfy_getObjectVerifierType(); } return TRUE; } return res; } return FALSE;}/*========================================================================= * FUNCTION: vIsProtectedAccess * TYPE: private operation on type keys * OVERVIEW: Check if the access to a method or field is to * a protected field/method of a superclass. * * INTERFACE: * parameters: thisClass: The class in question * index: Constant pool entry of field or method * isMethod: true for method, false for field. *=======================================================================*/bool_t vIsProtectedAccess(INSTANCE_CLASS thisClass, POOLINDEX index, bool_t isMethod) { CONSTANTPOOL constPool = thisClass->constPool; unsigned short memberClassIndex = constPool->entries[index].method.classIndex; INSTANCE_CLASS memberClass = (INSTANCE_CLASS)constPool->entries[memberClassIndex].clazz; INSTANCE_CLASS tClass; unsigned short nameTypeIndex; unsigned long nameTypeKey; /* if memberClass isn't a superclass of this class, then we don't worry * about this case */ for (tClass = thisClass; ; tClass = tClass->superClass) { if (tClass == NULL) { return FALSE; } else if (tClass == memberClass) { break; } } nameTypeIndex = constPool->entries[index].method.nameTypeIndex; nameTypeKey = constPool->entries[nameTypeIndex].nameTypeKey.i; while (memberClass != NULL) { if (isMethod) { FOR_EACH_METHOD(method, memberClass->methodTable) if (method->nameTypeKey.i == nameTypeKey) { return (((method->accessFlags & ACC_PROTECTED) != 0) && (memberClass->clazz.packageName != thisClass->clazz.packageName)); } END_FOR_EACH_METHOD } else { FOR_EACH_FIELD(field, memberClass->fieldTable) if (field->nameTypeKey.i == nameTypeKey) { return (((field->accessFlags & ACC_PROTECTED) != 0) && (memberClass->clazz.packageName != thisClass->clazz.packageName)); } END_FOR_EACH_FIELD } memberClass = memberClass->superClass; } return FALSE;}/*========================================================================= * FUNCTION: Vfy_getReferenceArrayElementType * TYPE: private operation on type keys * OVERVIEW: Obtain the element type key of a given object reference type. * * INTERFACE: * parameters: typeKey: object array type key. * returns: element type key. * * DANGER: * Before calling this function, make sure that typeKey in fact is an * object array. *=======================================================================*/VERIFIERTYPE Vfy_getReferenceArrayElementType(VERIFIERTYPE arrayType) { CLASSKEY arrayTypeKey = Vfy_toClassKey(arrayType); int n = (arrayTypeKey >> FIELD_KEY_ARRAY_SHIFT); if (arrayTypeKey == ITEM_Null) { return ITEM_Null; } else if (n < MAX_FIELD_KEY_ARRAY_DEPTH) { return ((n - 1) << FIELD_KEY_ARRAY_SHIFT) + (arrayTypeKey & 0x1FFF); } else { CLASS arrayClass = change_Key_to_CLASS(Vfy_toClassKey(arrayTypeKey)); const char* baseNameString = arrayClass->baseName->string; UString baseName = getUStringX(&baseNameString, 1, arrayClass->baseName->length - 1); UString packageName = arrayClass->packageName; CLASS elemClass = change_Name_to_CLASS(packageName, baseName); return Vfy_toVerifierType(elemClass->key); }}/*========================================================================= * FUNCTION: Vfy_getClassArrayVerifierType * TYPE: private operation on type keys * OVERVIEW: Obtain the object array type key whose element type is the * given element type key. * * INTERFACE: * parameters: typeKey: element type key. * returns: object array type key. * * DANGER: * Before calling this function, make sure that typeKey in fact is an * object type. *=======================================================================*/VERIFIERTYPE Vfy_getClassArrayVerifierType(CLASSKEY typeKey) { CLASSKEY res; int n = (typeKey >> FIELD_KEY_ARRAY_SHIFT); if (n < MAX_FIELD_KEY_ARRAY_DEPTH - 1) { res = (1 << FIELD_KEY_ARRAY_SHIFT) + typeKey; } else { CLASS elemClass = change_Key_to_CLASS(typeKey); ARRAY_CLASS arrayClass = getObjectArrayClass(elemClass); res = arrayClass->clazz.key; } return Vfy_toVerifierType(res);}/*========================================================================= * FUNCTION: Vfy_isArrayClassKey * TYPE: private operation on type keys * OVERVIEW: Check if the given type key denotes an array type of the * given dimension. * * INTERFACE: * parameters: typeKey: a type key. * dim: dimension. * returns: TRUE if the type key is an array of dim dimension, FALSE * otherwise. *=======================================================================*/bool_t Vfy_isArrayClassKey(CLASSKEY typeKey, int dim) { if (typeKey == ITEM_Null) { return TRUE; } else { int n = (typeKey >> FIELD_KEY_ARRAY_SHIFT); /* n is the dimension of the class. It has the value * 0..MAX_FIELD_KEY_ARRAY_DEPTH, in which the last value means * MAX_FIELD_KEY_ARRAY_DEPTH or more. . . */ if (dim <= MAX_FIELD_KEY_ARRAY_DEPTH) { return n >= dim; } if (n < MAX_FIELD_KEY_ARRAY_DEPTH) { /* We are looking for at more than MAX_FIELD_KEY_ARRAY_DEPTH, * dimensions, so n needs to be that value. */ return FALSE; } else { CLASS arrayClass = change_Key_to_CLASS(typeKey); char *baseName = arrayClass->baseName->string; /* The first dim characters of baseName must be [ */ for ( ; dim > 0; --dim) { if (*baseName++ != '[') { return FALSE; } } return TRUE; } }}/*========================================================================= * FUNCTION: change_Field_to_StackType * TYPE: private operation on type keys * OVERVIEW: Change an individual field type to a stack type * * INTERFACE: * parameters: fieldType: field type * stackTypeP: pointer for placing the corresponding stack type(s) * returns: number of words occupied by the resulting type. *=======================================================================*/int change_Field_to_StackType(CLASSKEY fieldType, VERIFIERTYPE* stackTypeP) { switch (fieldType) { case 'I': case 'B': case 'Z': case 'C': case 'S': *stackTypeP++ = ITEM_Integer; return 1;#if IMPLEMENTS_FLOAT case 'F': *stackTypeP++ = ITEM_Float; return 1; case 'D': *stackTypeP++ = ITEM_Double; *stackTypeP++ = ITEM_Double_2; return 2;#endif case 'J': *stackTypeP++ = ITEM_Long; *stackTypeP++ = ITEM_Long_2; return 2; default: *stackTypeP++ = fieldType; return 1; }}/*========================================================================= * FUNCTION: change_Arg_to_StackType * TYPE: private operation on type keys * OVERVIEW: Change an individual method argument type to a stack type * * INTERFACE: * parameters: sigP: pointer to method signature. * type: pointer for placing the corresponding stack type(s) * returns: number of words occupied by the resulting type. *=======================================================================*/int change_Arg_to_StackType(unsigned char** sigP, VERIFIERTYPE* typeP) { unsigned char *sig = *sigP; unsigned short hi, lo; hi = *sig++; if (hi == 'L') { hi = *sig++; lo = *sig++; *sigP = sig; return change_Field_to_StackType((unsigned short)((hi << 8) + lo), typeP); } if (hi < 'A' || hi > 'Z') { lo = *sig++; *sigP = sig; return change_Field_to_StackType((unsigned short)((hi << 8) + lo), typeP); } *sigP = sig; return change_Field_to_StackType(hi, typeP);}/*========================================================================= * FUNCTION: getStackType * TYPE: private operation on type keys * OVERVIEW: Get the recorded stack map of a given target ip. * * INTERFACE: * parameters: thisMethod: method being verified. * this_ip: current ip (unused for now). * target_ip: target ip (to look for a recored stack map). * returns: a stack map *=======================================================================*/static unsigned short *getStackMap(METHOD thisMethod, IPINDEX target_ip) { POINTERLIST stackMaps = thisMethod->u.java.stackMaps.verifierMap; unsigned short i; if (stackMaps == NULL) { return NULL; } else { long length = stackMaps->length; /* number of entries */ for (i = 0; i < length; i++) { if (target_ip == stackMaps->data[i + length].cell) { return (unsigned short*)stackMaps->data[i].cellp; } } } return NULL;}/*========================================================================= * FUNCTION: matchStackMap * TYPE: private operation on type keys * OVERVIEW: Match two stack maps. * * INTERFACE: * parameters: thisMethod: method being verified. * target_ip: target ip (to look for a recored stack map). * flags: bit-wise or of the SM_* flags. * returns: TRUE if match, FALSE otherwise. *=======================================================================*/bool_t matchStackMap(METHOD thisMethod, IPINDEX target_ip, int flags) { bool_t result = TRUE; /* Assume result is TRUE */ bool_t target_needs_initialization; unsigned short nstack; unsigned short nlocals; unsigned short i; /* Following is volatile, and will disappear at first GC */ unsigned short *stackMapBase = getStackMap(thisMethod, target_ip);#if INCLUDEDEBUGCODE if (traceverifier) { fprintf(stdout, "Match stack maps (this=%ld, target=%ld)%s%s%s\n", (long)vErrorIp, (long)target_ip, (flags & SM_CHECK) ? " CHECK" : "", (flags & SM_MERGE) ? " MERGE" : "", (flags & SM_EXIST) ? " EXIST" : ""); }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -