📄 verify3a.c
字号:
/** * verify3a.c * * Copyright 2004 * Kaffe.org contributors. See ChangeLog for details. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. * * * Performs pass 3a of bytecode verification: * verification of static constaints. */#include "config.h"#ifdef HAVE_STRING_H#include <string.h>#endif#include "baseClasses.h"#include "bytecode.h"#include "classMethod.h"#include "code.h"#include "constants.h"#include "exception.h"#include "errors.h"#include "debug.h"#include "gc.h"#include "lookup.h"#include "soft.h"#include "verify.h"#include "verify-block.h"#include "verify-debug.h"#include "verify-errors.h"/* * Helper function for error reporting in BRANCH_IN_BOUNDS macro in verifyMethod3a. */static inlineboolbranchInBoundsErrorInVerifyMethod3a(Verifier* v, uint32 codelen, uint32 n){ DBG(VERIFY3, dprintf("ERROR: branch to (%d) out of bound (%d) \n", n, codelen); ); return verifyError(v, "branch out of method code");}/* * Helper function for error reporting in CHECK_LOCAL_INDEX macro in verifyMethod3a. */static inlineboolcheckLocalIndexErrorInVerifyMethod3a(Verifier* v, uint32 pc, unsigned char* code, uint32 n){ DBG(VERIFY3, dprintf("ERROR: pc = %d, instruction = ", pc); printInstruction(code[pc]); dprintf(", localsz = %d, localindex = %d\n", v->method->localsz, n); ); return verifyError(v, "attempting to access a local variable beyond local array");}/* * verifyMethod3a() * check static constraints. section 4.8.1 of JVML Spec 2. * * NOTE: we don't check whether execution can fall off the end of method code here as * that would require us to know whether the last statements are reachable. * Sun's verifier, for instance, rejects code with an unreachable NOP at the end! * Thus we check whether execution can fall off the end during the data flow analysis * of pass 3b, structural constraint checking. * * TODO: turn some of these macros into inlined functions */voidverifyMethod3a(Verifier* v){#define ENSURE_NON_WIDE \ if (wide) { \ verifyError(v, "illegal instruction following wide instruction"); \ return; \ }#define CHECK_POOL_IDX(_IDX) \ if (_IDX > pool->size) { \ verifyError(v, "attempt to access a constant pool index beyond constant pool range"); \ return; \ } #define GET_IDX(_IDX, _PC) \ (_IDX) = getIdx(code, _PC); \ CHECK_POOL_IDX(_IDX)#define GET_WIDX(_IDX, _PC) \ _IDX = getWIdx(code, _PC); \ CHECK_POOL_IDX(_IDX)#define BRANCH_IN_BOUNDS(_N, _INST) \ if (_N >= codelen) { \ branchInBoundsErrorInVerifyMethod3a(v, codelen, _N); \ return; \ } /* makes sure the index given for a local variable is within the correct index */#define CHECK_LOCAL_INDEX(_N) \ if ((_N) >= v->method->localsz) { \ checkLocalIndexErrorInVerifyMethod3a(v, pc, code, _N); \ return; \ } const constants* pool = CLASS_CONSTANTS(v->method->class); /* used for looking at method signatures... */ const char* sig; uint32 codelen = (uint32)METHOD_BYTECODE_LEN(v->method); unsigned char* code = METHOD_BYTECODE_CODE(v->method); uint32 pc = 0, newpc = 0, n = 0, idx = 0; int32 branchoffset = 0; int32 low, high; bool wide; bool inABlock; /* used when calculating the start/return address of each block */ uint32 blockCount = 0; BlockInfo** blocks = NULL; DBG(VERIFY3, dprintf(" Verifier Pass 3a: checking static constraints and finding basic blocks...\n"); ); if (METHOD_BYTECODE_LEN(v->method) < 0) { verifyError(v, "method bytecode length is less than 0"); } /* find the start of every instruction and basic block to determine legal branches * * also, this makes sure that only legal instructions follow the WIDE instruction */ v->status[0] |= START_BLOCK; wide = false; pc = 0; while(pc < codelen) { v->status[pc] |= IS_INSTRUCTION; DBG(VERIFY3, dprintf(" instruction: (%d) ", pc); printInstruction(code[pc]); dprintf("\n"); ); if (codelen < getNextPC(code, pc)) { verifyError(v, "last operand in code array is cut off"); return; } switch(code[pc]) { case ALOAD_0: case ASTORE_0: case ILOAD_0: case ISTORE_0: case FLOAD_0: case FSTORE_0: ENSURE_NON_WIDE; CHECK_LOCAL_INDEX(0); break; case ALOAD_1: case ASTORE_1: case ILOAD_1: case ISTORE_1: case FLOAD_1: case FSTORE_1: case LLOAD_0: case LSTORE_0: case DLOAD_0: case DSTORE_0: ENSURE_NON_WIDE; CHECK_LOCAL_INDEX(1); break; case ALOAD_2: case ASTORE_2: case ILOAD_2: case ISTORE_2: case FLOAD_2: case FSTORE_2: case LLOAD_1: case LSTORE_1: case DLOAD_1: case DSTORE_1: ENSURE_NON_WIDE; CHECK_LOCAL_INDEX(2); break; case ALOAD_3: case ASTORE_3: case ILOAD_3: case ISTORE_3: case FLOAD_3: case FSTORE_3: case LLOAD_2: case LSTORE_2: case DLOAD_2: case DSTORE_2: ENSURE_NON_WIDE; CHECK_LOCAL_INDEX(3); break; case LLOAD_3: case LSTORE_3: case DLOAD_3: case DSTORE_3: ENSURE_NON_WIDE; CHECK_LOCAL_INDEX(4); break; case LDC1: GET_IDX(idx, pc); goto LDC_common; case LDC2: GET_WIDX(idx, pc); LDC_common: n = CONST_TAG(idx, pool); if (n != CONSTANT_Integer && n != CONSTANT_Float && n != CONSTANT_String && n != CONSTANT_ResolvedString) { verifyError(v, "ldc* on constant pool entry other than int/float/string"); return; } break; case LDC2W: GET_WIDX(idx, pc); n = CONST_TAG(idx, pool); if (n != CONSTANT_Double && n != CONSTANT_Long) { verifyError(v, "ldc2_w on constant pool entry other than long or double"); return; } break; case GETFIELD: case PUTFIELD: case GETSTATIC: case PUTSTATIC: ENSURE_NON_WIDE; GET_WIDX(idx, pc); idx = CONST_TAG(idx, pool); if (idx != CONSTANT_Fieldref) { verifyError(v, "[get/put][field/static] accesses something in the constant pool that is not a CONSTANT_Fieldref"); return; } break; case INVOKEVIRTUAL: case INVOKESTATIC: case INVOKESPECIAL: ENSURE_NON_WIDE; GET_WIDX(idx, pc); n = CONST_TAG(idx, pool); if (n != CONSTANT_Methodref) { verifyError(v, "invoke* accesses something in the constant pool that is not a CONSTANT_Methodref"); return; } sig = METHODREF_SIGD(idx, pool); if (*sig == '<') { if (!strcmp(constructor_name->data, sig)) { if (code[pc] != INVOKESPECIAL) { verifyError(v, "only invokespecial can be used to execute <init> methods"); return; } } else { verifyError(v, "no method with a name whose first character is '<' may be called by an invoke instruction"); return; } } break; /* invokeinterface is a 5 byte instruction. the first byte is the instruction. * the next two are the index into the constant pool for the methodreference. * the fourth is the number of parameters expected by the method, and the verifier * must check that the actual method signature of the method to be invoked matches * this number. the 5th must be zero. these are apparently present for historical * reasons (yeah Sun :::smirk:::). */ case INVOKEINTERFACE: ENSURE_NON_WIDE; GET_WIDX(idx, pc); n = CONST_TAG(idx, pool); if (n != CONSTANT_InterfaceMethodref) { verifyError(v, "invokeinterface accesses something in the constant pool that is not a CONSTANT_InterfaceMethodref"); return; } sig = INTERFACEMETHODREF_SIGD(idx, pool); if (*sig == '<') { verifyError(v, "invokeinterface cannot be used to invoke any instruction with a name starting with '<'"); return; } if (code[pc + 3] == 0) { verifyError(v, "fourth byte of invokeinterface is zero"); return; } else if (code[pc + 4] != 0) { verifyError(v, "fifth byte of invokeinterface is not zero"); return; } break; case INSTANCEOF: case CHECKCAST: ENSURE_NON_WIDE; GET_WIDX(n, pc); n = CONST_TAG(n, pool); if (n != CONSTANT_Class && n != CONSTANT_ResolvedClass) { verifyError(v, "instanceof/checkcast indexes a constant pool entry that is not type CONSTANT_Class or CONSTANT_ResolvedClass"); return; } break; case MULTIANEWARRAY: ENSURE_NON_WIDE; GET_WIDX(idx, pc); n = CONST_TAG(idx, pool); if (n != CONSTANT_Class && n != CONSTANT_ResolvedClass) { verifyError(v, "multinewarray indexes a constant pool entry that is not type CONSTANT_Class or CONSTANT_ResolvedClass"); return; } /* number of dimensions must be <= num dimensions of array type being created */ sig = CLASS_NAMED(idx, pool); newpc = code[pc + 3]; if (newpc == 0) { verifyError(v, "dimensions operand of multianewarray must be non-zero"); return; } for(n = 0; *sig == '['; sig++, n++); if (n < newpc) { verifyError(v, "dimensions operand of multianewarray is > the number of dimensions in array being created"); return; } break; case NEW: ENSURE_NON_WIDE; GET_WIDX(idx, pc); n = CONST_TAG(idx, pool); if (n != CONSTANT_Class && n != CONSTANT_ResolvedClass) { verifyError(v, "new indexes a constant pool entry that is not type CONSTANT_Class or CONSTANT_ResolvedClass"); return; } /* cannot create arrays with NEW */ sig = CLASS_NAMED(idx, pool); if (*sig == '[') { verifyError(v, "new instruction used to create a new array"); return; } break; case ANEWARRAY: ENSURE_NON_WIDE; GET_WIDX(idx, pc); n = CONST_TAG(idx, pool); if (n != CONSTANT_Class && n != CONSTANT_ResolvedClass) { verifyError(v, "anewarray indexes a constant pool entry that is not type CONSTANT_Class or CONSTANT_ResolvedClass"); return; } /* count the number of dimensions of the array being created...it must be <= 255 */ sig = CLASS_NAMED(idx, pool); for (n = 0; *sig == '['; sig++, n++); if (n > 255) { verifyError(v, "anewarray used to create an array of > 255 dimensions"); return; } break; case NEWARRAY: ENSURE_NON_WIDE; n = code[pc + 1]; if (n < 4 || n > 11) { verifyError(v, "newarray operand must be in the range [4,11]"); return; } break; /*********************************************************** * Instructions that can be modified by WIDE ***********************************************************/ case WIDE: ENSURE_NON_WIDE; wide = true; break; case ALOAD: case ASTORE: case ILOAD: case ISTORE: case FLOAD: case FSTORE: if (wide == true) { /* the WIDE is considered the beginning of the instruction */ v->status[pc] ^= IS_INSTRUCTION; v->status[pc] |= WIDE_MODDED; pc++; wide = false; n = getWord(code, pc); } else { n = code[pc + 1];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -