#include "bcvcfr.h"
#include "bcverify.h"
#include "bcverify_internal.h"
#include "cfreader.h"
#include "j9protos.h"
#include "j9consts.h"
#include "vrfyconvert.h"
#include "j9cp.h"
#include "j9bcvnls.h"
#include "rommeth.h"
#include "ut_j9bcverify.h"
#define SUPERCLASS(clazz) ((clazz)->superclasses[ J9CLASS_DEPTH(clazz) - 1 ])
#define J9CLASS_INDEX_FROM_CLASS_ENTRY(clazz) ((clazz & BCV_CLASS_INDEX_MASK) >> BCV_CLASS_INDEX_SHIFT)
#define J9CLASS_ARITY_FROM_CLASS_ENTRY(clazz) (((clazz & BCV_ARITY_MASK) >> BCV_ARITY_SHIFT) + ((clazz & BCV_TAG_BASE_ARRAY_OR_NULL) >> 1))
#define CLONEABLE_CLASS_NAME "java/lang/Cloneable"
#define SERIALIZEABLE_CLASS_NAME "java/io/Serializable"
#define CLONEABLE_CLASS_NAME_LENGTH (sizeof(CLONEABLE_CLASS_NAME) - 1)
#define SERIALIZEABLE_CLASS_NAME_LENGTH (sizeof(SERIALIZEABLE_CLASS_NAME) - 1)
static VMINLINE UDATA compareTwoUTF8s (J9UTF8 * first, J9UTF8 * second);
static UDATA addClassName (J9BytecodeVerificationData * verifyData, U_8 * name, UDATA length, UDATA index);
static void getNameAndLengthFromClassNameList (J9BytecodeVerificationData *verifyData, UDATA listIndex, U_8 ** name, UDATA * length);
static IDATA findFieldFromRamClass (J9Class ** ramClass, J9ROMFieldRef * field, UDATA firstSearch);
static IDATA findMethodFromRamClass (J9BytecodeVerificationData * verifyData, J9Class ** ramClass, J9ROMNameAndSignature * method, UDATA firstSearch);
static VMINLINE UDATA * pushType (J9BytecodeVerificationData *verifyData, U_8 * signature, UDATA * stackTop);
static IDATA isRAMClassCompatible(J9BytecodeVerificationData *verifyData, U_8* parentClass, UDATA parentLength, U_8* childClass, UDATA childLength, IDATA *reasonCode);
J9_DECLARE_CONSTANT_UTF8(j9_vrfy_Object, "java/lang/Object");
J9_DECLARE_CONSTANT_UTF8(j9_vrfy_String, "java/lang/String");
J9_DECLARE_CONSTANT_UTF8(j9_vrfy_Throwable, "java/lang/Throwable");
J9_DECLARE_CONSTANT_UTF8(j9_vrfy_Class, "java/lang/Class");
J9_DECLARE_CONSTANT_UTF8(j9_vrfy_MethodType, "java/lang/invoke/MethodType");
J9_DECLARE_CONSTANT_UTF8(j9_vrfy_MethodHandle, "java/lang/invoke/MethodHandle");
static UDATA
addClassName(J9BytecodeVerificationData * verifyData, U_8 * name, UDATA length, UDATA index)
{
J9ROMClass * romClass = verifyData->romClass;
U_32 *offset;
J9UTF8 *utf8;
UDATA classNameInClass = TRUE;
UDATA newSize, i, delta;
U_8 *newBuffer;
PORT_ACCESS_FROM_PORT(verifyData->portLib);
if ((verifyData->classNameSegmentFree + sizeof(UDATA) + sizeof(J9UTF8) + length + sizeof(UDATA)) >= verifyData->classNameSegmentEnd) {
newSize = (UDATA) (((length + sizeof(UDATA) + sizeof(J9UTF8) + sizeof(UDATA)) < (32 * (sizeof(UDATA) + sizeof(J9UTF8))))
? (32 * (sizeof(UDATA) + sizeof(J9UTF8)))
: (length + sizeof(UDATA) + sizeof(J9UTF8) + sizeof(UDATA) - 1) & ~(sizeof(UDATA) - 1));
delta = (UDATA) (verifyData->classNameSegmentFree - verifyData->classNameSegment);
newSize += verifyData->classNameSegmentEnd - verifyData->classNameSegment;
newBuffer = j9mem_allocate_memory( newSize , J9MEM_CATEGORY_CLASSES);
if( !newBuffer ) {
return BCV_ERR_INSUFFICIENT_MEMORY;
}
verifyData->classNameSegmentFree = newBuffer + delta;
memcpy( newBuffer, verifyData->classNameSegment, (UDATA) (verifyData->classNameSegmentEnd - verifyData->classNameSegment) );
delta = (UDATA) ((newBuffer - verifyData->classNameSegment) / sizeof (J9UTF8));
bcvfree( verifyData, verifyData->classNameSegment );
i = 0;
while (verifyData->classNameList[i]) {
if (((U_8 *)(verifyData->classNameList[i]) >= verifyData->classNameSegment) && ((U_8 *)(verifyData->classNameList[i]) < verifyData->classNameSegmentEnd)) {
verifyData->classNameList[i] += delta;
}
i++;
}
verifyData->classNameSegment = newBuffer;
verifyData->classNameSegmentEnd = newBuffer + newSize;
}
if (&(verifyData->classNameList[index + 1]) >= verifyData->classNameListEnd) {
newSize = (UDATA) ((U_8 *) verifyData->classNameListEnd - (U_8 *) verifyData->classNameList + (32 * sizeof(UDATA)));
newBuffer = j9mem_allocate_memory( newSize , J9MEM_CATEGORY_CLASSES);
if( !newBuffer ) {
return BCV_ERR_INSUFFICIENT_MEMORY;
}
memcpy( newBuffer, (U_8*) verifyData->classNameList, (UDATA) (((U_8*) verifyData->classNameListEnd) - ((U_8*) verifyData->classNameList)) );
bcvfree( verifyData, verifyData->classNameList );
verifyData->classNameList = (J9UTF8 **) newBuffer;
verifyData->classNameListEnd = (J9UTF8 **) (newBuffer + newSize);
}
if (((UDATA) name < (UDATA) romClass) || ((UDATA) name >= ((UDATA) romClass + (UDATA) romClass->romSize))) {
classNameInClass = FALSE;
}
offset = (U_32 *) verifyData->classNameSegmentFree;
utf8 = (J9UTF8 *) (offset + 1);
J9UTF8_SET_LENGTH(utf8, (U_16) length);
verifyData->classNameSegmentFree += sizeof(U_32);
if (classNameInClass) {
offset[0] = (U_32) ((UDATA) name - (UDATA) romClass);
verifyData->classNameSegmentFree += sizeof(U_32);
} else {
offset[0] = 0;
strncpy((char *) J9UTF8_DATA(utf8), (char *) name, length);
verifyData->classNameSegmentFree += (sizeof(J9UTF8) + length + sizeof(U_32) - 1) & ~(sizeof(U_32) - 1);
}
verifyData->classNameList[index] = (J9UTF8 *) offset;
verifyData->classNameList[index + 1] = NULL;
return index;
}
UDATA
findClassName(J9BytecodeVerificationData * verifyData, U_8 * name, UDATA length)
{
J9ROMClass * romClass = verifyData->romClass;
U_32 *offset = NULL;
U_8 *data = NULL;
J9UTF8 *utf8 = NULL;
UDATA index = 0;
while ((offset = (U_32 *) verifyData->classNameList[index]) != NULL) {
utf8 = (J9UTF8 *) (offset + 1);
if ((UDATA) J9UTF8_LENGTH(utf8) == length) {
data = (U_8 *) ((UDATA) offset[0] + (UDATA) romClass);
if (data == name) {
return index;
}
if (0 == offset[0]) {
data = J9UTF8_DATA(utf8);
}
if (0 == memcmp(data, name, length)) {
return index;
}
}
index++;
}
return addClassName(verifyData, name, length, index);
}
UDATA
convertClassNameToStackMapType(J9BytecodeVerificationData * verifyData, U_8 *name, U_16 length, UDATA type, UDATA arity)
{
J9ROMClass * romClass = verifyData->romClass;
U_32 *offset = NULL;
U_8 *data = NULL;
J9UTF8 *utf8 = NULL;
J9UTF8 *utf8_p = NULL;
UDATA index = 0;
while ((offset = (U_32 *) verifyData->classNameList[index]) != NULL) {
utf8 = (J9UTF8 *) (offset + 1);
if ((UDATA) J9UTF8_LENGTH(utf8) == (UDATA)length) {
data = (U_8 *) ((UDATA) offset[0] + (UDATA) romClass);
if (data == name) {
return type | (index << BCV_CLASS_INDEX_SHIFT);
}
if (0 == offset[0]) {
data = J9UTF8_DATA(utf8);
}
if (0 == memcmp(data, name, (UDATA)length)) {
return type | (index << BCV_CLASS_INDEX_SHIFT);
}
}
index++;
}
return type | (addClassName(verifyData, name, length, index) << BCV_CLASS_INDEX_SHIFT);
}
BOOLEAN
buildStackFromMethodSignature( J9BytecodeVerificationData *verifyData, UDATA **stackTopPtr, UDATA *argCount)
{
const J9ROMClass *romClass = verifyData->romClass;
const J9ROMMethod *romMethod = verifyData->romMethod;
const UDATA argMax = J9_ARG_COUNT_FROM_ROM_METHOD(romMethod);
UDATA i;
U_8 *args;
UDATA arity, baseType;
UDATA classIndex = 0;
UDATA *stackTop;
BOOLEAN isUninitializedThis = FALSE;
stackTop = *stackTopPtr;
*argCount = 0;
if ((!(romMethod->modifiers & J9AccStatic)) && (argMax > 0)) {
J9UTF8* utf8string = J9ROMMETHOD_NAME(romMethod);
J9UTF8 *className = J9ROMCLASS_CLASSNAME(romClass);
classIndex = findClassName(verifyData, J9UTF8_DATA(className), J9UTF8_LENGTH(className));
if ((J9UTF8_DATA(utf8string)[0] == '<') && (J9UTF8_DATA(utf8string)[1] == 'i') && (classIndex != BCV_JAVA_LANG_OBJECT_INDEX)) {
PUSH(BCV_SPECIAL_INIT | (classIndex << BCV_CLASS_INDEX_SHIFT));
isUninitializedThis = TRUE;
} else {
PUSH(BCV_GENERIC_OBJECT | (classIndex << BCV_CLASS_INDEX_SHIFT));
}
(*argCount)++;
}
args = J9UTF8_DATA(J9ROMMETHOD_SIGNATURE(romMethod));
for (i = 1; args[i] != ')'; i++) {
(*argCount)++;
if ((*argCount) > argMax) {
continue;
}
arity = 0;
while (args[i] == '[') {
i++;
arity++;
}
if (IS_REF_OR_VAL_SIGNATURE(args[i])) {
U_8 *string;
U_16 length = 0;
i++;
string = &args[i];
while (args[i] != ';') {
i++;
length++;
}
classIndex = convertClassNameToStackMapType(verifyData, string, length, 0, arity);
PUSH(classIndex | (arity << BCV_ARITY_SHIFT));
} else {
if (arity) {
arity--;
PUSH(BCV_TAG_BASE_ARRAY_OR_NULL | (UDATA) baseTypeCharConversion[args[i] - 'A'] | (arity << BCV_ARITY_SHIFT));
} else {
baseType = (UDATA) argTypeCharConversion[args[i] - 'A'];
PUSH(baseType);
if ((args[i] == 'J') || (args[i] == 'D')) {
(*argCount)++;
PUSH(BCV_BASE_TYPE_TOP);
}
}
}
}
for (i = 0; i < J9_TEMP_COUNT_FROM_ROM_METHOD(romMethod); i++) {
PUSH (BCV_BASE_TYPE_TOP);
}
*stackTopPtr = stackTop;
return isUninitializedThis;
}
UDATA*
pushReturnType(J9BytecodeVerificationData *verifyData, J9UTF8 * utf8string, UDATA * stackTop)
{
U_8 *signature;
signature = J9UTF8_DATA(utf8string);
while (*signature++ != ')');
return pushType(verifyData, signature, stackTop);
}
UDATA*
pushFieldType(J9BytecodeVerificationData *verifyData, J9UTF8 * utf8string, UDATA *stackTop)
{
return pushType(verifyData, J9UTF8_DATA(utf8string), stackTop);
}
UDATA *
pushClassType(J9BytecodeVerificationData * verifyData, J9UTF8 * utf8string, UDATA * stackTop)
{
if (J9UTF8_DATA(utf8string)[0] == '[') {
UDATA arrayType = parseObjectOrArrayName(verifyData, J9UTF8_DATA(utf8string));
PUSH(arrayType);
} else {
PUSH(convertClassNameToStackMapType(verifyData, J9UTF8_DATA(utf8string),J9UTF8_LENGTH(utf8string), BCV_OBJECT_OR_ARRAY, 0));
}
return stackTop;
}
void
initializeClassNameList(J9BytecodeVerificationData *verifyData)
{
J9UTF8 *name;
verifyData->classNameSegmentFree = verifyData->classNameSegment;
verifyData->classNameList[0] = NULL;
name = (J9UTF8*)&j9_vrfy_Object;
findClassName( verifyData, J9UTF8_DATA(name), J9UTF8_LENGTH(name));
name = (J9UTF8*)&j9_vrfy_String;
findClassName( verifyData, J9UTF8_DATA(name), J9UTF8_LENGTH(name));
name = (J9UTF8*)&j9_vrfy_Throwable;
findClassName( verifyData, J9UTF8_DATA(name), J9UTF8_LENGTH(name));
name = (J9UTF8*)&j9_vrfy_Class;
findClassName( verifyData, J9UTF8_DATA(name), J9UTF8_LENGTH(name));
name = (J9UTF8*)&j9_vrfy_MethodType;
findClassName( verifyData, J9UTF8_DATA(name), J9UTF8_LENGTH(name));
name = (J9UTF8*)&j9_vrfy_MethodHandle;
findClassName( verifyData, J9UTF8_DATA(name), J9UTF8_LENGTH(name));
}
UDATA *
pushLdcType(J9BytecodeVerificationData *verifyData, J9ROMClass * romClass, UDATA index, UDATA * stackTop)
{
switch(J9_CP_TYPE(J9ROMCLASS_CPSHAPEDESCRIPTION(romClass), index)) {
case J9CPTYPE_CLASS:
PUSH(BCV_JAVA_LANG_CLASS_INDEX << BCV_CLASS_INDEX_SHIFT);
break;
case J9CPTYPE_STRING:
PUSH(BCV_JAVA_LANG_STRING_INDEX << BCV_CLASS_INDEX_SHIFT);
break;
case J9CPTYPE_INT:
PUSH_INTEGER_CONSTANT;
break;
case J9CPTYPE_FLOAT:
PUSH_FLOAT_CONSTANT;
break;
case J9CPTYPE_METHOD_TYPE:
PUSH(BCV_JAVA_LANG_INVOKE_METHOD_TYPE_INDEX << BCV_CLASS_INDEX_SHIFT);
break;
case J9CPTYPE_METHODHANDLE:
PUSH(BCV_JAVA_LANG_INVOKE_METHODHANDLE_INDEX << BCV_CLASS_INDEX_SHIFT);
break;
case J9CPTYPE_CONSTANT_DYNAMIC:
{
J9ROMConstantDynamicRef* romConstantDynamicRef = (J9ROMConstantDynamicRef *)(J9_ROM_CP_FROM_ROM_CLASS(romClass) + index);
J9UTF8 *signature = J9ROMNAMEANDSIGNATURE_SIGNATURE(J9ROMCONSTANTDYNAMICREF_NAMEANDSIGNATURE(romConstantDynamicRef));
stackTop = pushType(verifyData, J9UTF8_DATA(signature), stackTop);
}
break;
}
return stackTop;
}
IDATA
isClassCompatible(J9BytecodeVerificationData *verifyData, UDATA sourceClass, UDATA targetClass, IDATA *reasonCode)
{
UDATA sourceIndex, targetIndex;
UDATA sourceArity, targetArity;
IDATA rc;
U_8 *sourceName, *targetName;
UDATA sourceLength, targetLength;
BOOLEAN classRelationshipVerifierEnabled = J9_ARE_ANY_BITS_SET(verifyData->vmStruct->javaVM->extendedRuntimeFlags2, J9_EXTENDED_RUNTIME2_ENABLE_CLASS_RELATIONSHIP_VERIFIER);
*reasonCode = 0;
if( sourceClass == targetClass ) {
return (IDATA) TRUE;
}
if( sourceClass == BCV_BASE_TYPE_NULL ) {
return (IDATA) TRUE;
}
if( sourceClass & BCV_BASE_OR_SPECIAL ) {
return (IDATA) FALSE;
}
if( targetClass == (BCV_JAVA_LANG_OBJECT_INDEX << BCV_CLASS_INDEX_SHIFT) ) {
return (IDATA) TRUE;
}
if ( targetClass == BCV_BASE_TYPE_NULL ) {
return (IDATA) FALSE;
}
sourceArity = J9CLASS_ARITY_FROM_CLASS_ENTRY(sourceClass);
targetArity = J9CLASS_ARITY_FROM_CLASS_ENTRY(targetClass);
if( targetArity > sourceArity ) {
return (IDATA) FALSE;
}
sourceIndex = J9CLASS_INDEX_FROM_CLASS_ENTRY(sourceClass);
targetIndex = J9CLASS_INDEX_FROM_CLASS_ENTRY(targetClass);
if( targetArity < sourceArity ) {
if (targetClass & BCV_TAG_BASE_ARRAY_OR_NULL) {
return (IDATA) FALSE;
}
if (targetIndex == BCV_JAVA_LANG_OBJECT_INDEX) {
return (IDATA) TRUE;
}
getNameAndLengthFromClassNameList (verifyData, targetIndex, &targetName, &targetLength);
if (J9UTF8_DATA_EQUALS(targetName, targetLength, CLONEABLE_CLASS_NAME, CLONEABLE_CLASS_NAME_LENGTH)
|| J9UTF8_DATA_EQUALS(targetName, targetLength, SERIALIZEABLE_CLASS_NAME, SERIALIZEABLE_CLASS_NAME_LENGTH)
) {
rc = isInterfaceClass(verifyData, targetName, targetLength, reasonCode);
if ((classRelationshipVerifierEnabled) && (BCV_ERR_CLASS_RELATIONSHIP_RECORD_REQUIRED == *reasonCode)) {
getNameAndLengthFromClassNameList (verifyData, sourceIndex, &sourceName, &sourceLength);
rc = j9bcv_recordClassRelationship (verifyData->vmStruct, verifyData->classLoader, sourceName, sourceLength, targetName, targetLength, reasonCode);
}
return rc;
}
return (IDATA) FALSE;
}
if( (sourceClass & BCV_TAG_BASE_ARRAY_OR_NULL) || (targetClass & BCV_TAG_BASE_ARRAY_OR_NULL) ) {
return (IDATA) FALSE;
}
if (targetIndex == BCV_JAVA_LANG_OBJECT_INDEX) {
return (IDATA) TRUE;
}
getNameAndLengthFromClassNameList (verifyData, targetIndex, &targetName, &targetLength);
rc = isInterfaceClass(verifyData, targetName, targetLength, reasonCode);
getNameAndLengthFromClassNameList (verifyData, sourceIndex, &sourceName, &sourceLength);
if ((classRelationshipVerifierEnabled) && (BCV_ERR_CLASS_RELATIONSHIP_RECORD_REQUIRED == *reasonCode)) {
rc = j9bcv_recordClassRelationship(verifyData->vmStruct, verifyData->classLoader, sourceName, sourceLength, targetName, targetLength, reasonCode);
}
if ((IDATA) FALSE != rc) {
return rc;
}
if (NULL != verifyData->vmStruct->currentException) {
return (IDATA) FALSE;
}
if (J9ROMCLASS_IS_HIDDEN(verifyData->romClass)) {
J9UTF8* className = J9ROMCLASS_CLASSNAME(verifyData->romClass);
if (J9UTF8_DATA_EQUALS(J9UTF8_DATA(className), J9UTF8_LENGTH(className), sourceName, sourceLength)) {
J9UTF8* superClassName = J9ROMCLASS_SUPERCLASSNAME(verifyData->romClass);
sourceLength = J9UTF8_LENGTH(superClassName);
sourceName = J9UTF8_DATA(superClassName);
}
}
rc = isRAMClassCompatible(verifyData, targetName, targetLength , sourceName, sourceLength, reasonCode);
if ((classRelationshipVerifierEnabled) && (BCV_ERR_CLASS_RELATIONSHIP_RECORD_REQUIRED == *reasonCode)) {
rc = j9bcv_recordClassRelationship(verifyData->vmStruct, verifyData->classLoader, sourceName, sourceLength, targetName, targetLength, reasonCode);
}
return rc;
}
static IDATA
isRAMClassCompatible(J9BytecodeVerificationData *verifyData, U_8* parentClass, UDATA parentLength, U_8* childClass, UDATA childLength, IDATA *reasonCode)
{
J9Class *sourceRAMClass, *targetRAMClass;
targetRAMClass = j9rtv_verifierGetRAMClass( verifyData, verifyData->classLoader, parentClass, parentLength, reasonCode );
if (NULL == targetRAMClass) {
return FALSE;
}
if( targetRAMClass->romClass->modifiers & J9AccInterface ) {
return (IDATA) TRUE;
}
sourceRAMClass = j9rtv_verifierGetRAMClass( verifyData, verifyData->classLoader, childClass, childLength, reasonCode );
if (NULL == sourceRAMClass) {
return FALSE;
}
targetRAMClass = J9_CURRENT_CLASS(targetRAMClass);
return isSameOrSuperClassOf( targetRAMClass, sourceRAMClass );
}
IDATA
isInterfaceClass(J9BytecodeVerificationData * verifyData, U_8* className, UDATA classLength, IDATA *reasonCode)
{
J9Class *ramClass;
*reasonCode = 0;
ramClass = j9rtv_verifierGetRAMClass(verifyData, verifyData->classLoader, className, classLength, reasonCode);
if (NULL == ramClass) {
return FALSE;
}
if (ramClass->romClass->modifiers & J9AccInterface) {
return TRUE;
}
return FALSE;
}
static UDATA *
pushType(J9BytecodeVerificationData *verifyData, U_8 * signature, UDATA * stackTop)
{
if (*signature != 'V') {
if ((*signature == '[') || IS_REF_OR_VAL_SIGNATURE(*signature)) {
PUSH(parseObjectOrArrayName(verifyData, signature));
} else {
UDATA baseType = (UDATA) argTypeCharConversion[*signature - 'A'];
PUSH(baseType);
if ((*signature == 'J') || (*signature == 'D')) {
PUSH(BCV_BASE_TYPE_TOP);
}
}
}
return stackTop;
}
UDATA
getSpecialType(J9BytecodeVerificationData *verifyData, UDATA type, U_8* bytecodes)
{
J9ROMClass * romClass = verifyData->romClass;
J9UTF8* newClassUTF8;
if ((type & BCV_SPECIAL_NEW) == (UDATA) (BCV_SPECIAL_NEW)) {
U_8* bcTempPtr;
U_16 index;
J9ROMConstantPoolItem* constantPool;
bcTempPtr = bytecodes + ((type & BCV_CLASS_INDEX_MASK) >> BCV_CLASS_INDEX_SHIFT);
index = PARAM_16(bcTempPtr, 1);
constantPool = (J9ROMConstantPoolItem *) ((U_8 *) romClass + sizeof(J9ROMClass));
newClassUTF8 = J9ROMSTRINGREF_UTF8DATA((J9ROMStringRef *) (&constantPool[index]));
} else {
if ((type & BCV_SPECIAL_INIT) == (UDATA) (BCV_SPECIAL_INIT)) {
newClassUTF8 = J9ROMCLASS_CLASSNAME(romClass);
} else {
return type;
}
}
return convertClassNameToStackMapType(verifyData, J9UTF8_DATA(newClassUTF8), J9UTF8_LENGTH(newClassUTF8), 0, 0);
}
IDATA
isClassCompatibleByName(J9BytecodeVerificationData *verifyData, UDATA sourceClass, U_8* targetClassName, UDATA targetClassNameLength, IDATA *reasonCode)
{
UDATA index;
*reasonCode = 0;
if( sourceClass == BCV_BASE_TYPE_NULL )
return (IDATA) TRUE;
if( sourceClass & BCV_BASE_OR_SPECIAL )
return (IDATA) FALSE;
if (*targetClassName == '[') {
index = parseObjectOrArrayName(verifyData, targetClassName);
} else {
index = convertClassNameToStackMapType(verifyData, targetClassName, (U_16)targetClassNameLength, 0, 0);
}
return isClassCompatible(verifyData, sourceClass, index, reasonCode);
}
U_8 *
j9bcv_createVerifyErrorString(J9PortLibrary * portLib, J9BytecodeVerificationData * error)
{
const char *formatString;
const char *errorString;
U_8 *verifyError;
UDATA stringLength = 0;
U_8 byteArray[1024];
U_8* detailedErrMsg = NULL;
UDATA detailedErrMsgLength = 0;
PORT_ACCESS_FROM_PORT(portLib);
if ((IDATA) error->errorCode == -1) {
return NULL;
}
if ((IDATA)error->errorModule == -1) {
return NULL;
}
if ((IDATA) error->errorPC == -1) {
formatString = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_BCV_ERROR_TEMPLATE_NO_PC, "%s; class=%.*s, method=%.*s%.*s");
} else {
if (J9_ARE_ALL_BITS_SET(error->verificationFlags, J9_VERIFY_ERROR_DETAILS)
&& (0 != error->errorDetailCode)
) {
detailedErrMsg = byteArray;
detailedErrMsgLength = sizeof(byteArray);
detailedErrMsg = error->javaVM->verboseStruct->getRtvExceptionDetails(error, detailedErrMsg, &detailedErrMsgLength);
}
if (NULL == error->errorSignatureString) {
formatString = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_BCV_ERROR_TEMPLATE_WITH_PC, "%s; class=%.*s, method=%.*s%.*s, pc=%u");
} else {
formatString = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_BCV_ERROR_TEMPLATE_TYPE_MISMATCH,
"%s; class=%.*s, method=%.*s%.*s, pc=%u; Type Mismatch, argument %d in signature %.*s.%.*s:%.*s does not match");
}
}
errorString = OMRPORT_FROM_J9PORT(PORTLIB)->nls_lookup_message(OMRPORT_FROM_J9PORT(PORTLIB), J9NLS_DO_NOT_APPEND_NEWLINE, (U_32)(error->errorModule), (U_32)(error->errorCode), NULL);
stringLength = strlen(errorString);
stringLength += J9UTF8_LENGTH(J9ROMCLASS_CLASSNAME(error->romClass));
stringLength += J9UTF8_LENGTH(J9ROMMETHOD_NAME(error->romMethod));
stringLength += J9UTF8_LENGTH(J9ROMMETHOD_SIGNATURE(error->romMethod));
stringLength += 10;
if (NULL != error->errorSignatureString) {
stringLength += 10;
stringLength += J9UTF8_LENGTH(error->errorClassString);
stringLength += J9UTF8_LENGTH(error->errorMethodString);
stringLength += J9UTF8_LENGTH(error->errorSignatureString);
}
stringLength += strlen(formatString);
stringLength += detailedErrMsgLength;
verifyError = j9mem_allocate_memory(stringLength, J9MEM_CATEGORY_CLASSES);
if (NULL != verifyError) {
UDATA errStrLength = 0;
J9UTF8 * romClassName = J9ROMCLASS_CLASSNAME(error->romClass);
J9UTF8 * romMethodName = J9ROMMETHOD_NAME(error->romMethod);
J9UTF8 * romMethodSignatureString = J9ROMMETHOD_SIGNATURE(error->romMethod);
if (NULL == error->errorSignatureString) {
errStrLength = j9str_printf(PORTLIB, (char*) verifyError, stringLength, formatString, errorString,
(U_32) J9UTF8_LENGTH(romClassName), J9UTF8_DATA(romClassName),
(U_32) J9UTF8_LENGTH(romMethodName), J9UTF8_DATA(romMethodName),
(U_32) J9UTF8_LENGTH(romMethodSignatureString), J9UTF8_DATA(romMethodSignatureString),
error->errorPC);
} else {
errStrLength = j9str_printf(PORTLIB, (char*) verifyError, stringLength, formatString, errorString,
(U_32) J9UTF8_LENGTH(romClassName), J9UTF8_DATA(romClassName),
(U_32) J9UTF8_LENGTH(romMethodName), J9UTF8_DATA(romMethodName),
(U_32) J9UTF8_LENGTH(romMethodSignatureString), J9UTF8_DATA(romMethodSignatureString),
error->errorPC,
error->errorArgumentIndex,
(U_32) J9UTF8_LENGTH(error->errorClassString), J9UTF8_DATA(error->errorClassString),
(U_32) J9UTF8_LENGTH(error->errorMethodString), J9UTF8_DATA(error->errorMethodString),
(U_32) J9UTF8_LENGTH(error->errorSignatureString), J9UTF8_DATA(error->errorSignatureString));
}
if (detailedErrMsgLength > 0) {
j9str_printf(PORTLIB, (char*)&verifyError[errStrLength], stringLength - errStrLength, "%.*s", detailedErrMsgLength, detailedErrMsg);
}
}
if (detailedErrMsg != byteArray) {
j9mem_free_memory(detailedErrMsg);
}
RESET_VERIFY_ERROR(error);
return verifyError;
}
IDATA
isFieldAccessCompatible(J9BytecodeVerificationData * verifyData, J9ROMFieldRef * fieldRef, UDATA bytecode, UDATA receiver, IDATA *reasonCode)
{
J9ROMClass * romClass = verifyData->romClass;
J9ROMConstantPoolItem * constantPool = (J9ROMConstantPoolItem *) (romClass + 1);
J9UTF8 * utf8string = J9ROMCLASSREF_NAME((J9ROMClassRef *) &constantPool[fieldRef->classRefCPIndex]);
*reasonCode = 0;
if (bytecode == 181) {
if ((receiver & BCV_SPECIAL_INIT) == (UDATA) BCV_SPECIAL_INIT) {
J9UTF8 *classString = ((J9UTF8 *) J9ROMCLASS_CLASSNAME(romClass));
if (utf8string != classString) {
if (J9UTF8_LENGTH(utf8string) == J9UTF8_LENGTH(classString)) {
IDATA i;
for (i = (IDATA) (J9UTF8_LENGTH(utf8string) - 1); i >= 0; i--) {
if (J9UTF8_DATA(utf8string)[i] != J9UTF8_DATA(classString)[i]) {
break;
}
}
if (i < 0) {
return (IDATA) TRUE;
}
}
return (IDATA) FALSE;
} else {
return (IDATA) TRUE;
}
}
}
return isClassCompatibleByName(verifyData, receiver, J9UTF8_DATA(utf8string), J9UTF8_LENGTH(utf8string), reasonCode);
}
UDATA
isProtectedAccessPermitted(J9BytecodeVerificationData *verifyData, J9UTF8* declaringClassName, UDATA targetClass, void* member, UDATA isField, IDATA *reasonCode )
{
J9ROMClass * romClass = verifyData->romClass;
*reasonCode = 0;
if ((0 == (verifyData->vmStruct->javaVM->runtimeFlags & J9RuntimeFlagXfuture))
&& (0 == (verifyData->verificationFlags & J9_VERIFY_DO_PROTECTED_ACCESS_CHECK))
) {
return TRUE;
}
if (J9CLASS_ARITY_FROM_CLASS_ENTRY(targetClass) == 0) {
J9Class * definingRamClass;
J9Class * currentRamClass;
J9UTF8 * currentClassName;
IDATA rc;
currentClassName = J9ROMCLASS_CLASSNAME(romClass);
if (compareTwoUTF8s(declaringClassName, currentClassName)) {
return TRUE;
}
if (J9ROMCLASS_IS_HIDDEN(romClass)) {
currentClassName = J9ROMCLASS_SUPERCLASSNAME(romClass);
if (compareTwoUTF8s(declaringClassName, currentClassName)) {
return TRUE;
}
}
currentRamClass = j9rtv_verifierGetRAMClass (verifyData, verifyData->classLoader, J9UTF8_DATA(currentClassName), J9UTF8_LENGTH(currentClassName), reasonCode);
if ((NULL == currentRamClass) && (BCV_ERR_INSUFFICIENT_MEMORY == *reasonCode)) {
return FALSE;
}
definingRamClass = currentRamClass;
if (isField) {
rc = findFieldFromRamClass(&definingRamClass, (J9ROMFieldRef *) member, FALSE);
} else {
rc = findMethodFromRamClass(verifyData, &definingRamClass, (J9ROMNameAndSignature *) member, FALSE);
}
if (BCV_NOT_FOUND == rc) return TRUE;
definingRamClass = j9rtv_verifierGetRAMClass (verifyData, verifyData->classLoader, J9UTF8_DATA(declaringClassName), J9UTF8_LENGTH(declaringClassName), reasonCode);
if (NULL == definingRamClass) {
return FALSE;
}
if (!isSameOrSuperClassOf (definingRamClass, currentRamClass)) {
return TRUE;
}
if (isField) {
rc = findFieldFromRamClass(&definingRamClass, (J9ROMFieldRef *) member, TRUE);
} else {
rc = findMethodFromRamClass(verifyData, &definingRamClass, (J9ROMNameAndSignature *) member, TRUE);
}
if ((BCV_SUCCESS == rc) || (BCV_NOT_FOUND == rc)) {
return TRUE;
}
if (currentRamClass->packageID == definingRamClass->packageID) return TRUE;
if (isSameOrSuperClassOf(definingRamClass, currentRamClass)) {
U_8 * targetClassName = NULL;
UDATA targetClassLength = 0;
J9Class * targetRamClass = NULL;
if (targetClass != BCV_BASE_TYPE_NULL) {
getNameAndLengthFromClassNameList(verifyData, J9CLASS_INDEX_FROM_CLASS_ENTRY(targetClass), &targetClassName, &targetClassLength);
targetRamClass = j9rtv_verifierGetRAMClass(verifyData, verifyData->classLoader, targetClassName, targetClassLength, reasonCode);
if (NULL == targetRamClass) {
return FALSE;
}
if (J9ROMCLASS_IS_HIDDEN(romClass)) {
currentClassName = J9ROMCLASS_CLASSNAME(romClass);
if (!J9UTF8_DATA_EQUALS(targetClassName, targetClassLength, J9UTF8_DATA(currentClassName), J9UTF8_LENGTH(currentClassName))) {
return FALSE;
}
} else {
if (!isSameOrSuperClassOf(currentRamClass, targetRamClass)) {
return FALSE;
}
}
}
}
}
return TRUE;
}
static UDATA compareTwoUTF8s(J9UTF8 * first, J9UTF8 * second)
{
return J9UTF8_EQUALS(first, second);
}
static void getNameAndLengthFromClassNameList (J9BytecodeVerificationData *verifyData, UDATA listIndex, U_8 ** name, UDATA * length)
{
U_32 * offset;
offset = (U_32 *) verifyData->classNameList[listIndex];
*length = (U_32) J9UTF8_LENGTH(offset + 1);
if (offset[0] == 0) {
*name = J9UTF8_DATA(offset + 1);
} else {
J9ROMClass * romClass = verifyData->romClass;
*name = (U_8 *) ((UDATA) offset[0] + (UDATA) romClass);
}
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
if (IS_QTYPE(*(char *)*name)
&& (';' == *(char *)(*name + (*length - 1)))
) {
*name += 1;
*length -= 2;
}
#endif
}
static IDATA findFieldFromRamClass (J9Class ** ramClass, J9ROMFieldRef * field, UDATA firstSearch)
{
J9UTF8 * searchName = J9ROMNAMEANDSIGNATURE_NAME(J9ROMFIELDREF_NAMEANDSIGNATURE(field));
for (;;) {
J9ROMFieldShape * currentField;
J9ROMClass * romClass = (*ramClass)->romClass;
J9ROMFieldWalkState state;
currentField = romFieldsStartDo(romClass, &state);
while (currentField != NULL) {
if ((currentField->modifiers & J9AccStatic) == 0) {
if (compareTwoUTF8s(searchName, J9ROMFIELDSHAPE_NAME(currentField))) {
if (currentField->modifiers & CFR_ACC_PROTECTED) return BCV_FAIL;
if (firstSearch) return BCV_SUCCESS;
}
}
currentField = romFieldsNextDo(&state);
}
*ramClass = SUPERCLASS(*ramClass);
if (NULL == *ramClass) return BCV_NOT_FOUND;
}
}
static IDATA
findMethodFromRamClass(J9BytecodeVerificationData * verifyData, J9Class ** ramClass, J9ROMNameAndSignature * method, UDATA firstSearch)
{
J9UTF8 * searchName = J9ROMNAMEANDSIGNATURE_NAME(method);
J9UTF8 * searchSignature = J9ROMNAMEANDSIGNATURE_SIGNATURE(method);
for (;;) {
J9ROMClass * romClass = (*ramClass)->romClass;
UDATA redefinedClassIndex = 0;
J9UTF8 * currentClassName = J9ROMCLASS_CLASSNAME(romClass);
J9ROMMethod * currentRomMethod = NULL;
UDATA methodIndex = 0;
for (redefinedClassIndex = 0; redefinedClassIndex < verifyData->redefinedClassesCount; redefinedClassIndex++) {
J9ROMClass * currentRedefinedClass = verifyData->redefinedClasses[redefinedClassIndex].replacementClass.romClass;
Assert_RTV_true(NULL != currentRedefinedClass);
if (0 != compareTwoUTF8s(currentClassName, J9ROMCLASS_CLASSNAME(currentRedefinedClass))) {
romClass = currentRedefinedClass;
break;
}
}
currentRomMethod = J9ROMCLASS_ROMMETHODS(romClass);
for (methodIndex = 0; methodIndex < romClass->romMethodCount; methodIndex++) {
if ((0 != compareTwoUTF8s(searchName, J9ROMMETHOD_NAME(currentRomMethod)))
&& (0 != compareTwoUTF8s(searchSignature, J9ROMMETHOD_SIGNATURE(currentRomMethod)))
) {
if (currentRomMethod->modifiers & CFR_ACC_PROTECTED) return BCV_FAIL;
if (firstSearch) return BCV_SUCCESS;
}
currentRomMethod = J9_NEXT_ROM_METHOD(currentRomMethod);
}
*ramClass = SUPERCLASS(*ramClass);
if (NULL == *ramClass) return BCV_NOT_FOUND;
}
}
UDATA
parseObjectOrArrayName(J9BytecodeVerificationData *verifyData, U_8 *signature)
{
UDATA arity, arrayType;
U_8 *string = signature;
while (*signature == '[') {
signature++;
}
arity = (UDATA) (signature - string);
if (IS_REF_OR_VAL_SIGNATURE(*signature)) {
U_16 length = 0;
UDATA classIndex = 0;
signature++;
string = signature;
while (*signature++ != ';') {
length++;
}
arrayType = convertClassNameToStackMapType(verifyData, string, length, 0, arity);
} else {
arity--;
arrayType = (UDATA) (BCV_TAG_BASE_ARRAY_OR_NULL + (UDATA) baseTypeCharConversion[*signature - 'A']);
}
return arrayType | (arity << BCV_ARITY_SHIFT);
}
void
storeVerifyErrorData (J9BytecodeVerificationData * verifyData, I_16 errorDetailCode, U_32 errorCurrentFramePosition, UDATA errorTargetType, UDATA errorTempData, IDATA currentPC)
{
J9BranchTargetStack *liveStack = (J9BranchTargetStack *) verifyData->liveStack;
verifyData->errorDetailCode = errorDetailCode;
verifyData->errorCurrentFramePosition = errorCurrentFramePosition;
verifyData->errorTargetType = errorTargetType;
verifyData->errorTempData = errorTempData;
liveStack->pc = (UDATA)currentPC;
}