📄 verify.c
字号:
*buf = '\0'; return afterSig;}/* * countSizeOfArgsInSignature() * Longs & Double count for 2, all else counts for one. */staticuint32countSizeOfArgsInSignature(const char* sig){ uint32 count = 0; for (sig++; *sig != ')'; sig = parseFieldTypeDescriptor(sig)) { if (*sig == 'J' || *sig == 'D') count += 2; else count++; } return count;}/* * Helper function for error reporting in checkMethodCall. * Provided basically to give better debugging output. */static inlineboolverifyErrorInCheckMethodCall(Verifier* v, char* argbuf, uint32 pc, const uint32 idx, const constants* pool, const char* methSig, const char* msg){ gc_free(argbuf); DBG(VERIFY3, dprintf(" error with method invocation, pc = %d, method = %s%s\n", pc, METHODREF_NAMED(idx, pool), methSig); ); return verifyError(v, msg);}/* * Helper function for error reporting in checkMethodCall. */static inlinebooltypeErrorInCheckMethodCall(Verifier* v, char* argbuf, uint32 pc, const uint32 idx, const constants* pool, const char* methSig){ return verifyErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig, "parameters fail type checking in method invocation");}/* * checkMethodCall() * verify an invoke instruction. this includes making sure that the types * on the operand stack are type compatible with those expected by the method * being called. * * note: we don't check to make sure that the class being referenced by the * method call actually has the method, or that we have permission to * access it, as those checks are deferred until pass 4. * * returns whether the method's arguments type check correctly. * it also pushes the return type onto binfo's operand stack. */boolcheckMethodCall(Verifier* v, BlockInfo* binfo, uint32 pc){ const unsigned char* code = METHOD_BYTECODE_CODE(v->method); const uint32 opcode = code[pc]; const constants* pool = CLASS_CONSTANTS(v->class); const uint32 idx = getWord(code, pc + 1); const uint32 classIdx = METHODREF_CLASS(idx, pool); Type mrc; Type* methodRefClass = &mrc; Type* t = &mrc; /* for shorthand :> */ Type* receiver = NULL; const char* methSig = METHODREF_SIGD(idx, pool); const char* sig = methSig; uint32 nargs = countSizeOfArgsInSignature(sig); uint32 paramIndex = 0; char* argbuf = checkPtr(gc_malloc(strlen(sig) * sizeof(char), KGC_ALLOC_VERIFIER)); DBG(VERIFY3, dprintf("%scalling method %s%s\n", indent, METHODREF_NAMED(idx, pool), sig); ); if (nargs > binfo->stacksz) { return verifyErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig, "not enough stuff on opstack for method invocation"); } /* make sure that the receiver is type compatible with the class being invoked */ if (opcode != INVOKESTATIC) { if (nargs == binfo->stacksz) { return verifyErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig, "not enough stuff on opstack for method invocation"); } receiver = &binfo->opstack[binfo->stacksz - (nargs + 1)]; if (!(receiver->tinfo & TINFO_UNINIT) && !isReference(receiver)) { return verifyErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig, "invoking a method on something that is not a reference"); } if (pool->tags[classIdx] == CONSTANT_Class) { methodRefClass->tinfo = TINFO_NAME; methodRefClass->data.name = UNRESOLVED_CLASS_NAMED(classIdx, pool); } else { methodRefClass->tinfo = TINFO_CLASS; methodRefClass->data.class = CLASS_CLASS(classIdx, pool); } if (!strcmp(METHODREF_NAMED(idx,pool), constructor_name->data)) { if (receiver->tinfo & TINFO_UNINIT) { UninitializedType* uninit = receiver->data.uninit; if (receiver->tinfo == TINFO_UNINIT_SUPER) { Type t_uninit_super; t_uninit_super.tinfo = TINFO_CLASS; t_uninit_super.data.class = uninit->type.data.class->superclass; if (!sameType(methodRefClass, &uninit->type) && uninit->type.data.class != getTOBJ()->data.class && !sameType(methodRefClass, &t_uninit_super)) { return verifyErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig, "incompatible receiving type for superclass constructor call"); } } else if (!sameType(methodRefClass, &uninit->type)) { DBG(VERIFY3, dprintf("%smethodRefClass: ", indent); printType(methodRefClass); dprintf("\n%sreceiver: ", indent); printType(&uninit->type); dprintf("\n"); ); return verifyErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig, "incompatible receiving type for constructor call"); } /* fix front of list, if necessary */ if (uninit == v->uninits) { v->uninits = v->uninits->next; if (v->uninits) { (v->uninits)->prev = NULL; } uninit->next = NULL; } popUninit(v->method, uninit, binfo); } else if (!sameType(methodRefClass, receiver)) { return verifyErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig, "incompatible receiving type for constructor call"); } } else if (!typecheck(v, methodRefClass, receiver)) { if (receiver->tinfo & TINFO_UNINIT) { return verifyErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig, "invoking a method on an uninitialized object reference"); } DBG(VERIFY3, dprintf("%srequired receiver type: ", indent); printType(methodRefClass); dprintf("\n%sactual receiver type: ", indent); printType(receiver); dprintf("\n"); ); return verifyErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig, "expected method receiver does not typecheck with object on operand stack"); } } /* here we use paramIndex to represent which parameter we're currently considering. * remember, when we call a method, the first parameter is deepest in the stack, * so when we traverse the parameter list in the method signature we have to look * from the bottom up. */ paramIndex = binfo->stacksz - nargs; for (sig = getNextArg(sig + 1, argbuf); *argbuf != ')'; sig = getNextArg(sig, argbuf)) { if (paramIndex >= binfo->stacksz) { gc_free(argbuf); return verifyErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig, "error: not enough parameters on stack for method invocation"); } switch (*argbuf) { case '[': case 'L': t->tinfo = TINFO_SIG; t->data.sig = argbuf; if (!typecheck(v, t, &binfo->opstack[paramIndex])) { return typeErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig); } binfo->opstack[paramIndex] = *getTUNSTABLE(); paramIndex++; break; case 'Z': case 'S': case 'B': case 'C': case 'I': if (binfo->opstack[paramIndex].data.class != getTINT()->data.class) { return typeErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig); } binfo->opstack[paramIndex] = *getTUNSTABLE(); paramIndex++; break; case 'F': if (binfo->opstack[paramIndex].data.class != getTFLOAT()->data.class) { return typeErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig); } binfo->opstack[paramIndex] = *getTUNSTABLE(); paramIndex++; break; case 'J': if (binfo->opstack[paramIndex].data.class != getTLONG()->data.class || !isWide(&binfo->opstack[paramIndex + 1])) { return typeErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig); } binfo->opstack[paramIndex] = *getTUNSTABLE(); binfo->opstack[paramIndex+ 1] = *getTUNSTABLE(); paramIndex += 2; break; case 'D': if (binfo->opstack[paramIndex].data.class != getTDOUBLE()->data.class || !isWide(&binfo->opstack[paramIndex + 1])) { return typeErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig); } binfo->opstack[paramIndex] = *getTUNSTABLE(); binfo->opstack[paramIndex + 1] = *getTUNSTABLE(); paramIndex += 2; break; default: return typeErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig); } } binfo->stacksz -= nargs; if (opcode != INVOKESTATIC) { /* pop object reference off the stack */ binfo->stacksz--; binfo->opstack[binfo->stacksz] = *getTUNSTABLE(); } /************************************************************** * Process Return Type **************************************************************/ sig++; sig = getNextArg(sig, argbuf); if (*argbuf == 'J' || *argbuf == 'D') { if (v->method->stacksz < binfo->stacksz + 2) { return verifyErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig, "not enough room on operand stack for method call's return value"); } } else if (*argbuf != 'V') { if (v->method->stacksz < binfo->stacksz + 1) { return verifyErrorInCheckMethodCall(v, argbuf, pc, idx, pool, methSig, "not enough room on operand stack for method call's return value"); } } switch (*argbuf) { case 'Z': case 'S': case 'B': case 'C': case 'I': binfo->opstack[binfo->stacksz++] = *getTINT(); break; case 'F': binfo->opstack[binfo->stacksz++] = *getTFLOAT(); break; case 'J': binfo->opstack[binfo->stacksz] = *getTLONG(); binfo->opstack[binfo->stacksz + 1] = *getTWIDE(); binfo->stacksz += 2; break; case 'D': binfo->opstack[binfo->stacksz] = *getTDOUBLE(); binfo->opstack[binfo->stacksz + 1] = *getTWIDE(); binfo->stacksz += 2; break; case 'V': break; case '[': case 'L': v->sigs = pushSig(v->sigs, argbuf); binfo->opstack[binfo->stacksz].data.class = (Hjava_lang_Class*)argbuf; binfo->opstack[binfo->stacksz].tinfo = TINFO_SIG; binfo->stacksz++; /* no freeing of the argbuf here... */ return(true); default: /* shouldn't get here because of parsing during pass 2... */ DBG(VERIFY3, dprintf(" unrecognized return type signature: %s\n", argbuf); ); gc_free(argbuf); postExceptionMessage(v->einfo, JAVA_LANG(InternalError), "unrecognized return type signature"); return(false); } gc_free(argbuf); return(true);}static inlineboolverifyErrorInLoadInitialArgs(Verifier* v, const char* msg, char* argbuf) { gc_free(argbuf); return verifyError(v, msg);}static inlineboollocalOverflowErrorInLoadInitialArgs(Verifier* v, char* argbuf) { return verifyErrorInLoadInitialArgs(v, "method arguments cannot fit into local variables", argbuf);}/* * pushes the initial method arguments into local variable array */staticboolloadInitialArgs(Verifier* v){ uint32 paramCount = 0; /* the +1 skips the initial '(' */ const char* sig = METHOD_SIGD(v->method) + 1; char* argbuf = checkPtr(gc_malloc((strlen(sig)+1) * sizeof(char), KGC_ALLOC_VERIFIER)); char* newsig = NULL; /* load the initial argument into the first basic block. */ BlockInfo* block = v->blocks[0]; Type* locals = block->locals; DBG(VERIFY3, dprintf(" sig: %s\n", sig); ); /* must have at least 1 local variable for the object reference */ if (!METHOD_IS_STATIC(v->method)) { if (v->method->localsz <= 0) { return verifyErrorInLoadInitialArgs(v, "number of locals in non-static method must be > 0", argbuf); } /* the first local variable in every method is the class to which it belongs */ locals[0].tinfo = TINFO_CLASS; locals[0].data.class = v->method->class; paramCount++; if (!strcmp(METHOD_NAMED(v->method), constructor_name->data)) { /* the local reference in a constructor is uninitialized */ v->uninits = pushUninit(v->uninits, &locals[0]); locals[0].tinfo = TINFO_UNINIT_SUPER; locals[0].data.uninit = v->uninits; } } for (sig = getNextArg(sig, argbuf); *argbuf != ')'; sig = getNextArg(sig, argbuf)) { if (paramCount > v->method->localsz) { return localOverflowErrorInLoadInitialArgs(v, argbuf); } switch (*argbuf) { case 'Z': case 'S': case 'B': case 'C': case 'I': locals[paramCount++] = *getTINT(); break; case 'F': locals[paramCount++] = *getTFLOAT(); break; case 'J': if (paramCount + 1 > v->method->localsz) { return localOverflowErrorInLoadInitialArgs(v, argbuf); } locals[paramCount] = *getTLONG(); locals[paramCount+1] = *getTWIDE(); paramCount += 2; break; case 'D': if (paramCount + 1 > v->method->localsz) { return localOverflowErrorInLoadInitialArgs(v, argbuf); } locals[paramCount] = *getTDOUBLE(); locals[paramCount+1] = *getTWIDE(); paramCount += 2; break; case '[': case 'L': newsig = checkPtr(gc_malloc((strlen(argbuf) + 1) * sizeof(char), KGC_ALLOC_VERIFIER)); v->sigs = pushSig(v->sigs, newsig); sprintf(newsig, "%s", argbuf); locals[paramCount].tinfo = TINFO_SIG; locals[paramCount].data.sig = newsig; paramCount++; break; default: DBG(VERIFY3, dprintf("ERROR, loadInitialArgs(): argument to method has bad signature.\n"); dprintf(" it starts with an unrecognized character: %c\n", *argbuf); dprintf(" the rest of argbuf: %s\n", argbuf); ); return verifyErrorInLoadInitialArgs(v, "unrecognized first character in parameter type descriptor", argbuf); } } /* success! */ gc_free(argbuf); return(true);#undef LOCAL_OVERFLOW_ERROR#undef VERIFY_ERROR}/* * returns a pointer to the first character of the method's return value * in the method's type descriptor. */const char*getMethodReturnSig(const Method* method){ const char* sig = METHOD_SIGD(method); /* skip the type parameters */ for (sig++; *sig != ')'; sig = parseFieldTypeDescriptor(sig)); sig++; return sig;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -