static bool replaceFailingInstruction(Method* meth, InsnFlags* insnFlags,
int insnIdx, VerifyError failure)
{
+ VerifyErrorRefType refType;
const u2* oldInsns = meth->insns + insnIdx;
u2 oldInsn = *oldInsns;
bool result = false;
case OP_INSTANCE_OF:
case OP_NEW_INSTANCE:
case OP_NEW_ARRAY:
-
case OP_FILLED_NEW_ARRAY: // insn[1] == class ref, 3 bytes
case OP_FILLED_NEW_ARRAY_RANGE:
+ refType = VERIFY_ERROR_REF_CLASS;
+ break;
case OP_IGET: // insn[1] == field ref, 2 bytes
case OP_IGET_BOOLEAN:
case OP_SPUT_SHORT:
case OP_SPUT_WIDE:
case OP_SPUT_OBJECT:
+ refType = VERIFY_ERROR_REF_FIELD;
+ break;
case OP_INVOKE_VIRTUAL: // insn[1] == method ref, 3 bytes
case OP_INVOKE_VIRTUAL_RANGE:
case OP_INVOKE_STATIC_RANGE:
case OP_INVOKE_INTERFACE:
case OP_INVOKE_INTERFACE_RANGE:
+ refType = VERIFY_ERROR_REF_METHOD;
break;
+
default:
/* could handle this in a generic way, but this is probably safer */
LOG_VFY("GLITCH: verifier asked to replace opcode 0x%02x\n",
}
/* encode the opcode, with the failure code in the high byte */
- newInsns[0] = OP_THROW_VERIFICATION_ERROR | (failure << 8);
+ newInsns[0] = OP_THROW_VERIFICATION_ERROR |
+ (failure << 8) | (refType << (8 + kVerifyErrorRefTypeShift));
result = true;
VERIFY_ERROR_NONE = 0, /* no error; must be zero */
VERIFY_ERROR_GENERIC, /* VerifyError */
- VERIFY_ERROR_NO_CLASS, /* NoClassDefFoundError (ref=class) */
- VERIFY_ERROR_NO_FIELD, /* NoSuchFieldError (ref=field) */
- VERIFY_ERROR_NO_METHOD, /* NoSuchMethodError (ref=method) */
- VERIFY_ERROR_ACCESS_CLASS, /* IllegalAccessError (ref=class) */
- VERIFY_ERROR_ACCESS_FIELD, /* IllegalAccessError (ref=field) */
- VERIFY_ERROR_ACCESS_METHOD, /* IllegalAccessError (ref=method) */
- VERIFY_ERROR_CLASS_CHANGE, /* IncompatibleClassChangeError (ref=class) */
- VERIFY_ERROR_INSTANTIATION, /* InstantiationError (ref=class) */
+ VERIFY_ERROR_NO_CLASS, /* NoClassDefFoundError */
+ VERIFY_ERROR_NO_FIELD, /* NoSuchFieldError */
+ VERIFY_ERROR_NO_METHOD, /* NoSuchMethodError */
+ VERIFY_ERROR_ACCESS_CLASS, /* IllegalAccessError */
+ VERIFY_ERROR_ACCESS_FIELD, /* IllegalAccessError */
+ VERIFY_ERROR_ACCESS_METHOD, /* IllegalAccessError */
+ VERIFY_ERROR_CLASS_CHANGE, /* IncompatibleClassChangeError */
+ VERIFY_ERROR_INSTANTIATION, /* InstantiationError */
} VerifyError;
+/*
+ * Identifies the type of reference in the instruction that generated the
+ * verify error (e.g. VERIFY_ERROR_ACCESS_CLASS could come from a method,
+ * field, or class reference).
+ *
+ * This must fit in two bits.
+ */
+typedef enum VerifyErrorRefType {
+ VERIFY_ERROR_REF_CLASS = 0,
+ VERIFY_ERROR_REF_FIELD = 1,
+ VERIFY_ERROR_REF_METHOD = 2,
+} VerifyErrorRefType;
+
+#define kVerifyErrorRefTypeShift 6
+
#define VERIFY_OK(_failure) ((_failure) == VERIFY_ERROR_NONE)
/*
* Each returns a newly-allocated string.
*/
#define kThrowShow_accessFromClass 1
-static char* classNameFromIndex(const Method* method, int ref, int flags)
+static char* classNameFromIndex(const Method* method, int ref,
+ VerifyErrorRefType refType, int flags)
{
static const int kBufLen = 256;
const DvmDex* pDvmDex = method->clazz->pDvmDex;
+
+ if (refType == VERIFY_ERROR_REF_FIELD) {
+ /* get class ID from field ID */
+ const DexFieldId* pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
+ ref = pFieldId->classIdx;
+ } else if (refType == VERIFY_ERROR_REF_METHOD) {
+ /* get class ID from method ID */
+ const DexMethodId* pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
+ ref = pMethodId->classIdx;
+ }
+
const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, ref);
char* dotClassName = dvmDescriptorToDot(className);
if (flags == 0)
free(dotClassName);
return result;
}
-static char* fieldNameFromIndex(const Method* method, int ref, int flags)
+static char* fieldNameFromIndex(const Method* method, int ref,
+ VerifyErrorRefType refType, int flags)
{
static const int kBufLen = 256;
const DvmDex* pDvmDex = method->clazz->pDvmDex;
const char* className;
const char* fieldName;
+ if (refType != VERIFY_ERROR_REF_FIELD) {
+ LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_FIELD, refType);
+ return NULL; /* no message */
+ }
+
pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
className = dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->classIdx);
fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
free(dotName);
return result;
}
-static char* methodNameFromIndex(const Method* method, int ref, int flags)
+static char* methodNameFromIndex(const Method* method, int ref,
+ VerifyErrorRefType refType, int flags)
{
static const int kBufLen = 384;
const DvmDex* pDvmDex = method->clazz->pDvmDex;
const char* className;
const char* methodName;
+ if (refType != VERIFY_ERROR_REF_METHOD) {
+ LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_METHOD,refType);
+ return NULL; /* no message */
+ }
+
pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
className = dexStringByTypeIdx(pDvmDex->pDexFile, pMethodId->classIdx);
methodName = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
* This is used by the invoke-verification-error instruction. It always
* throws an exception.
*
- * "kind" indicates the kind of failure encountered by the verifier. The
- * meaning of "ref" is kind-specific; it's usually an index to a
- * class, field, or method reference.
+ * "kind" indicates the kind of failure encountered by the verifier. It
+ * has two parts, an error code and an indication of the reference type.
*/
void dvmThrowVerificationError(const Method* method, int kind, int ref)
{
+ const int typeMask = 0xff << kVerifyErrorRefTypeShift;
+ VerifyError errorKind = kind & ~typeMask;
+ VerifyErrorRefType refType = kind >> kVerifyErrorRefTypeShift;
const char* exceptionName = "Ljava/lang/VerifyError;";
char* msg = NULL;
- switch ((VerifyError) kind) {
+ switch ((VerifyError) errorKind) {
case VERIFY_ERROR_NO_CLASS:
exceptionName = "Ljava/lang/NoClassDefFoundError;";
- msg = classNameFromIndex(method, ref, 0);
+ msg = classNameFromIndex(method, ref, refType, 0);
break;
case VERIFY_ERROR_NO_FIELD:
exceptionName = "Ljava/lang/NoSuchFieldError;";
- msg = fieldNameFromIndex(method, ref, 0);
+ msg = fieldNameFromIndex(method, ref, refType, 0);
break;
case VERIFY_ERROR_NO_METHOD:
exceptionName = "Ljava/lang/NoSuchMethodError;";
- msg = methodNameFromIndex(method, ref, 0);
+ msg = methodNameFromIndex(method, ref, refType, 0);
break;
case VERIFY_ERROR_ACCESS_CLASS:
exceptionName = "Ljava/lang/IllegalAccessError;";
- msg = classNameFromIndex(method, ref, kThrowShow_accessFromClass);
+ msg = classNameFromIndex(method, ref, refType,
+ kThrowShow_accessFromClass);
break;
case VERIFY_ERROR_ACCESS_FIELD:
exceptionName = "Ljava/lang/IllegalAccessError;";
- msg = fieldNameFromIndex(method, ref, kThrowShow_accessFromClass);
+ msg = fieldNameFromIndex(method, ref, refType,
+ kThrowShow_accessFromClass);
break;
case VERIFY_ERROR_ACCESS_METHOD:
exceptionName = "Ljava/lang/IllegalAccessError;";
- msg = methodNameFromIndex(method, ref, kThrowShow_accessFromClass);
+ msg = methodNameFromIndex(method, ref, refType,
+ kThrowShow_accessFromClass);
break;
case VERIFY_ERROR_CLASS_CHANGE:
exceptionName = "Ljava/lang/IncompatibleClassChangeError;";
- msg = classNameFromIndex(method, ref, 0);
+ msg = classNameFromIndex(method, ref, refType, 0);
break;
case VERIFY_ERROR_INSTANTIATION:
exceptionName = "Ljava/lang/InstantiationError;";
- msg = classNameFromIndex(method, ref, 0);
+ msg = classNameFromIndex(method, ref, refType, 0);
break;
case VERIFY_ERROR_GENERIC: