#include "cfreader.h"
#include "j9protos.h"
#include "j9user.h"
#include <string.h>
#include "ut_j9bcu.h"
#include "j9bcvnls.h"
#include "romphase.h"
#include "bcutil_internal.h"
#include "util_api.h"
#include "attrlookup.h"
static I_32 checkAttributes (J9PortLibrary* portLib, J9CfrClassFile* classfile, J9CfrAttribute** attributes, U_32 attributesCount, U_8* segment, I_32 maxBootstrapMethodIndex, U_32 extra, U_32 flags);
static I_32 readAttributes (J9CfrClassFile * classfile, J9CfrAttribute *** pAttributes, U_32 attributesCount, U_8 * data, U_8 * dataEnd, U_8 * segment, U_8 * segmentEnd, U_8 ** pIndex, U_8 ** pFreePointer, U_32 flags, UDATA * syntheticFound);
static I_32 checkFields (J9PortLibrary* portLib, J9CfrClassFile * classfile, U_8 * segment, U_32 flags);
static U_8 attributeTagFor (J9CfrConstantPoolInfo *utf8, BOOLEAN stripDebugAttributes);
static I_32 readAnnotations (J9CfrClassFile * classfile, J9CfrAnnotation * pAnnotations, U_32 annotationCount, U_8 * data, U_8 * dataEnd, U_8 * segment, U_8 * segmentEnd, U_8 ** pIndex, U_8 ** pFreePointer, U_32 flags);
static I_32 readTypeAnnotation (J9CfrClassFile * classfile, J9CfrTypeAnnotation * pAnnotations, U_8 * data, U_8 * dataEnd, U_8 * segment, U_8 * segmentEnd, U_8 ** pIndex, U_8 ** pFreePointer, U_32 flags);
static I_32 readAnnotationElement (J9CfrClassFile * classfile, J9CfrAnnotationElement ** pAnnotationElement, U_8 * data, U_8 * dataEnd, U_8 * segment, U_8 * segmentEnd, U_8 ** pIndex, U_8 ** pFreePointer, U_32 flags);
static I_32 checkClassVersion (J9CfrClassFile* classfile, U_8* segment, U_32 vmVersionShifted, U_32 flags);
static BOOLEAN utf8EqualUtf8 (J9CfrConstantPoolInfo *utf8a, J9CfrConstantPoolInfo *utf8b);
static BOOLEAN utf8Equal (J9CfrConstantPoolInfo* utf8, char* string, UDATA length);
static I_32 readMethods (J9CfrClassFile* classfile, U_8* data, U_8* dataEnd, U_8* segment, U_8* segmentEnd, U_8** pIndex, U_8** pFreePointer, U_32 flags);
static I_32 readPool (J9CfrClassFile* classfile, U_8* data, U_8* dataEnd, U_8* segment, U_8* segmentEnd, U_8** pIndex, U_8** pFreePointer);
static I_32 checkDuplicateMembers (J9PortLibrary* portLib, J9CfrClassFile * classfile, U_8 * segment, U_32 flags, UDATA memberSize);
static I_32 checkPool (J9CfrClassFile* classfile, U_8* segment, U_8* poolStart, I_32 *maxBootstrapMethodIndex, U_32 flags);
static I_32 checkClass (J9PortLibrary *portLib, J9CfrClassFile* classfile, U_8* segment, U_32 endOfConstantPool, U_32 vmVersionShifted, U_32 flags);
static I_32 readFields (J9CfrClassFile* classfile, U_8* data, U_8* dataEnd, U_8* segment, U_8* segmentEnd, U_8** pIndex, U_8** pFreePointer, U_32 flags);
static I_32 checkMethods (J9PortLibrary* portLib, J9CfrClassFile* classfile, U_8* segment, U_32 vmVersionShifted, U_32 flags);
static BOOLEAN memberEqual (J9CfrClassFile * classfile, J9CfrMember* a, J9CfrMember* b);
static void sortMethodIndex(J9CfrConstantPoolInfo* constantPool, J9CfrMethod *list, IDATA start, IDATA end);
static IDATA compareMethodIDs(J9CfrConstantPoolInfo* constantPool, J9CfrMethod *a, J9CfrMethod *b);
static U_8* getUTF8Data(J9CfrConstantPoolInfo* constantPool, U_16 cpIndex);
static U_16 getUTF8Length(J9CfrConstantPoolInfo* constantPool, U_16 cpIndex);
#define OUTSIDE_CODE ((U_32) -1)
#define DUP_TIMING 0
#define DUP_HASH_THRESHOLD 30
#define MAX_CONSTANT_POOL_SIZE 0xFFFF
static const U_8 cpTypeCharConversion[] = {
0, CFR_CONSTANT_Integer, CFR_CONSTANT_Integer, CFR_CONSTANT_Double,
0, CFR_CONSTANT_Float, 0, 0,
CFR_CONSTANT_Integer, CFR_CONSTANT_Long, 0, CFR_CONSTANT_String,
0, 0, 0, 0,
0, 0, CFR_CONSTANT_Integer, 0,
0, 0, 0, 0,
0, CFR_CONSTANT_Integer};
static BOOLEAN
utf8Equal(J9CfrConstantPoolInfo* utf8, char* string, UDATA length)
{
if ((utf8->tag !=CFR_CONSTANT_Utf8) || (utf8->slot1 != length)) {
return FALSE;
}
return memcmp(utf8->bytes, string, length) == 0;
}
static U_8
attributeTagFor(J9CfrConstantPoolInfo *utf8, BOOLEAN stripDebugAttributes)
{
const struct AttribType *attribType = lookupKnownAttribute((const char *)utf8->bytes, (unsigned int)utf8->slot1);
if (NULL != attribType) {
return (stripDebugAttributes ? attribType->strippedAttribCode : attribType->attribCode);
}
return (U_8) (stripDebugAttributes
? CFR_ATTRIBUTE_StrippedUnknown
: CFR_ATTRIBUTE_Unknown);
}
static I_32
readAttributes(J9CfrClassFile * classfile, J9CfrAttribute *** pAttributes, U_32 attributesCount, U_8 * data,
U_8 * dataEnd, U_8 * segment, U_8 * segmentEnd, U_8 ** pIndex, U_8 ** pFreePointer, U_32 flags, UDATA * syntheticFound)
{
J9CfrAttribute **attributes = *pAttributes;
U_8 *index = *pIndex;
U_8 *freePointer = *pFreePointer;
J9CfrConstantPoolInfo *info;
J9CfrAttribute *attrib;
J9CfrAttributeCode *code;
J9CfrAttributeExceptions *exceptions;
J9CfrExceptionTableEntry *exception;
J9CfrAttributeInnerClasses *classes;
J9CfrParameterAnnotations *parameterAnnotations;
J9CfrTypeAnnotation *typeAnnotations = NULL;
J9CfrAttributeStackMap *stackMap;
J9CfrAttributeBootstrapMethods *bootstrapMethods;
J9CfrAttributeRecord *record;
J9CfrAttributePermittedSubclasses *permittedSubclasses;
#if JAVA_SPEC_VERSION >= 11
J9CfrAttributeNestHost *nestHost;
J9CfrAttributeNestMembers *nestMembers;
#endif
U_32 name, length;
U_32 tag, errorCode, offset;
U_8 *end;
U_32 address;
U_32 i, j, k;
I_32 result;
BOOLEAN sourceFileAttributeRead = FALSE;
BOOLEAN bootstrapMethodAttributeRead = FALSE;
BOOLEAN visibleTypeAttributeRead = FALSE;
BOOLEAN invisibleTypeAttributeRead = FALSE;
BOOLEAN sourceDebugExtensionRead = FALSE;
BOOLEAN annotationDefaultRead = FALSE;
BOOLEAN visibleAnnotationsRead = FALSE;
BOOLEAN invisibleAnnotationsRead = FALSE;
BOOLEAN visibleParameterAnnotationsRead = FALSE;
BOOLEAN invisibleParameterAnnotationsRead = FALSE;
BOOLEAN recordAttributeRead = FALSE;
BOOLEAN permittedSubclassesAttributeRead = FALSE;
#if JAVA_SPEC_VERSION >= 11
BOOLEAN nestAttributeRead = FALSE;
#endif
if (NULL != syntheticFound) {
*syntheticFound = FALSE;
}
for (i = 0; i < attributesCount; i++) {
address = (U_32) (index - data);
CHECK_EOF(6);
NEXT_U16(name, index);
NEXT_U32(length, index);
end = index + length;
if ((!name) || (name >= classfile->constantPoolCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
offset = address;
goto _errorFound;
}
info = &classfile->constantPool[name];
if (info->tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_BAD_NAME_INDEX__ID;
offset = address;
goto _errorFound;
}
tag = attributeTagFor(info, (BOOLEAN) (flags & CFR_StripDebugAttributes));
switch (tag) {
case CFR_ATTRIBUTE_SourceFile:
if (sourceFileAttributeRead){
errorCode = J9NLS_CFR_ERR_FOUND_MULTIPLE_SOURCE_FILE_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
}
sourceFileAttributeRead = TRUE;
if (!ALLOC_CAST(attrib, J9CfrAttributeSourceFile, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(2);
NEXT_U16(((J9CfrAttributeSourceFile *) attrib)->sourceFileIndex, index);
break;
case CFR_ATTRIBUTE_Signature:
if (!ALLOC_CAST(attrib, J9CfrAttributeSignature, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(2);
NEXT_U16(((J9CfrAttributeSignature *) attrib)->signatureIndex, index);
break;
case CFR_ATTRIBUTE_ConstantValue:
if (!ALLOC_CAST(attrib, J9CfrAttributeConstantValue, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(2);
NEXT_U16(((J9CfrAttributeConstantValue *) attrib)->constantValueIndex, index);
break;
case CFR_ATTRIBUTE_Code:
if (!ALLOC(code, J9CfrAttributeCode)) {
return -2;
}
attrib = (J9CfrAttribute*)code;
CHECK_EOF(8);
NEXT_U16(code->maxStack, index);
NEXT_U16(code->maxLocals, index);
NEXT_U32(code->codeLength, index);
CHECK_EOF(code->codeLength);
if (!ALLOC_ARRAY(code->code, code->codeLength, U_8)) {
return -2;
}
code->originalCode = index;
memcpy (code->code, index, code->codeLength);
index += code->codeLength;
CHECK_EOF(2);
NEXT_U16(code->exceptionTableLength, index);
if (!ALLOC_ARRAY(code->exceptionTable, code->exceptionTableLength, J9CfrExceptionTableEntry)) {
return -2;
}
CHECK_EOF(code->exceptionTableLength << 3);
for (j = 0; j < code->exceptionTableLength; j++) {
exception = &(code->exceptionTable[j]);
NEXT_U16(exception->startPC, index);
NEXT_U16(exception->endPC, index);
NEXT_U16(exception->handlerPC, index);
NEXT_U16(exception->catchType, index);
}
CHECK_EOF(2);
NEXT_U16(code->attributesCount, index);
if (!ALLOC_ARRAY(code->attributes, code->attributesCount, J9CfrAttribute *)) {
return -2;
}
if ((result = readAttributes(classfile, &(code->attributes), code->attributesCount, data, dataEnd, segment, segmentEnd, &index, &freePointer, flags, NULL)) != 0) {
return result;
}
break;
case CFR_ATTRIBUTE_Exceptions:
if (!ALLOC(exceptions, J9CfrAttributeExceptions)) {
return -2;
}
attrib = (J9CfrAttribute*)exceptions;
CHECK_EOF(2);
NEXT_U16(exceptions->numberOfExceptions, index);
if (!ALLOC_ARRAY(exceptions->exceptionIndexTable, exceptions->numberOfExceptions, U_16)) {
return -2;
}
CHECK_EOF(exceptions->numberOfExceptions << 1);
for (j = 0; j < exceptions->numberOfExceptions; j++) {
NEXT_U16(exceptions->exceptionIndexTable[j], index);
}
break;
case CFR_ATTRIBUTE_LineNumberTable:
if (!ALLOC_CAST(attrib, J9CfrAttributeLineNumberTable, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(2);
NEXT_U16(((J9CfrAttributeLineNumberTable *) attrib)->lineNumberTableLength, index);
if (!ALLOC_ARRAY(
((J9CfrAttributeLineNumberTable *) attrib)->lineNumberTable,
((J9CfrAttributeLineNumberTable *) attrib)->lineNumberTableLength,
J9CfrLineNumberTableEntry)) {
return -2;
}
CHECK_EOF(((J9CfrAttributeLineNumberTable *) attrib)->lineNumberTableLength << 2);
for (j = 0; j < ((J9CfrAttributeLineNumberTable *) attrib)->lineNumberTableLength; j++) {
NEXT_U16(((J9CfrAttributeLineNumberTable *) attrib)->lineNumberTable[j].startPC, index);
NEXT_U16(((J9CfrAttributeLineNumberTable *) attrib)->lineNumberTable[j].lineNumber, index);
}
break;
case CFR_ATTRIBUTE_LocalVariableTable:
if (!ALLOC_CAST(attrib, J9CfrAttributeLocalVariableTable, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(2);
NEXT_U16(((J9CfrAttributeLocalVariableTable *) attrib)->localVariableTableLength, index);
if (!ALLOC_ARRAY(
((J9CfrAttributeLocalVariableTable *) attrib)->localVariableTable,
((J9CfrAttributeLocalVariableTable *) attrib)->localVariableTableLength,
J9CfrLocalVariableTableEntry)) {
return -2;
}
CHECK_EOF(((J9CfrAttributeLocalVariableTable *) attrib)->localVariableTableLength * 10);
for (j = 0; j < ((J9CfrAttributeLocalVariableTable *) attrib)->localVariableTableLength; j++) {
NEXT_U16(((J9CfrAttributeLocalVariableTable *) attrib)->localVariableTable[j].startPC, index);
NEXT_U16(((J9CfrAttributeLocalVariableTable *) attrib)->localVariableTable[j].length, index);
NEXT_U16(((J9CfrAttributeLocalVariableTable *) attrib)->localVariableTable[j].nameIndex, index);
NEXT_U16(((J9CfrAttributeLocalVariableTable *) attrib)->localVariableTable[j].descriptorIndex, index);
NEXT_U16(((J9CfrAttributeLocalVariableTable *) attrib)->localVariableTable[j].index, index);
}
break;
case CFR_ATTRIBUTE_LocalVariableTypeTable:
if (!ALLOC_CAST(attrib, J9CfrAttributeLocalVariableTypeTable, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(2);
NEXT_U16(((J9CfrAttributeLocalVariableTypeTable *) attrib)->localVariableTypeTableLength, index);
if (!ALLOC_ARRAY(
((J9CfrAttributeLocalVariableTypeTable *) attrib)->localVariableTypeTable,
((J9CfrAttributeLocalVariableTypeTable *) attrib)->localVariableTypeTableLength,
J9CfrLocalVariableTypeTableEntry)) {
return -2;
}
CHECK_EOF(((J9CfrAttributeLocalVariableTypeTable *) attrib)->localVariableTypeTableLength * 10);
for (j = 0; j < ((J9CfrAttributeLocalVariableTypeTable *) attrib)->localVariableTypeTableLength; j++) {
NEXT_U16(((J9CfrAttributeLocalVariableTypeTable *) attrib)->localVariableTypeTable[j].startPC, index);
NEXT_U16(((J9CfrAttributeLocalVariableTypeTable *) attrib)->localVariableTypeTable[j].length, index);
NEXT_U16(((J9CfrAttributeLocalVariableTypeTable *) attrib)->localVariableTypeTable[j].nameIndex, index);
NEXT_U16(((J9CfrAttributeLocalVariableTypeTable *) attrib)->localVariableTypeTable[j].signatureIndex, index);
NEXT_U16(((J9CfrAttributeLocalVariableTypeTable *) attrib)->localVariableTypeTable[j].index, index);
}
break;
case CFR_ATTRIBUTE_Synthetic:
if (!ALLOC_CAST(attrib, J9CfrAttributeSynthetic, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(length);
index += length;
if (NULL != syntheticFound) {
*syntheticFound = TRUE;
}
break;
case CFR_ATTRIBUTE_AnnotationDefault: {
if (annotationDefaultRead) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_ANNOTATION_DEFAULT_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
} else {
annotationDefaultRead = TRUE;
}
if (!ALLOC_CAST(attrib, J9CfrAttributeAnnotationDefault, J9CfrAttribute)) {
return -2;
}
result = readAnnotationElement(classfile, &((J9CfrAttributeAnnotationDefault *)attrib)->defaultValue,
data, dataEnd, segment, segmentEnd, &index, &freePointer, flags);
if (result != 0) {
return result;
}
}
break;
case CFR_ATTRIBUTE_RuntimeInvisibleAnnotations:
if (invisibleAnnotationsRead) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_ANNOTATION_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
} else {
invisibleAnnotationsRead = TRUE;
}
if (J9_ARE_NO_BITS_SET(flags, BCT_RetainRuntimeInvisibleAttributes)) {
if (!ALLOC(attrib, J9CfrAttribute)) {
return BCT_ERR_OUT_OF_ROM;
}
CHECK_EOF(length);
index += length;
break;
}
case CFR_ATTRIBUTE_RuntimeVisibleAnnotations: {
U_8 *attributeStart = index;
J9CfrAttributeRuntimeVisibleAnnotations *annotations = NULL;
if (CFR_ATTRIBUTE_RuntimeVisibleAnnotations == tag) {
if (visibleAnnotationsRead) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_ANNOTATION_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
}
visibleAnnotationsRead = TRUE;
}
if (!ALLOC_CAST(attrib, J9CfrAttributeRuntimeVisibleAnnotations, J9CfrAttribute)) {
return BCT_ERR_OUT_OF_ROM;
}
annotations = (J9CfrAttributeRuntimeVisibleAnnotations *)attrib;
annotations->numberOfAnnotations = 0;
annotations->annotations = NULL;
annotations->rawAttributeData = NULL;
annotations->rawDataLength = 0;
if (length > 1) {
CHECK_EOF(2);
NEXT_U16(annotations->numberOfAnnotations, index);
if (!ALLOC_ARRAY(annotations->annotations, annotations->numberOfAnnotations, J9CfrAnnotation)) {
return BCT_ERR_OUT_OF_ROM;
}
result = readAnnotations(classfile, annotations->annotations, annotations->numberOfAnnotations, data, dataEnd, segment, segmentEnd, &index, &freePointer, flags);
}
if (BCT_ERR_OUT_OF_ROM == result) {
return result;
} else if ((BCT_ERR_NO_ERROR != result) || (0 == length) || (index != end)) {
U_32 cursor = 0;
Trc_BCU_MalformedAnnotation(address);
if (BCT_ERR_INVALID_ANNOTATION_BAD_CP_INDEX_OUT_OF_RANGE == result) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
offset = address;
goto _errorFound;
} else if (BCT_ERR_INVALID_ANNOTATION_BAD_CP_UTF8_STRING == result) {
errorCode = J9NLS_CFR_ERR_BAD_NAME_INDEX__ID;
offset = address;
goto _errorFound;
}
if (0 == length) {
annotations->rawDataLength = 1;
if (!ALLOC_ARRAY(annotations->rawAttributeData, 1, U_8)) {
return BCT_ERR_OUT_OF_ROM;
}
annotations->rawAttributeData[0] = 0;
} else {
annotations->rawDataLength = length;
if (!ALLOC_ARRAY(annotations->rawAttributeData, length, U_8)) {
return BCT_ERR_OUT_OF_ROM;
}
index = attributeStart;
for (cursor = 0; cursor < annotations->rawDataLength; ++cursor) {
CHECK_EOF(1);
NEXT_U8(annotations->rawAttributeData[cursor], index);
}
}
}
}
break;
case CFR_ATTRIBUTE_MethodParameters:
if (!ALLOC_CAST(attrib, J9CfrAttributeMethodParameters, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(1);
NEXT_U8(((J9CfrAttributeMethodParameters *) attrib)->numberOfMethodParameters, index);
if (!ALLOC_ARRAY(
((J9CfrAttributeMethodParameters *) attrib)->methodParametersIndexTable,
((J9CfrAttributeMethodParameters *) attrib)->numberOfMethodParameters,
U_16)) {
return -2;
}
if (!ALLOC_ARRAY(
((J9CfrAttributeMethodParameters *) attrib)->flags,
((J9CfrAttributeMethodParameters *) attrib)->numberOfMethodParameters,
U_16)) {
return -2;
}
CHECK_EOF(((J9CfrAttributeMethodParameters *) attrib)->numberOfMethodParameters * 4);
for (j = 0; j < ((J9CfrAttributeMethodParameters *) attrib)->numberOfMethodParameters; j++) {
NEXT_U16(((J9CfrAttributeMethodParameters *) attrib)->methodParametersIndexTable[j], index);
NEXT_U16(((J9CfrAttributeMethodParameters *) attrib)->flags[j], index);
}
break;
case CFR_ATTRIBUTE_RuntimeInvisibleParameterAnnotations:
if (invisibleParameterAnnotationsRead) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_PARAMETER_ANNOTATION_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
} else {
invisibleParameterAnnotationsRead = TRUE;
}
if (J9_ARE_NO_BITS_SET(flags, BCT_RetainRuntimeInvisibleAttributes)) {
if (!ALLOC(attrib, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(length);
index += length;
break;
}
case CFR_ATTRIBUTE_RuntimeVisibleParameterAnnotations: {
U_8 *attributeStart = index;
J9CfrAttributeRuntimeVisibleParameterAnnotations *annotations = NULL;
if (CFR_ATTRIBUTE_RuntimeVisibleParameterAnnotations == tag) {
if (visibleParameterAnnotationsRead) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_PARAMETER_ANNOTATION_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
}
visibleParameterAnnotationsRead = TRUE;
}
if (!ALLOC_CAST(attrib, J9CfrAttributeRuntimeVisibleParameterAnnotations, J9CfrAttribute)) {
return -2;
}
annotations = (J9CfrAttributeRuntimeVisibleParameterAnnotations *)attrib;
annotations->rawAttributeData = NULL;
annotations->rawDataLength = 0;
CHECK_EOF(1);
NEXT_U8(annotations->numberOfParameters, index);
if (!ALLOC_ARRAY(annotations->parameterAnnotations, annotations->numberOfParameters, J9CfrParameterAnnotations)) {
return -2;
}
parameterAnnotations = annotations->parameterAnnotations;
for (j = 0; j < annotations->numberOfParameters; j++, parameterAnnotations++) {
CHECK_EOF(2);
NEXT_U16(parameterAnnotations->numberOfAnnotations, index);
if (!ALLOC_ARRAY(parameterAnnotations->annotations, parameterAnnotations->numberOfAnnotations, J9CfrAnnotation)) {
return -2;
}
result = readAnnotations(classfile, parameterAnnotations->annotations, parameterAnnotations->numberOfAnnotations, data, dataEnd,
segment, segmentEnd, &index, &freePointer, flags);
if (BCT_ERR_NO_ERROR != result) {
break;
}
}
if (BCT_ERR_OUT_OF_ROM == result) {
return result;
} else if ((BCT_ERR_NO_ERROR != result) || (index != end) || (0 == annotations->numberOfParameters)) {
U_32 cursor = 0;
Trc_BCU_MalformedParameterAnnotation(address);
if (!ALLOC_ARRAY(annotations->rawAttributeData, length + 1, U_8)) {
return -2;
}
index = attributeStart;
NEXT_U8(annotations->rawAttributeData[0], index);
if (0 != annotations->rawAttributeData[0]) {
annotations->rawAttributeData[1] = annotations->rawAttributeData[0];
annotations->rawAttributeData[0] = 0;
annotations->rawDataLength = length + 1;
} else {
if (length > 1) {
NEXT_U8(annotations->rawAttributeData[1], index);
}
annotations->rawDataLength = length;
}
annotations->numberOfParameters = annotations->rawAttributeData[0];
for (cursor = 2; cursor < annotations->rawDataLength; ++cursor) {
CHECK_EOF(1);
NEXT_U8(annotations->rawAttributeData[cursor], index);
}
}
}
break;
case CFR_ATTRIBUTE_RuntimeInvisibleTypeAnnotations: {
if (invisibleTypeAttributeRead) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_TYPE_ANNOTATIONS_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
}
invisibleTypeAttributeRead = TRUE;
if (J9_ARE_NO_BITS_SET(flags, BCT_RetainRuntimeInvisibleAttributes)) {
if (!ALLOC(attrib, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(length);
index += length;
break;
}
}
case CFR_ATTRIBUTE_RuntimeVisibleTypeAnnotations: {
J9CfrAttributeRuntimeVisibleTypeAnnotations *annotations = NULL;
U_8 *attributeStart = index;
BOOLEAN foundError = FALSE;
{
if (CFR_ATTRIBUTE_RuntimeVisibleTypeAnnotations == tag) {
if (visibleTypeAttributeRead) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_TYPE_ANNOTATIONS_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
}
visibleTypeAttributeRead = TRUE;
}
}
if (!ALLOC_CAST(attrib, J9CfrAttributeRuntimeVisibleTypeAnnotations, J9CfrAttribute)) {
return -2;
}
annotations = (J9CfrAttributeRuntimeVisibleTypeAnnotations *)attrib;
annotations->numberOfAnnotations = 0;
annotations->typeAnnotations = NULL;
annotations->rawAttributeData = NULL;
annotations->rawDataLength = 0;
if (length > 1) {
CHECK_EOF(2);
NEXT_U16(annotations->numberOfAnnotations, index);
if (!ALLOC_ARRAY(annotations->typeAnnotations, annotations->numberOfAnnotations, J9CfrTypeAnnotation)) {
return -2;
}
typeAnnotations = annotations->typeAnnotations;
for (j = 0; j < annotations->numberOfAnnotations; j++, typeAnnotations++) {
result = readTypeAnnotation(classfile, typeAnnotations, data, dataEnd, segment, segmentEnd, &index, &freePointer, flags);
if (BCT_ERR_NO_ERROR != result) {
break;
}
}
}
if (BCT_ERR_OUT_OF_ROM == result) {
return result;
} else if ((BCT_ERR_NO_ERROR != result) || (0 == length) || (index != end)) {
const U_32 minimumRawDataBytes = 4;
Trc_BCU_MalformedTypeAnnotation(address);
annotations->rawDataLength = OMR_MAX(minimumRawDataBytes, length + 1);
if (!ALLOC_ARRAY(annotations->rawAttributeData, annotations->rawDataLength, U_8)) {
return -2;
}
index = attributeStart;
if (length >= 2) {
NEXT_U16(annotations->rawAttributeData[0], index);
} else {
annotations->rawAttributeData[0] = 0;
annotations->rawAttributeData[1] = 1;
}
if (index == end) {
annotations->rawAttributeData[2] = CFR_TARGET_TYPE_ErrorInAttribute;
annotations->rawDataLength -= 1;
} else {
U_32 cursor = 0;
NEXT_U8(annotations->rawAttributeData[2], index);
if (CFR_TARGET_TYPE_ErrorInAttribute != annotations->rawAttributeData[2]) {
annotations->rawAttributeData[3] = annotations->rawAttributeData[2];
annotations->rawAttributeData[2] = CFR_TARGET_TYPE_ErrorInAttribute;
cursor = 4;
} else {
annotations->rawDataLength -= 1;
cursor = 3;
}
while (index != end) {
CHECK_EOF(1);
NEXT_U8(annotations->rawAttributeData[cursor], index);
cursor++;
}
}
}
result = 0;
}
break;
case CFR_ATTRIBUTE_InnerClasses:
if (!ALLOC(classes, J9CfrAttributeInnerClasses)) {
return -2;
}
attrib = (J9CfrAttribute*)classes;
CHECK_EOF(2);
NEXT_U16(classes->numberOfClasses, index);
if (!ALLOC_ARRAY(classes->classes, classes->numberOfClasses, J9CfrClassesEntry)) {
return -2;
}
CHECK_EOF(classes->numberOfClasses << 3);
for (j = 0; j < classes->numberOfClasses; j++) {
NEXT_U16(classes->classes[j].innerClassInfoIndex, index);
NEXT_U16(classes->classes[j].outerClassInfoIndex, index);
NEXT_U16(classes->classes[j].innerNameIndex, index);
NEXT_U16(classes->classes[j].innerClassAccessFlags, index);
}
break;
case CFR_ATTRIBUTE_BootstrapMethods:
if (bootstrapMethodAttributeRead) {
errorCode = J9NLS_CFR_ERR_FOUND_MULTIPLE_BOOTSTRAP_METHODS_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
}
bootstrapMethodAttributeRead = TRUE;
if (!ALLOC(bootstrapMethods, J9CfrAttributeBootstrapMethods)) {
return -2;
}
attrib = (J9CfrAttribute*)bootstrapMethods;
CHECK_EOF(2);
NEXT_U16(bootstrapMethods->numberOfBootstrapMethods, index);
if (!ALLOC_ARRAY(bootstrapMethods->bootstrapMethods, bootstrapMethods->numberOfBootstrapMethods, J9CfrBootstrapMethod)) {
return -2;
}
for (j = 0; j < bootstrapMethods->numberOfBootstrapMethods; j++) {
CHECK_EOF(4);
NEXT_U16(bootstrapMethods->bootstrapMethods[j].bootstrapMethodIndex, index);
NEXT_U16(bootstrapMethods->bootstrapMethods[j].numberOfBootstrapArguments, index);
if (!ALLOC_ARRAY(bootstrapMethods->bootstrapMethods[j].bootstrapArguments, bootstrapMethods->bootstrapMethods[j].numberOfBootstrapArguments, U_16)) {
return -2;
}
CHECK_EOF(bootstrapMethods->bootstrapMethods[j].numberOfBootstrapArguments << 1);
for (k = 0; k < bootstrapMethods->bootstrapMethods[j].numberOfBootstrapArguments; k++) {
NEXT_U16(bootstrapMethods->bootstrapMethods[j].bootstrapArguments[k], index);
}
}
break;
case CFR_ATTRIBUTE_EnclosingMethod:
if (!ALLOC_CAST(attrib, J9CfrAttributeEnclosingMethod, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(4);
NEXT_U16(((J9CfrAttributeEnclosingMethod *) attrib)->classIndex, index);
NEXT_U16(((J9CfrAttributeEnclosingMethod *) attrib)->methodIndex, index);
break;
case CFR_ATTRIBUTE_Deprecated:
if (!ALLOC_CAST(attrib, J9CfrAttributeDeprecated, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(length);
index += length;
break;
case CFR_ATTRIBUTE_StackMapTable:
if (!ALLOC(stackMap, J9CfrAttributeStackMap)) {
return -2;
}
attrib = (J9CfrAttribute *)stackMap;
CHECK_EOF(2);
NEXT_U16(stackMap->numberOfEntries, index);
stackMap->mapLength = 0;
if (length > 1) {
stackMap->mapLength = length - 2;
}
if (!ALLOC_ARRAY(stackMap->entries, stackMap->mapLength, U_8)) {
return -2;
}
CHECK_EOF(stackMap->mapLength);
memcpy (stackMap->entries, index, stackMap->mapLength);
index += stackMap->mapLength;
break;
case CFR_ATTRIBUTE_Record:
if (recordAttributeRead){
errorCode = J9NLS_CFR_ERR_MULTIPLE_RECORD_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
}
recordAttributeRead = TRUE;
classfile->j9Flags |= CFR_J9FLAG_IS_RECORD;
if (!ALLOC(record, J9CfrAttributeRecord)) {
return -2;
}
attrib = (J9CfrAttribute*)record;
CHECK_EOF(2);
NEXT_U16(record->numberOfRecordComponents, index);
if (!ALLOC_ARRAY(record->recordComponents, record->numberOfRecordComponents, J9CfrRecordComponent)) {
return -2;
}
for (j = 0; j < record->numberOfRecordComponents; j++) {
J9CfrRecordComponent* recordComponent = &(record->recordComponents[j]);
CHECK_EOF(6);
NEXT_U16(recordComponent->nameIndex, index);
NEXT_U16(recordComponent->descriptorIndex, index);
NEXT_U16(recordComponent->attributesCount, index);
if (!ALLOC_ARRAY(recordComponent->attributes, recordComponent->attributesCount, J9CfrAttribute *)) {
return -2;
}
result = readAttributes(classfile, &(recordComponent->attributes), recordComponent->attributesCount, data, dataEnd, segment, segmentEnd, &index, &freePointer, flags, NULL);
if (result != 0) {
return result;
}
}
break;
case CFR_ATTRIBUTE_PermittedSubclasses:
if (permittedSubclassesAttributeRead) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_PERMITTEDSUBCLASSES_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
}
permittedSubclassesAttributeRead = TRUE;
classfile->j9Flags |= CFR_J9FLAG_IS_SEALED;
if (!ALLOC(permittedSubclasses, J9CfrAttributePermittedSubclasses)) {
return -2;
}
attrib = (J9CfrAttribute*)permittedSubclasses;
CHECK_EOF(2);
NEXT_U16(permittedSubclasses->numberOfClasses, index);
if (!ALLOC_ARRAY(permittedSubclasses->classes, permittedSubclasses->numberOfClasses, U_16)) {
return -2;
}
for (j = 0; j < permittedSubclasses->numberOfClasses; j++) {
CHECK_EOF(2);
NEXT_U16(permittedSubclasses->classes[j], index);
}
break;
#if JAVA_SPEC_VERSION >= 11
case CFR_ATTRIBUTE_NestHost:
if (nestAttributeRead) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_NEST_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
}
if (!ALLOC(nestHost, J9CfrAttributeNestHost)) {
return -2;
}
nestAttributeRead = TRUE;
attrib = (J9CfrAttribute*)nestHost;
CHECK_EOF(2);
NEXT_U16(nestHost->hostClassIndex, index);
break;
case CFR_ATTRIBUTE_NestMembers: {
U_16 numberOfClasses;
if (nestAttributeRead) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_NEST_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
}
if (!ALLOC(nestMembers, J9CfrAttributeNestMembers)) {
return -2;
}
nestAttributeRead = TRUE;
attrib = (J9CfrAttribute*)nestMembers;
CHECK_EOF(2);
NEXT_U16(numberOfClasses, index);
nestMembers->numberOfClasses = numberOfClasses;
if (!ALLOC_ARRAY(nestMembers->classes, numberOfClasses, U_16)) {
return -2;
}
CHECK_EOF(2 * numberOfClasses);
for (j = 0; j < numberOfClasses; j++) {
NEXT_U16(nestMembers->classes[j], index);
}
break;
}
#endif
case CFR_ATTRIBUTE_StrippedLineNumberTable:
case CFR_ATTRIBUTE_StrippedLocalVariableTable:
case CFR_ATTRIBUTE_StrippedLocalVariableTypeTable:
case CFR_ATTRIBUTE_StrippedInnerClasses:
case CFR_ATTRIBUTE_StrippedSourceDebugExtension:
case CFR_ATTRIBUTE_StrippedUnknown:
if (!ALLOC(attrib, J9CfrAttribute)) {
return -2;
}
CHECK_EOF(length);
index += length;
break;
case CFR_ATTRIBUTE_SourceDebugExtension:
if (sourceDebugExtensionRead) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_SOURCE_DEBUG_EXTENSION_ATTRIBUTES__ID;
offset = address;
goto _errorFound;
} else {
sourceDebugExtensionRead = TRUE;
}
case CFR_ATTRIBUTE_StackMap:
case CFR_ATTRIBUTE_Unknown:
default:
if (!ALLOC_CAST(attrib, J9CfrAttributeUnknown, J9CfrAttribute)) {
return -2;
}
if (!ALLOC_ARRAY(((J9CfrAttributeUnknown*) attrib)->value, length, U_8)) {
return -2;
}
CHECK_EOF(length);
memcpy (((J9CfrAttributeUnknown *) attrib)->value, index, length);
index += length;
break;
}
attrib->tag = tag;
attrib->nameIndex = (U_16) name;
attrib->length = length;
attrib->romAddress = address;
attributes[i] = (J9CfrAttribute *) attrib;
if (index != end) {
errorCode = (U_32) ((index < end) ? J9NLS_CFR_ERR_LENGTH_TOO_SMALL__ID : J9NLS_CFR_ERR_LENGTH_TOO_BIG__ID);
offset = address + 2;
goto _errorFound;
}
}
*pAttributes = attributes;
*pIndex = index;
*pFreePointer = freePointer;
return 0;
_errorFound:
buildError((J9CfrError *) segment, errorCode, CFR_ThrowClassFormatError, offset);
return -1;
}
static I_32
readMethods(J9CfrClassFile* classfile, U_8* data, U_8* dataEnd, U_8* segment, U_8* segmentEnd, U_8** pIndex, U_8** pFreePointer, U_32 flags)
{
U_8* index = *pIndex;
U_8* freePointer = *pFreePointer;
J9CfrMethod* method;
UDATA errorCode, offset;
U_32 i;
I_32 result;
for (i = 0; i < classfile->methodsCount; i++) {
U_32 j;
UDATA syntheticFound = FALSE;
method = &(classfile->methods[i]);
method->romAddress = (UDATA) (index - data);
CHECK_EOF(8);
method->accessFlags = NEXT_U16(method->accessFlags, index) & CFR_METHOD_ACCESS_MASK;
method->j9Flags = 0;
NEXT_U16(method->nameIndex, index);
NEXT_U16(method->descriptorIndex, index);
NEXT_U16(method->attributesCount, index);
if (!ALLOC_ARRAY(method->attributes, method->attributesCount, J9CfrAttribute*)) {
return -2;
}
if ((result = readAttributes(classfile, &(method->attributes), method->attributesCount, data, dataEnd, segment, segmentEnd, &index, &freePointer, flags, &syntheticFound))!= 0) {
return result;
}
if (syntheticFound) {
method->accessFlags |= CFR_ACC_SYNTHETIC;
}
method->codeAttribute = NULL;
method->exceptionsAttribute = NULL;
method->methodParametersAttribute = NULL;
for (j = 0; j < method->attributesCount; j++) {
switch (method->attributes[j]->tag) {
case CFR_ATTRIBUTE_Code:
if (method->codeAttribute) {
errorCode = J9NLS_CFR_ERR_TWO_CODE_ATTRIBUTES__ID;
offset = method->attributes[j]->romAddress;
goto _errorFound;
}
method->codeAttribute = (J9CfrAttributeCode*)(method->attributes[j]);
break;
case CFR_ATTRIBUTE_Exceptions:
if (method->exceptionsAttribute) {
errorCode = J9NLS_CFR_ERR_TWO_EXCEPTIONS_ATTRIBUTES__ID;
offset = method->attributes[j]->romAddress;
goto _errorFound;
}
method->exceptionsAttribute = (J9CfrAttributeExceptions*)(method->attributes[j]);
break;
case CFR_ATTRIBUTE_MethodParameters:
if (method->methodParametersAttribute) {
errorCode = J9NLS_CFR_ERR_TWO_METHOD_PARAMETERS_ATTRIBUTES__ID;
offset = method->attributes[j]->romAddress;
goto _errorFound;
}
method->methodParametersAttribute = (J9CfrAttributeMethodParameters*)(method->attributes[j]);
}
}
}
*pIndex = index;
*pFreePointer = freePointer;
return 0;
_errorFound:
buildError((J9CfrError *) segment, errorCode, CFR_ThrowClassFormatError, offset);
return -1;
}
static I_32
readFields(J9CfrClassFile* classfile, U_8* data, U_8* dataEnd, U_8* segment, U_8* segmentEnd, U_8** pIndex, U_8** pFreePointer, U_32 flags)
{
U_8* index = *pIndex;
U_8* freePointer = *pFreePointer;
J9CfrField* field;
UDATA errorCode, offset;
U_32 i, j;
I_32 result;
field = classfile->fields;
for (i = 0; i < classfile->fieldsCount; i++, field++) {
UDATA syntheticFound = FALSE;
field->romAddress = (UDATA) (index - data);
CHECK_EOF(8);
field->accessFlags = NEXT_U16(field->accessFlags, index) & CFR_FIELD_ACCESS_MASK;
NEXT_U16(field->nameIndex, index);
NEXT_U16(field->descriptorIndex, index);
NEXT_U16(field->attributesCount, index);
if (!ALLOC_ARRAY(field->attributes, field->attributesCount, J9CfrAttribute*)) {
return -2;
}
if ((result = readAttributes(classfile, &(field->attributes), field->attributesCount, data, dataEnd, segment, segmentEnd, &index, &freePointer, flags, &syntheticFound)) != 0) {
return result;
}
if (syntheticFound) {
field->accessFlags |= CFR_ACC_SYNTHETIC;
}
field->constantValueAttribute = NULL;
for (j = 0; j < field->attributesCount; j++) {
if (field->attributes[j]->tag == CFR_ATTRIBUTE_ConstantValue) {
if (field->constantValueAttribute) {
errorCode = J9NLS_CFR_ERR_TWO_CONSTANT_VALUE_ATTRIBUTES__ID;
offset = field->attributes[j]->romAddress;
goto _errorFound;
}
field->constantValueAttribute = (J9CfrAttributeConstantValue*)(field->attributes[j]);
}
}
}
*pIndex = index;
*pFreePointer = freePointer;
return 0;
_errorFound:
buildError((J9CfrError *) segment, errorCode, CFR_ThrowClassFormatError, offset);
return -1;
}
static I_32
readPool(J9CfrClassFile* classfile, U_8* data, U_8* dataEnd, U_8* segment, U_8* segmentEnd, U_8** pIndex, U_8** pFreePointer)
{
U_8* index = *pIndex;
U_8* freePointer = *pFreePointer;
J9CfrConstantPoolInfo* info;
J9CfrConstantPoolInfo* previousUTF8;
J9CfrConstantPoolInfo* previousNAT;
U_32 size, errorCode, offset;
U_32 i;
I_32 verifyResult;
info = &(classfile->constantPool[0]);
info->tag = CFR_CONSTANT_Null;
info->flags1 = 0;
info->nextCPIndex = 0;
info->slot1 = 0;
info->slot2 = 0;
info->bytes = 0;
info->romAddress = 0;
classfile->firstUTF8CPIndex = 0;
classfile->firstNATCPIndex = 0;
for (i = 1; i < classfile->constantPoolCount;) {
info = &(classfile->constantPool[i]);
CHECK_EOF(1);
NEXT_U8(info->tag, index);
info->flags1 = 0;
info->nextCPIndex = 0;
info->romAddress = 0;
switch (info->tag) {
case CFR_CONSTANT_Utf8:
CHECK_EOF(2);
NEXT_U16(size, index);
info->slot2 = 0;
if (!ALLOC_ARRAY(info->bytes, size + 1, U_8)) {
return -2;
}
CHECK_EOF(size);
verifyResult = j9bcutil_verifyCanonisizeAndCopyUTF8(info->bytes, index, size, &(info->flags1));
info->slot1 = (U_32) verifyResult;
if ((verifyResult < 0) ||
(J9_ARE_ALL_BITS_SET(info->flags1, CFR_FOUND_CHARS_IN_EXTENDED_MUE_FORM) && (classfile->majorVersion >= 48))
) {
errorCode = J9NLS_CFR_ERR_BAD_UTF8__ID;
offset = (U_32) (index - data - 1);
goto _errorFound;
}
info->bytes[info->slot1] = (U_8) '\0';
freePointer -= (size - info->slot1);
index += size;
if (0 == classfile->firstUTF8CPIndex) {
classfile->firstUTF8CPIndex = i;
previousUTF8 = info;
} else {
previousUTF8->nextCPIndex = (U_16)i;
previousUTF8 = info;
}
classfile->lastUTF8CPIndex = i;
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
info->flags1 |= CFR_CLASS_FILE_VERSION_SUPPORT_VALUE_TYPE;
#endif
i++;
break;
case CFR_CONSTANT_Integer:
case CFR_CONSTANT_Float:
CHECK_EOF(4);
NEXT_U32(info->slot1, index);
info->slot2 = 0;
i++;
break;
case CFR_CONSTANT_Long:
case CFR_CONSTANT_Double:
CHECK_EOF(8);
#ifdef J9VM_ENV_LITTLE_ENDIAN
NEXT_U32(info->slot2, index);
NEXT_U32(info->slot1, index);
#else
NEXT_U32(info->slot1, index);
NEXT_U32(info->slot2, index);
#endif
i++;
classfile->constantPool[i].tag = CFR_CONSTANT_Null;
i++;
if (i > classfile->constantPoolCount) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
offset = (U_32) (index - data - 1);
goto _errorFound;
}
break;
case CFR_CONSTANT_MethodType:
if (classfile->majorVersion < 51) {
errorCode = J9NLS_CFR_ERR_CP_ENTRY_INVALID_BEFORE_V51__ID;
offset = (U_32) (index - data - 1);
goto _errorFound;
}
case CFR_CONSTANT_Class:
case CFR_CONSTANT_String:
CHECK_EOF(2);
NEXT_U16(info->slot1, index);
info->slot2 = 0;
i++;
break;
case CFR_CONSTANT_Dynamic:
if (classfile->majorVersion < 55) {
errorCode = J9NLS_CFR_ERR_CP_ENTRY_INVALID_BEFORE_V55__ID;
offset = (U_32) (index - data - 1);
goto _errorFound;
}
case CFR_CONSTANT_InvokeDynamic:
if (classfile->majorVersion < 51) {
errorCode = J9NLS_CFR_ERR_CP_ENTRY_INVALID_BEFORE_V51__ID;
offset = (U_32) (index - data - 1);
goto _errorFound;
}
case CFR_CONSTANT_Fieldref:
case CFR_CONSTANT_Methodref:
case CFR_CONSTANT_InterfaceMethodref:
CHECK_EOF(4);
NEXT_U16(info->slot1, index);
NEXT_U16(info->slot2, index);
i++;
break;
case CFR_CONSTANT_NameAndType:
CHECK_EOF(4);
NEXT_U16(info->slot1, index);
NEXT_U16(info->slot2, index);
if (0 == classfile->firstNATCPIndex) {
classfile->firstNATCPIndex = i;
previousNAT = info;
} else {
previousNAT->nextCPIndex = (U_16)i;
previousNAT = info;
}
i++;
break;
case CFR_CONSTANT_MethodHandle:
if (classfile->majorVersion < 51) {
errorCode = J9NLS_CFR_ERR_CP_ENTRY_INVALID_BEFORE_V51__ID;
offset = (U_32) (index - data - 1);
goto _errorFound;
}
CHECK_EOF(3);
NEXT_U8(info->slot1, index);
NEXT_U16(info->slot2, index);
i++;
break;
case CFR_CONSTANT_Module:
case CFR_CONSTANT_Package:
if (classfile->majorVersion < 53) {
errorCode = J9NLS_CFR_ERR_CP_ENTRY_INVALID_BEFORE_V53__ID;
offset = (U_32)(index - data - 1);
goto _errorFound;
}
CHECK_EOF(2);
NEXT_U16(info->slot1, index);
i++;
break;
default:
errorCode = J9NLS_CFR_ERR_UNKNOWN_CONSTANT__ID;
offset = (U_32) (index - data - 1);
goto _errorFound;
}
}
*pIndex = index;
*pFreePointer = freePointer;
return 0;
_errorFound:
buildError((J9CfrError *) segment, errorCode, CFR_ThrowClassFormatError, offset);
return -1;
}
static I_32
checkPool(J9CfrClassFile* classfile, U_8* segment, U_8* poolStart, I_32 *maxBootstrapMethodIndex, U_32 flags)
{
J9CfrConstantPoolInfo* info;
J9CfrConstantPoolInfo* utf8;
J9CfrConstantPoolInfo* cpBase;
U_32 count, i, errorCode;
U_8* index;
cpBase = classfile->constantPool;
count = classfile->constantPoolCount;
index = poolStart;
info = &cpBase[1];
for (i = 1; i < count; i++, info++) {
switch (info->tag) {
case CFR_CONSTANT_Utf8:
index += info->slot1 + 3;
break;
case CFR_CONSTANT_Integer:
case CFR_CONSTANT_Float:
index += 5;
break;
case CFR_CONSTANT_Long:
case CFR_CONSTANT_Double:
index += 9;
i++;
info++;
break;
case CFR_CONSTANT_Class:
if ((!(info->slot1)) || (info->slot1 > count)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
utf8 = &cpBase[info->slot1];
if (utf8->tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_BAD_NAME_INDEX__ID;
goto _errorFound;
}
index += 3;
break;
case CFR_CONSTANT_String:
if ((!(info->slot1)) || (info->slot1 > count)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (cpBase[info->slot1].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_BAD_STRING_INDEX__ID;
goto _errorFound;
}
index += 3;
break;
case CFR_CONSTANT_Fieldref:
case CFR_CONSTANT_Methodref:
case CFR_CONSTANT_InterfaceMethodref:
if (!(info->slot1) || (info->slot1 > count)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (cpBase[info->slot1].tag != CFR_CONSTANT_Class) {
errorCode = J9NLS_CFR_ERR_BAD_CLASS_INDEX__ID;
goto _errorFound;
}
if (!(info->slot2) || (info->slot2 > count)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (cpBase[info->slot2].tag != CFR_CONSTANT_NameAndType) {
errorCode = J9NLS_CFR_ERR_BAD_NAME_AND_TYPE_INDEX__ID;
goto _errorFound;
}
index += 5;
break;
case CFR_CONSTANT_NameAndType:
if ((!(info->slot1)) || (info->slot1 > count)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (cpBase[info->slot1].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_BAD_NAME_INDEX__ID;
goto _errorFound;
}
if ((!(info->slot2)) || (info->slot2 > count)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (cpBase[info->slot2].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_BAD_DESCRIPTOR_INDEX__ID;
goto _errorFound;
}
index += 5;
break;
case CFR_CONSTANT_MethodType:
if (!(info->slot1) || (info->slot1 > count)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (cpBase[info->slot1].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_BAD_DESCRIPTOR_INDEX__ID;
goto _errorFound;
}
index += 3;
break;
case CFR_CONSTANT_MethodHandle:
if (!(info->slot2) || (info->slot2 > count)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
switch(cpBase[info->slot2].tag){
case CFR_CONSTANT_Fieldref:
if ((info->slot1 < 1) || (info->slot1 > 4)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
break;
case CFR_CONSTANT_Methodref:
if ((info->slot1 < MH_REF_INVOKEVIRTUAL) || (info->slot1 > MH_REF_NEWINVOKESPECIAL)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
break;
case CFR_CONSTANT_InterfaceMethodref:
if ((info->slot1 != MH_REF_INVOKEINTERFACE)
&& (!((classfile->majorVersion >= 52)
&& ((info->slot1 == MH_REF_INVOKESTATIC) || (info->slot1 == MH_REF_INVOKESPECIAL))))
) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
break;
default:
errorCode = J9NLS_CFR_ERR_BAD_METHODHANDLE_REF_INDEX__ID;
goto _errorFound;
}
index += 4;
break;
case CFR_CONSTANT_Dynamic:
case CFR_CONSTANT_InvokeDynamic:
if (((I_32) info->slot1) > *maxBootstrapMethodIndex) {
*maxBootstrapMethodIndex = info->slot1;
}
if (!(info->slot2) || (info->slot2 > count)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (cpBase[info->slot2].tag != CFR_CONSTANT_NameAndType) {
errorCode = J9NLS_CFR_ERR_BAD_NAME_AND_TYPE_INDEX__ID;
goto _errorFound;
}
index += 5;
break;
case CFR_CONSTANT_Module:
errorCode = J9NLS_CFR_ERR_CONSTANT_MODULE_OUTSIDE_MODULE__ID;
goto _errorFound;
case CFR_CONSTANT_Package:
errorCode = J9NLS_CFR_ERR_CONSTANT_PACKAGE_OUTSIDE_MODULE__ID;
goto _errorFound;
default:
errorCode = J9NLS_CFR_ERR_UNKNOWN_CONSTANT__ID;
goto _errorFound;
}
}
return 0;
_errorFound:
buildError((J9CfrError *) segment, errorCode, CFR_ThrowClassFormatError, (UDATA) (index - poolStart + 10));
return -1;
}
static I_32
checkFields(J9PortLibrary* portLib, J9CfrClassFile * classfile, U_8 * segment, U_32 flags)
{
J9CfrField *field;
U_32 value, maskedValue, errorCode, offset = 0;
U_32 i;
U_8 sigChar, sigTag, constantTag;
for (i = 0; i < classfile->fieldsCount; i++) {
field = &(classfile->fields[i]);
value = field->accessFlags & CFR_FIELD_ACCESS_MASK;
if ((flags & BCT_MajorClassFileVersionMask) < BCT_JavaMajorVersionShifted(5)) {
value &= ~CFR_FIELD_ACCESS_NEWJDK5_MASK;
}
if (classfile->accessFlags & CFR_ACC_INTERFACE) {
if ((value & ~CFR_INTERFACE_FIELD_ACCESS_MASK) ||
((value & CFR_INTERFACE_FIELD_ACCESS_REQUIRED) != CFR_INTERFACE_FIELD_ACCESS_REQUIRED)) {
errorCode = J9NLS_CFR_ERR_INTERFACE_FIELD__ID;
goto _errorFound;
}
}
maskedValue = value & CFR_PUBLIC_PRIVATE_PROTECTED_MASK;
if (maskedValue & (maskedValue - 1)) {
errorCode = J9NLS_CFR_ERR_ACCESS_CONFLICT_FIELD__ID;
goto _errorFound;
}
if ((value & (U_32) (CFR_ACC_FINAL | CFR_ACC_VOLATILE)) == (U_32) (CFR_ACC_FINAL | CFR_ACC_VOLATILE)) {
errorCode = J9NLS_CFR_ERR_FINAL_VOLATILE_FIELD__ID;
goto _errorFound;
}
offset = 2;
value = field->nameIndex;
if ((!value) || (value >= classfile->constantPoolCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (classfile->constantPool[value].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_BAD_NAME_INDEX__ID;
goto _errorFound;
}
offset = 4;
value = field->descriptorIndex;
if ((!value) || (value >= classfile->constantPoolCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (classfile->constantPool[value].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_BAD_DESCRIPTOR_INDEX__ID;
goto _errorFound;
}
if (checkAttributes(portLib, classfile, field->attributes, field->attributesCount, segment, -1, OUTSIDE_CODE, flags)) {
return -1;
}
if (field->constantValueAttribute && (field->accessFlags & CFR_ACC_FINAL) &&
(field->accessFlags & CFR_ACC_STATIC)) {
sigChar = classfile->constantPool[field->descriptorIndex].bytes[0];
constantTag = classfile->constantPool[field->constantValueAttribute->constantValueIndex].tag;
if ((sigChar < 'A') || (sigChar > 'Z')) {
errorCode = J9NLS_CFR_ERR_INCOMPATIBLE_CONSTANT__ID;
goto _errorFound;
}
sigTag = (U_32) cpTypeCharConversion[sigChar - 'A'];
if (sigTag == constantTag) {
if (sigTag == CFR_CONSTANT_String) {
if (!utf8Equal(&classfile->constantPool[field->descriptorIndex], "Ljava/lang/String;", 18)) {
errorCode = J9NLS_CFR_ERR_INCOMPATIBLE_CONSTANT__ID;
goto _errorFound;
}
}
} else {
errorCode = J9NLS_CFR_ERR_INCOMPATIBLE_CONSTANT__ID;
goto _errorFound;
}
}
}
return 0;
_errorFound:
buildError((J9CfrError *) segment, errorCode, CFR_ThrowClassFormatError, field->romAddress + offset);
return -1;
}
static I_32
checkMethods(J9PortLibrary* portLib, J9CfrClassFile* classfile, U_8* segment, U_32 vmVersionShifted, U_32 flags)
{
J9CfrMethod* method;
U_32 value = 0;
U_32 maskedValue = 0;
U_32 errorCode = 0;
U_32 offset = 0;
U_32 i;
BOOLEAN nameIndexOK;
U_32 classfileVersion = flags & BCT_MajorClassFileVersionMask;
for (i = 0; i < classfile->methodsCount; i++) {
method = &(classfile->methods[i]);
nameIndexOK = TRUE;
value = method->nameIndex;
if ((!value) || (value >= classfile->constantPoolCount)) {
nameIndexOK = FALSE;
} else if (classfile->constantPool[value].tag != CFR_CONSTANT_Utf8) {
nameIndexOK = FALSE;
}
value = method->accessFlags & CFR_METHOD_ACCESS_MASK;
if (classfileVersion < BCT_JavaMajorVersionShifted(5)) {
value &= ~CFR_METHOD_ACCESS_NEWJDK5_MASK;
}
if ((classfileVersion < BCT_JavaMajorVersionShifted(2)) && ((flags & CFR_Xfuture) == 0)) {
value &= ~CFR_ACC_STRICT;
}
if (nameIndexOK && utf8Equal(&classfile->constantPool[method->nameIndex], "<clinit>", 8)) {
if (classfileVersion < BCT_JavaMajorVersionShifted(7)) {
method->accessFlags |= CFR_ACC_STATIC;
} else if (vmVersionShifted >= BCT_JavaMajorVersionShifted(9)) {
if (J9_ARE_NO_BITS_SET(method->accessFlags, CFR_ACC_STATIC)) {
errorCode = J9NLS_CFR_ERR_CLINIT_NOT_STATIC__ID;
goto _errorFound;
}
}
method->accessFlags &= CFR_CLINIT_METHOD_ACCESS_MASK;
goto _nameCheck;
}
if (nameIndexOK && utf8Equal(&classfile->constantPool[method->nameIndex], "<init>", 6)) {
if ((J9_IS_CLASSFILE_VALUETYPE(classfile) && (value & ~CFR_INIT_VT_METHOD_ACCESS_MASK))
|| (!J9_IS_CLASSFILE_VALUETYPE(classfile) && (value & ~CFR_INIT_METHOD_ACCESS_MASK))
) {
errorCode = J9NLS_CFR_ERR_INIT_METHOD__ID;
goto _errorFound;
}
if (vmVersionShifted >= BCT_JavaMajorVersionShifted(9)) {
if (classfile->accessFlags & CFR_ACC_INTERFACE) {
errorCode = J9NLS_CFR_ERR_INIT_ILLEGAL_IN_INTERFACE__ID;
goto _errorFound;
}
}
}
if (classfile->accessFlags & CFR_ACC_INTERFACE) {
if (classfileVersion < BCT_JavaMajorVersionShifted(8)) {
U_32 mask = CFR_INTERFACE_METHOD_ACCESS_MASK;
if ((flags & CFR_Xfuture) == 0) {
mask |= (CFR_ACC_STRICT | CFR_ACC_SYNCHRONIZED);
}
if ((value & ~mask) || ((value & CFR_INTERFACE_METHOD_ACCESS_REQUIRED) != CFR_INTERFACE_METHOD_ACCESS_REQUIRED)) {
errorCode = J9NLS_CFR_ERR_INTERFACE_METHOD__ID;
goto _errorFound;
}
} else {
const U_32 illegalMask = CFR_ACC_PROTECTED | CFR_ACC_FINAL | CFR_ACC_NATIVE | CFR_ACC_SYNCHRONIZED;
const U_32 publicPrivateMask = CFR_ACC_PUBLIC | CFR_ACC_PRIVATE;
const U_32 maskedValue = value & publicPrivateMask;
BOOLEAN oneOfPublicOrPrivate = (maskedValue != 0) && (((maskedValue) & ((maskedValue) - 1)) == 0);
if ((0 != (value & illegalMask)) || !oneOfPublicOrPrivate) {
errorCode = J9NLS_CFR_ERR_INTERFACE_METHOD_JAVA_8__ID;
goto _errorFound;
}
if ((CFR_ACC_ABSTRACT == (value & CFR_ACC_ABSTRACT)) && (0 != (value & ~CFR_ABSTRACT_METHOD_ACCESS_MASK))) {
errorCode = J9NLS_CFR_ERR_INTERFACE_METHOD_JAVA_8__ID;
goto _errorFound;
}
}
goto _nameCheck;
}
if (value & CFR_ACC_ABSTRACT) {
if (value & ~CFR_ABSTRACT_METHOD_ACCESS_MASK) {
errorCode = J9NLS_CFR_ERR_ABSTRACT_METHOD__ID;
goto _errorFound;
}
}
maskedValue = value & CFR_PUBLIC_PRIVATE_PROTECTED_MASK;
if (maskedValue & (maskedValue - 1)) {
errorCode = J9NLS_CFR_ERR_ACCESS_CONFLICT_METHOD__ID;
goto _errorFound;
}
_nameCheck:
offset = 2;
value = method->nameIndex;
if (!nameIndexOK) {
if ((!value) || (value >= classfile->constantPoolCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (classfile->constantPool[value].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_BAD_NAME_INDEX__ID;
goto _errorFound;
}
}
offset = 4;
value = method->descriptorIndex;
if ((!value) || (value >= classfile->constantPoolCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (classfile->constantPool[value].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_BAD_DESCRIPTOR_INDEX__ID;
goto _errorFound;
}
if (checkAttributes(portLib, classfile, method->attributes, method->attributesCount, segment, -1, OUTSIDE_CODE, flags)) {
return -1;
}
if (method->codeAttribute) {
if (method->codeAttribute->codeLength > 65535) {
errorCode = J9NLS_CFR_ERR_CODE_ARRAY_TOO_LARGE__ID;
goto _errorFound;
}
if (J9_ARE_ANY_BITS_SET(method->accessFlags, CFR_ACC_NATIVE | CFR_ACC_ABSTRACT)) {
errorCode = J9NLS_CFR_ERR_CODE_FOR_ABSTRACT_OR_NATIVE__ID;
goto _errorFound;
}
}
}
return 0;
_errorFound:
buildError((J9CfrError *) segment, errorCode, CFR_ThrowClassFormatError, method->romAddress + offset);
return -1;
}
static I_32
checkAttributes(J9PortLibrary* portLib, J9CfrClassFile* classfile, J9CfrAttribute** attributes, U_32 attributesCount, U_8* segment, I_32 maxBootstrapMethodIndex, U_32 extra, U_32 flags)
{
J9CfrAttribute* attrib;
J9CfrAttributeCode* code;
J9CfrAttributeExceptions* exceptions;
J9CfrExceptionTableEntry* exception;
J9CfrAttributeInnerClasses* classes = NULL;
J9CfrAttributeEnclosingMethod* enclosing = NULL;
J9CfrConstantPoolInfo* cpBase;
U_32 value, errorCode, errorType, cpCount;
U_32 i, j, k;
UDATA foundStackMap = FALSE;
BOOLEAN bootstrapMethodAttributeRead = FALSE;
BOOLEAN enablePermittedSubclassErrors = FALSE;
I_32* innerClassArrayIndexTable = NULL;
PORT_ACCESS_FROM_PORT(portLib);
errorType = CFR_ThrowClassFormatError;
cpBase = classfile->constantPool;
cpCount = (U_32) classfile->constantPoolCount;
for(i = 0; i < attributesCount; i++) {
attrib = attributes[i];
switch(attrib->tag) {
case CFR_ATTRIBUTE_SourceFile:
value = ((J9CfrAttributeSourceFile*)attrib)->sourceFileIndex;
if((!value)||(value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if(cpBase[value].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_SOURCE_FILE_INDEX__ID;
goto _errorFound;
}
break;
case CFR_ATTRIBUTE_Signature:
value = ((J9CfrAttributeSignature*)attrib)->signatureIndex;
if((0 == value)||(value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if(cpBase[value].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_BC_INVALID_SIG__ID;
goto _errorFound;
}
break;
case CFR_ATTRIBUTE_ConstantValue:
value = ((J9CfrAttributeConstantValue*)attrib)->constantValueIndex;
if((0 == value)||(value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
switch(cpBase[value].tag) {
case CFR_CONSTANT_Integer:
case CFR_CONSTANT_Float:
case CFR_CONSTANT_Long:
case CFR_CONSTANT_Double:
case CFR_CONSTANT_String:
break;
default:
errorCode = J9NLS_CFR_ERR_CONSTANT_VALUE_INDEX__ID;
goto _errorFound;
}
break;
case CFR_ATTRIBUTE_Code:
code = (J9CfrAttributeCode*)attrib;
if(code->codeLength == 0) {
errorCode = J9NLS_CFR_ERR_CODE_ARRAY_EMPTY__ID;
goto _errorFound;
}
for(j = 0; j < code->exceptionTableLength; j++) {
exception = &(code->exceptionTable[j]);
value = exception->catchType;
if(value >= cpCount) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if((0 != value) && (cpBase[value].tag != CFR_CONSTANT_Class)) {
errorCode = J9NLS_CFR_ERR_CATCH_NOT_CLASS__ID;
goto _errorFound;
}
}
if(checkAttributes(portLib, classfile, code->attributes, code->attributesCount, segment, -1, code->codeLength, flags)) {
return -1;
}
break;
case CFR_ATTRIBUTE_Exceptions:
exceptions = (J9CfrAttributeExceptions*)attrib;
for(j = 0; j < exceptions->numberOfExceptions; j++) {
value = exceptions->exceptionIndexTable[j];
if((0 == value)||(value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if(cpBase[value].tag != CFR_CONSTANT_Class) {
errorCode = J9NLS_CFR_ERR_EXCEPTION_NOT_CLASS__ID;
goto _errorFound;
}
}
break;
case CFR_ATTRIBUTE_MethodParameters:
{
break;
}
case CFR_ATTRIBUTE_LineNumberTable:
value = ((J9CfrAttributeLineNumberTable*)attrib)->lineNumberTableLength;
for(j = 0; j < value; j++) {
if(((J9CfrAttributeLineNumberTable*)attrib)->lineNumberTable[j].startPC >= extra) {
errorCode = J9NLS_CFR_ERR_LINE_NUMBER_PC__ID;
goto _errorFound;
}
}
break;
case CFR_ATTRIBUTE_LocalVariableTable:
for(j = 0; j < ((J9CfrAttributeLocalVariableTable*)attrib)->localVariableTableLength; j++) {
value = ((J9CfrAttributeLocalVariableTable*)attrib)->localVariableTable[j].startPC;
if(value > extra) {
errorCode = J9NLS_CFR_ERR_LOCAL_VARIABLE_START__ID;
goto _errorFound;
}
if(((J9CfrAttributeLocalVariableTable*)attrib)->localVariableTable[j].length + value > extra) {
errorCode = J9NLS_CFR_ERR_LOCAL_VARIABLE_LENGTH__ID;
goto _errorFound;
}
value = ((J9CfrAttributeLocalVariableTable*)attrib)->localVariableTable[j].nameIndex;
if((0 == value)||(value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if(cpBase) {
if(cpBase[value].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_LOCAL_VARIABLE_NAME_NOT_UTF8__ID;
goto _errorFound;
}
if((flags & CFR_Xfuture) && (bcvCheckName(&cpBase[value]))) {
errorCode = J9NLS_CFR_ERR_LOCAL_VARIABLE_NAME__ID;
goto _errorFound;
}
}
value = ((J9CfrAttributeLocalVariableTable*)attrib)->localVariableTable[j].descriptorIndex;
if((0 == value)||(value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if(cpBase) {
if(cpBase[value].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_LOCAL_VARIABLE_SIGNATURE_NOT_UTF8__ID;
goto _errorFound;
}
if(j9bcv_checkFieldSignature(&cpBase[value], 0)) {
errorCode = J9NLS_CFR_ERR_LOCAL_VARIABLE_SIGNATURE_INVALID__ID;
goto _errorFound;
}
}
}
break;
case CFR_ATTRIBUTE_LocalVariableTypeTable:
for(j = 0; j < ((J9CfrAttributeLocalVariableTypeTable*)attrib)->localVariableTypeTableLength; j++) {
value = ((J9CfrAttributeLocalVariableTypeTable*)attrib)->localVariableTypeTable[j].startPC;
if(value > extra) {
errorCode = J9NLS_CFR_ERR_LOCAL_VARIABLE_START__ID;
goto _errorFound;
}
if(((J9CfrAttributeLocalVariableTypeTable*)attrib)->localVariableTypeTable[j].length + value > extra) {
errorCode = J9NLS_CFR_ERR_LOCAL_VARIABLE_LENGTH__ID;
goto _errorFound;
}
value = ((J9CfrAttributeLocalVariableTypeTable*)attrib)->localVariableTypeTable[j].nameIndex;
if((0 == value)||(value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if(cpBase) {
if(cpBase[value].tag != CFR_CONSTANT_Utf8) {
errorCode = J9NLS_CFR_ERR_LOCAL_VARIABLE_NAME_NOT_UTF8__ID;
goto _errorFound;
}
if((flags & CFR_Xfuture) && (bcvCheckName(&cpBase[value]))) {
errorCode = J9NLS_CFR_ERR_LOCAL_VARIABLE_NAME__ID;
goto _errorFound;
}
}
value = ((J9CfrAttributeLocalVariableTypeTable*)attrib)->localVariableTypeTable[j].signatureIndex;
if((0 == value)||(value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if((cpBase)&&(cpBase[value].tag != CFR_CONSTANT_Utf8)) {
errorCode = J9NLS_CFR_ERR_LOCAL_VARIABLE_SIGNATURE_NOT_UTF8__ID;
goto _errorFound;
}
}
break;
case CFR_ATTRIBUTE_InnerClasses:
{
BOOLEAN cycleOfInnerClassFound = FALSE;
if (classes != NULL) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_INNER_CLASS_ATTRIBUTES__ID;
goto _errorFound;
}
innerClassArrayIndexTable = j9mem_allocate_memory(cpCount * sizeof(I_32), J9MEM_CATEGORY_CLASSES);
if (NULL == innerClassArrayIndexTable) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(-2);
return -2;
}
memset(innerClassArrayIndexTable, -1, cpCount * sizeof(I_32));
classes = (J9CfrAttributeInnerClasses*)attrib;
for (j = 0; j < classes->numberOfClasses; j++) {
value = classes->classes[j].innerClassInfoIndex;
if ((0 == value)||(value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (cpBase[value].tag != CFR_CONSTANT_Class) {
errorCode = J9NLS_CFR_ERR_INNER_CLASS_NOT_CLASS__ID;
goto _errorFound;
}
innerClassArrayIndexTable[value] = j;
value = classes->classes[j].outerClassInfoIndex;
if ((0 != value) && (value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if ((0 != value) && (cpBase[value].tag != CFR_CONSTANT_Class)) {
errorCode = J9NLS_CFR_ERR_OUTER_CLASS_NOT_CLASS__ID;
goto _errorFound;
}
if (0 != value) {
J9CfrConstantPoolInfo* outerClassInfoUtf8 = &cpBase[cpBase[value].slot1];
if (CFR_CONSTANT_Utf8 != outerClassInfoUtf8->tag) {
errorCode = J9NLS_CFR_ERR_OUTER_CLASS_NAME_NOT_UTF8__ID;
goto _errorFound;
}
if (0 == outerClassInfoUtf8->slot1) {
errorCode = J9NLS_CFR_ERR_OUTER_CLASS_UTF8_ZERO_LENGTH__ID;
goto _errorFound;
}
if ('[' == outerClassInfoUtf8->bytes[0]) {
errorCode = J9NLS_CFR_ERR_OUTER_CLASS_BAD_ARRAY_CLASS__ID;
goto _errorFound;
}
}
value = classes->classes[j].innerNameIndex;
if ((0 != value) && (value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if ((0 != value) && (cpBase[value].tag != CFR_CONSTANT_Utf8)) {
errorCode = J9NLS_CFR_ERR_INNER_NAME_NOT_UTF8__ID;
goto _errorFound;
}
}
for (j = 0; ((j < classes->numberOfClasses) && !cycleOfInnerClassFound); j++) {
U_32 valueInnerClassInfoIndex = classes->classes[j].innerClassInfoIndex;
U_32 valueOuterClassInfoIndex = classes->classes[j].outerClassInfoIndex;
J9CfrConstantPoolInfo* innerClassInfoUtf8 = &cpBase[cpBase[valueInnerClassInfoIndex].slot1];
J9CfrConstantPoolInfo* outerClassInfoUtf8 = &cpBase[cpBase[valueOuterClassInfoIndex].slot1];
I_32 nextInnerClassArrayIndex = -1;
while (!cycleOfInnerClassFound) {
if (utf8EqualUtf8(innerClassInfoUtf8, outerClassInfoUtf8)) {
cycleOfInnerClassFound = TRUE;
break;
}
nextInnerClassArrayIndex = innerClassArrayIndexTable[valueOuterClassInfoIndex];
if (nextInnerClassArrayIndex >= 0) {
valueOuterClassInfoIndex = classes->classes[nextInnerClassArrayIndex].outerClassInfoIndex;
outerClassInfoUtf8 = &cpBase[cpBase[valueOuterClassInfoIndex].slot1];
} else {
break;
}
}
}
if (!cycleOfInnerClassFound) {
for (j = 0; j < classes->numberOfClasses; j++) {
for (k = j + 1; k < classes->numberOfClasses; k++) {
if (classes->classes[j].innerClassInfoIndex == classes->classes[k].innerClassInfoIndex) {
errorCode = J9NLS_CFR_ERR_DUPLICATE_INNER_CLASS_ENTRY__ID;
goto _errorFound;
}
}
}
}
if (NULL != innerClassArrayIndexTable) {
j9mem_free_memory(innerClassArrayIndexTable);
innerClassArrayIndexTable = NULL;
}
break;
}
case CFR_ATTRIBUTE_EnclosingMethod:
if (enclosing != NULL) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_ENCLOSING_METHOD_ATTRIBUTES__ID;
goto _errorFound;
}
enclosing = (J9CfrAttributeEnclosingMethod*)attrib;
value = enclosing->classIndex;
if ((0 == value) || (value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if(cpBase[value].tag != CFR_CONSTANT_Class) {
errorCode = J9NLS_CFR_ERR_ENCLOSING_METHOD_CLASS_INDEX_NOT_CLASS__ID;
goto _errorFound;
}
value = enclosing->methodIndex;
if(value >= cpCount) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if((0 != value) && (cpBase[value].tag != CFR_CONSTANT_NameAndType)) {
errorCode = J9NLS_CFR_ERR_ENCLOSING_METHOD_METHOD_INDEX_NOT_NAME_AND_TYPE__ID;
goto _errorFound;
}
break;
case CFR_ATTRIBUTE_BootstrapMethods:
{
J9CfrAttributeBootstrapMethods* bootstrapMethods = (J9CfrAttributeBootstrapMethods *) attrib;
if (maxBootstrapMethodIndex >= (I_32) bootstrapMethods->numberOfBootstrapMethods) {
errorCode = J9NLS_CFR_ERR_BOOTSTRAP_METHOD_TABLE_ABSENT_OR_WRONG_SIZE__ID;
goto _errorFound;
}
bootstrapMethodAttributeRead = TRUE;
for (j = 0; j < bootstrapMethods->numberOfBootstrapMethods; j++) {
U_16 numberOfBootstrapArguments = 0;
J9CfrBootstrapMethod *bsm = &bootstrapMethods->bootstrapMethods[j];
value = bsm->bootstrapMethodIndex;
if ((0 == value) || (value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (cpBase[value].tag != CFR_CONSTANT_MethodHandle) {
errorCode = J9NLS_CFR_ERR_BOOTSTRAP_METHODHANDLE__ID;
goto _errorFound;
}
numberOfBootstrapArguments = bsm->numberOfBootstrapArguments;
for (k = 0; k < numberOfBootstrapArguments; k++) {
U_8 cpValueTag = 0;
value = bsm->bootstrapArguments[k];
if ((0 == value) || (value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
cpValueTag = cpBase[value].tag;
switch(cpValueTag) {
case CFR_CONSTANT_String:
case CFR_CONSTANT_Class:
case CFR_CONSTANT_Integer:
case CFR_CONSTANT_Long:
case CFR_CONSTANT_Float:
case CFR_CONSTANT_Double:
case CFR_CONSTANT_MethodHandle:
case CFR_CONSTANT_MethodType:
case CFR_CONSTANT_Dynamic:
break;
default:
errorCode = J9NLS_CFR_ERR_BAD_BOOTSTRAP_ARGUMENT_ENTRY__ID;
buildBootstrapMethodError((J9CfrError *)segment, errorCode, errorType, attrib->romAddress, j, value, cpValueTag);
return -1;
}
}
}
}
break;
case CFR_ATTRIBUTE_StackMapTable:
if (extra == OUTSIDE_CODE) {
errorCode = J9NLS_CFR_ERR_STACK_MAP_ATTRIBUTE_OUTSIDE_CODE_ATTRIBUTE__ID;
goto _errorFound;
}
if (foundStackMap) {
errorCode = J9NLS_CFR_ERR_MULTIPLE_STACK_MAP_ATTRIBUTES__ID;
goto _errorFound;
}
foundStackMap = TRUE;
break;
case CFR_ATTRIBUTE_Record:
value = ((J9CfrAttributeRecord*)attrib)->nameIndex;
if ((0 == value) || (value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if ((0 != value) && (cpBase[value].tag != CFR_CONSTANT_Utf8)) {
errorCode = J9NLS_CFR_ERR_RECORD_NAME_NOT_UTF8__ID;
goto _errorFound;
}
for (j = 0; j < ((J9CfrAttributeRecord*)attrib)->numberOfRecordComponents; j++) {
J9CfrRecordComponent* recordComponent = &(((J9CfrAttributeRecord*)attrib)->recordComponents[j]);
value = recordComponent->nameIndex;
if ((0 == value) || (value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if ((0 != value) && (cpBase[value].tag != CFR_CONSTANT_Utf8)) {
errorCode = J9NLS_CFR_ERR_RECORD_COMPONENT_NAME_NOT_UTF8__ID;
goto _errorFound;
}
value = recordComponent->descriptorIndex;
if ((0 == value) || (value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if ((0 != value) && (cpBase[value].tag != CFR_CONSTANT_Utf8)) {
errorCode = J9NLS_CFR_ERR_RECORD_COMPONENT_DESCRIPTOR_NOT_UTF8__ID;
goto _errorFound;
}
if (checkAttributes(portLib, classfile, recordComponent->attributes, recordComponent->attributesCount, segment, -1, OUTSIDE_CODE, flags)) {
return -1;
}
}
break;
case CFR_ATTRIBUTE_PermittedSubclasses:
if ((classfile->majorVersion > 59)
|| ((59 == classfile->majorVersion) && (65535 == classfile->minorVersion))
) {
enablePermittedSubclassErrors = TRUE;
}
if (J9_ARE_ANY_BITS_SET(classfile->accessFlags, CFR_ACC_FINAL)) {
if (enablePermittedSubclassErrors) {
errorCode = J9NLS_CFR_FINAL_CLASS_CANNOT_BE_SEALED__ID;
goto _errorFound;
}
break;
}
value = ((J9CfrAttributePermittedSubclasses*)attrib)->nameIndex;
if ((0 == value) || (value >= cpCount)) {
if (enablePermittedSubclassErrors) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
break;
}
if ((0 != value) && (cpBase[value].tag != CFR_CONSTANT_Utf8)) {
if (enablePermittedSubclassErrors) {
errorCode = J9NLS_CFR_ERR_PERMITTEDSUBCLASSES_NAME_NOT_UTF8__ID;
goto _errorFound;
}
break;
}
for (j = 0; j < ((J9CfrAttributePermittedSubclasses*)attrib)->numberOfClasses; j++) {
value = ((J9CfrAttributePermittedSubclasses*)attrib)->classes[j];
if ((0 == value) || (value >= cpCount)) {
if (enablePermittedSubclassErrors) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
break;
}
if ((0 != value) && (cpBase[value].tag != CFR_CONSTANT_Class)) {
if (enablePermittedSubclassErrors) {
errorCode = J9NLS_CFR_ERR_PERMITTEDSUBCLASSES_CLASS_ENTRY_NOT_CLASS_TYPE__ID;
goto _errorFound;
}
break;
}
}
break;
#if JAVA_SPEC_VERSION >= 11
case CFR_ATTRIBUTE_NestHost:
value = ((J9CfrAttributeNestHost*)attrib)->hostClassIndex;
if ((!value) || (value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (CFR_CONSTANT_Class != cpBase[value].tag) {
errorCode = J9NLS_CFR_ERR_BAD_NEST_HOST_INDEX__ID;
goto _errorFound;
}
break;
case CFR_ATTRIBUTE_NestMembers: {
U_16 nestMembersCount = ((J9CfrAttributeNestMembers*)attrib)->numberOfClasses;
for (j = 0; j < nestMembersCount; j++) {
value = ((J9CfrAttributeNestMembers*)attrib)->classes[j];
if ((0 == value) || (value >= cpCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
goto _errorFound;
}
if (CFR_CONSTANT_Class != cpBase[value].tag) {
errorCode = J9NLS_CFR_ERR_NEST_MEMBERS_NAME_NOT_CONSTANT_CLASS__ID;
goto _errorFound;
}
}
break;
}
#endif
case CFR_ATTRIBUTE_StackMap:
case CFR_ATTRIBUTE_Synthetic:
case CFR_ATTRIBUTE_Deprecated:
case CFR_ATTRIBUTE_StrippedLineNumberTable:
case CFR_ATTRIBUTE_StrippedLocalVariableTable:
case CFR_ATTRIBUTE_StrippedInnerClasses:
case CFR_ATTRIBUTE_StrippedUnknown:
case CFR_ATTRIBUTE_Unknown:
break;
}
}
if (!bootstrapMethodAttributeRead && (maxBootstrapMethodIndex >= 0)) {
errorCode = J9NLS_CFR_ERR_BOOTSTRAP_METHOD_TABLE_ABSENT_OR_WRONG_SIZE__ID;
buildError((J9CfrError *) segment, errorCode, errorType, 0);
return -1;
}
return 0;
_errorFound:
if (NULL != innerClassArrayIndexTable) {
j9mem_free_memory(innerClassArrayIndexTable);
innerClassArrayIndexTable = NULL;
}
buildError((J9CfrError *) segment, errorCode, errorType, attrib->romAddress);
return -1;
}
static I_32
checkClassVersion(J9CfrClassFile* classfile, U_8* segment, U_32 vmVersionShifted, U_32 flags)
{
const U_32 offset = 6;
const U_16 max_allowed_version = vmVersionShifted >> BCT_MajorClassFileVersionMaskShift;
const U_16 majorVersion = classfile->majorVersion;
const U_16 minorVersion = classfile->minorVersion;
U_32 errorCode = J9NLS_CFR_ERR_MAJOR_VERSION__ID;
if (majorVersion == max_allowed_version) {
errorCode = J9NLS_CFR_ERR_MINOR_VERSION__ID;
if (0 == minorVersion) {
return 0;
} else if (0xffff == minorVersion) {
errorCode = J9NLS_CFR_ERR_PREVIEW_VERSION__ID;
if (J9_ARE_ANY_BITS_SET(flags, BCT_AnyPreviewVersion | BCT_EnablePreview)) {
return 0;
}
}
} else if ((majorVersion >= 45) && (majorVersion < max_allowed_version)) {
errorCode = J9NLS_CFR_ERR_MINOR_VERSION__ID;
if (majorVersion <= 55) {
return 0;
}
if (0 == minorVersion) {
return 0;
}
if (0xffff == minorVersion) {
errorCode = J9NLS_CFR_ERR_PREVIEW_VERSION__ID;
if (J9_ARE_ANY_BITS_SET(flags, BCT_AnyPreviewVersion)) {
return 0;
}
}
}
buildError((J9CfrError *) segment, errorCode, CFR_ThrowUnsupportedClassVersionError, offset);
return -1;
}
static I_32
checkClass(J9PortLibrary *portLib, J9CfrClassFile* classfile, U_8* segment, U_32 endOfConstantPool, U_32 vmVersionShifted, U_32 flags)
{
U_32 value, errorCode, offset;
U_32 i;
I_32 maxBootstrapMethodIndex = -1;
if(checkPool(classfile, segment, (U_8*)10, &maxBootstrapMethodIndex, flags)) {
return -1;
}
value = classfile->accessFlags & CFR_CLASS_ACCESS_MASK;
if ((flags & BCT_MajorClassFileVersionMask) < BCT_JavaMajorVersionShifted(5)) {
value &= ~CFR_CLASS_ACCESS_NEWJDK5_MASK;
if (value & CFR_ACC_INTERFACE) {
value &= ~CFR_ACC_SUPER;
}
}
if ((value & CFR_ACC_ANNOTATION) && (! (value & CFR_ACC_INTERFACE))) {
errorCode = J9NLS_CFR_ERR_ANNOTATION_NOT_INTERFACE__ID;
offset = endOfConstantPool;
goto _errorFound;
}
if ((value & CFR_ACC_FINAL)&&(value & CFR_ACC_ABSTRACT)) {
errorCode = J9NLS_CFR_ERR_FINAL_ABSTRACT_CLASS__ID;
offset = endOfConstantPool;
goto _errorFound;
}
if ((value & CFR_ACC_INTERFACE) && (value & ~CFR_INTERFACE_CLASS_ACCESS_MASK))
{
errorCode = J9NLS_CFR_ERR_INTERFACE_CLASS__ID;
offset = endOfConstantPool;
goto _errorFound;
}
value = classfile->thisClass;
if ((!value)||(value >= classfile->constantPoolCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
offset = endOfConstantPool + 2;
goto _errorFound;
}
if ((classfile->constantPool) && (classfile->constantPool[value].tag != CFR_CONSTANT_Class)) {
errorCode = J9NLS_CFR_ERR_NOT_CLASS__ID;
offset = endOfConstantPool + 2;
goto _errorFound;
}
if ((classfile->constantPool) && (CFR_CONSTANT_Class == classfile->constantPool[value].tag)) {
value = classfile->constantPool[classfile->thisClass].slot1;
if (J9_ARE_ALL_BITS_SET(classfile->constantPool[value].flags1, CFR_FOUND_SEPARATOR_IN_MUE_FORM) && (classfile->majorVersion < 48)) {
errorCode = J9NLS_CFR_ERR_BAD_CLASS_NAME__ID;
offset = endOfConstantPool + 2;
goto _errorFound;
}
}
value = classfile->superClass;
if (value >= classfile->constantPoolCount) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
offset = endOfConstantPool + 4;
goto _errorFound;
}
if (0 == value) {
if(!utf8Equal(&classfile->constantPool[classfile->constantPool[classfile->thisClass].slot1], "java/lang/Object", 16)) {
errorCode = J9NLS_CFR_ERR_NULL_SUPER__ID;
offset = endOfConstantPool + 4;
goto _errorFound;
}
} else if (classfile->constantPool[value].tag != CFR_CONSTANT_Class) {
errorCode = J9NLS_CFR_ERR_SUPER_NOT_CLASS__ID;
offset = endOfConstantPool + 4;
goto _errorFound;
}
for (i = 0; i < classfile->interfacesCount; i++) {
U_32 j;
J9CfrConstantPoolInfo* cpInfo;
value = classfile->interfaces[i];
if((!value)||(value >= classfile->constantPoolCount)) {
errorCode = J9NLS_CFR_ERR_BAD_INDEX__ID;
offset = endOfConstantPool + 4 + (i << 1);
goto _errorFound;
}
cpInfo = &classfile->constantPool[value];
if(cpInfo->tag != CFR_CONSTANT_Class) {
errorCode = J9NLS_CFR_ERR_INTERFACE_NOT_CLASS__ID;
offset = endOfConstantPool + 4 + (i << 1);
goto _errorFound;
}
for (j = 0; j < i; j++) {
U_32 otherValue = classfile->interfaces[j];
J9CfrConstantPoolInfo* otherCpInfo = &classfile->constantPool[otherValue];
if(utf8EqualUtf8(&classfile->constantPool[cpInfo->slot1], &classfile->constantPool[otherCpInfo->slot1])) {
errorCode = J9NLS_CFR_ERR_DUPLICATE_INTERFACE__ID;
offset = endOfConstantPool + 4 + (i << 1);
goto _errorFound;
}
}
}
if (classfile->accessFlags & CFR_ACC_INTERFACE) {
if(!utf8Equal(&classfile->constantPool[classfile->constantPool[classfile->superClass].slot1], "java/lang/Object", 16)) {
errorCode = J9NLS_CFR_ERR_INTERFACE_SUPER_NOT_OBJECT__ID;
offset = endOfConstantPool + 4 + (i << 1);
goto _errorFound;
}
}
if (checkFields(portLib, classfile, segment, flags)) {
return -1;
}
if (checkMethods(portLib, classfile, segment, vmVersionShifted, flags)) {
return -1;
}
if (checkDuplicateMembers(portLib, classfile, segment, flags, (UDATA) sizeof(J9CfrField))) {
return -1;
}
if (checkDuplicateMembers(portLib, classfile, segment, flags, (UDATA) sizeof(J9CfrMethod))) {
return -1;
}
if (checkAttributes(portLib, classfile, classfile->attributes, classfile->attributesCount, segment, maxBootstrapMethodIndex, OUTSIDE_CODE, flags)) {
return -1;
}
return 0;
_errorFound:
buildError((J9CfrError *) segment, errorCode, CFR_ThrowClassFormatError, offset);
return -1;
}
#define VERBOSE_START(phase) \
do { \
if (NULL != verboseContext) { \
romVerboseRecordPhaseStart(verboseContext, phase); \
} \
} while (0)
#define VERBOSE_END(phase) \
do { \
if (NULL != verboseContext) { \
romVerboseRecordPhaseEnd(verboseContext, phase); \
} \
} while (0)
I_32
j9bcutil_readClassFileBytes(J9PortLibrary *portLib,
IDATA (*verifyFunction) (J9PortLibrary *aPortLib, J9CfrClassFile* classfile, U_8* segment, U_8* segmentLength, U_8* freePointer, U_32 vmVersionShifted, U_32 flags, I_32 *hasRET),
U_8* data, UDATA dataLength, U_8* segment, UDATA segmentLength, U_32 flags, U_8** segmentFreePointer, void *verboseContext, UDATA findClassFlags, UDATA romClassSortingThreshold)
{
U_8* dataEnd;
U_8* segmentEnd;
U_8* index;
U_8* freePointer;
U_8* endOfConstantPool;
J9CfrClassFile* classfile;
I_32 result;
UDATA errorCode;
UDATA offset = 0;
UDATA i;
I_32 hasRET = 0;
UDATA syntheticFound = FALSE;
U_32 vmVersionShifted = flags & BCT_MajorClassFileVersionMask;
U_16 constantPoolAllocationSize = 0;
U_16 errorAction = CFR_ThrowClassFormatError;
Trc_BCU_j9bcutil_readClassFileBytes_Entry();
if (segmentLength < (UDATA) sizeof(J9CfrClassFile)) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(-2);
return -2;
}
index = data;
dataEnd = data + dataLength;
freePointer = segment;
segmentEnd = segment + segmentLength;
ALLOC(classfile, J9CfrClassFile);
CHECK_EOF(8);
NEXT_U32(classfile->magic, index);
if (classfile->magic != (U_32) CFR_MAGIC) {
errorCode = J9NLS_CFR_ERR_MAGIC__ID;
offset = index - data - 4;
goto _errorFound;
}
NEXT_U16(classfile->minorVersion, index);
NEXT_U16(classfile->majorVersion, index);
if (checkClassVersion(classfile, segment, vmVersionShifted, flags)) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(-1);
return -1;
}
if (J9_ARE_ANY_BITS_SET(flags, BCT_BasicCheckOnly)) {
Trc_BCU_j9bcutil_readClassFileBytes_Basic_Check_Exit(0);
return 0;
}
if (J9_ARE_ANY_BITS_SET(findClassFlags, J9_FINDCLASS_FLAG_UNSAFE)) {
flags |= BCT_Unsafe;
}
flags &= ~BCT_MajorClassFileVersionMask;
flags |= ((UDATA) classfile->majorVersion) << BCT_MajorClassFileVersionMaskShift;
CHECK_EOF(2);
NEXT_U16(classfile->constantPoolCount, index);
constantPoolAllocationSize = classfile->constantPoolCount;
if (constantPoolAllocationSize < 1) {
errorCode = J9NLS_CFR_ERR_CONSTANT_POOL_EMPTY__ID;
offset = index - data - 2;
goto _errorFound;
}
VERBOSE_START(ParseClassFileConstantPool);
if (J9_ARE_ANY_BITS_SET(findClassFlags, J9_FINDCLASS_FLAG_ANON | J9_FINDCLASS_FLAG_HIDDEN)) {
if (constantPoolAllocationSize == MAX_CONSTANT_POOL_SIZE) {
Trc_BCU_j9bcutil_readClassFileBytes_MaxCPCount();
return BCT_ERR_OUT_OF_MEMORY;
}
constantPoolAllocationSize += 1;
}
if (!ALLOC_ARRAY(classfile->constantPool, constantPoolAllocationSize, J9CfrConstantPoolInfo)) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(-2);
return -2;
}
if ((result = readPool(classfile, data, dataEnd, segment, segmentEnd, &index, &freePointer)) != 0) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(result);
return result;
}
endOfConstantPool = index;
VERBOSE_END(ParseClassFileConstantPool);
CHECK_EOF(8);
classfile->accessFlags = NEXT_U16(classfile->accessFlags, index);
if (((flags & BCT_MajorClassFileVersionMask) >= BCT_JavaMajorVersionShifted(9))
&& J9_ARE_ALL_BITS_SET(classfile->accessFlags, CFR_ACC_MODULE)
) {
errorCode = J9NLS_CFR_ERR_MODULE_IS_INVALID_CLASS__ID;
errorAction = CFR_ThrowNoClassDefFoundError;
offset = index - data - 2;
goto _errorFound;
}
#if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)
if ((flags & BCT_MajorClassFileVersionMask) < BCT_JavaMajorVersionShifted(19)) {
classfile->accessFlags &= ~(CFR_ACC_VALUE_TYPE | CFR_ACC_PRIMITIVE_VALUE_TYPE | CFR_ACC_ATOMIC);
}
if (J9_ARE_ALL_BITS_SET(classfile->accessFlags, CFR_ACC_PRIMITIVE_VALUE_TYPE)
&& J9_ARE_NO_BITS_SET(classfile->accessFlags, CFR_ACC_VALUE_TYPE)
) {
errorCode = J9NLS_CFR_ERR_VALUE_FLAG_MISSING_ON_PRIMITIVE_CLASS__ID;
offset = index - data - 2;
goto _errorFound;
}
#endif
classfile->accessFlags &= CFR_CLASS_ACCESS_MASK;
classfile->j9Flags = 0;
if ((classfile->accessFlags & (CFR_ACC_INTERFACE | CFR_ACC_ABSTRACT)) == CFR_ACC_INTERFACE) {
if ((flags & BCT_MajorClassFileVersionMask) >= BCT_JavaMajorVersionShifted(6)) {
errorCode = J9NLS_CFR_ERR_INTERFACE_NOT_ABSTRACT__ID;
offset = index - data - 2;
goto _errorFound;
} else {
classfile->accessFlags |= CFR_ACC_ABSTRACT;
}
}
NEXT_U16(classfile->thisClass, index);
NEXT_U16(classfile->superClass, index);
NEXT_U16(classfile->interfacesCount, index);
if(!ALLOC_ARRAY(classfile->interfaces, classfile->interfacesCount, U_16)) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(-2);
return -2;
}
CHECK_EOF(classfile->interfacesCount << 1);
for(i = 0; i < classfile->interfacesCount; i++) {
NEXT_U16(classfile->interfaces[i], index);
}
CHECK_EOF(2);
NEXT_U16(classfile->fieldsCount, index);
VERBOSE_START(ParseClassFileFields);
if(!ALLOC_ARRAY(classfile->fields, classfile->fieldsCount, J9CfrField)) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(-2);
return -2;
}
if((result = readFields(classfile, data, dataEnd, segment, segmentEnd, &index, &freePointer, flags)) != 0) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(result);
return result;
}
VERBOSE_END(ParseClassFileFields);
CHECK_EOF(2);
NEXT_U16(classfile->methodsCount, index);
VERBOSE_START(ParseClassFileMethods);
if(!ALLOC_ARRAY(classfile->methods, classfile->methodsCount, J9CfrMethod)) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(-2);
return -2;
}
if((result = readMethods(classfile, data, dataEnd, segment, segmentEnd, &index, &freePointer, flags)) != 0) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(result);
return result;
}
VERBOSE_END(ParseClassFileMethods);
if (classfile->methodsCount >= romClassSortingThreshold) {
sortMethodIndex(classfile->constantPool, classfile->methods, 0, classfile->methodsCount - 1);
}
CHECK_EOF(2);
NEXT_U16(classfile->attributesCount, index);
VERBOSE_START(ParseClassFileAttributes);
if(!ALLOC_ARRAY(classfile->attributes, classfile->attributesCount, J9CfrAttribute*)) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(-2);
return -2;
}
if((result = readAttributes(classfile, &(classfile->attributes), classfile->attributesCount, data, dataEnd, segment, segmentEnd, &index, &freePointer, flags, &syntheticFound)) != 0) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(result);
return result;
}
if (syntheticFound) {
classfile->accessFlags |= CFR_ACC_SYNTHETIC;
}
VERBOSE_END(ParseClassFileAttributes);
VERBOSE_START(ParseClassFileCheckClass);
if(index != dataEnd) {
offset = index - data;
if (dataLength < offset) {
errorCode = J9NLS_CFR_ERR_UNEXPECTED_EOF__ID;
offset = dataLength;
} else {
errorCode = J9NLS_CFR_ERR_EXPECTED_EOF__ID;
}
goto _errorFound;
}
classfile->classFileSize = (U_32) dataLength;
if (0 != (flags & CFR_StaticVerification)) {
if(checkClass(portLib, classfile, segment, (U_32) (endOfConstantPool - data), vmVersionShifted, flags)) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(-1);
return -1;
}
}
VERBOSE_END(ParseClassFileCheckClass);
VERBOSE_START(ParseClassFileVerifyClass);
if (0 != (flags & CFR_StaticVerification)) {
if((result = (I_32)(verifyFunction)(portLib, classfile, segment, segmentEnd, freePointer, vmVersionShifted, flags, &hasRET)) != 0) {
Trc_BCU_j9bcutil_readClassFileBytes_Exit(result);
return result;
}
} else {
if (classfile->majorVersion < 51) {
hasRET = checkForJsrs(classfile);
}
}
VERBOSE_END(ParseClassFileVerifyClass);
classfile->constantPoolCount = constantPoolAllocationSize;
VERBOSE_START(ParseClassFileInlineJSRs);
if (((classfile->j9Flags & CFR_J9FLAG_HAS_JSR) == CFR_J9FLAG_HAS_JSR) && ((flags & CFR_LeaveJSRs) == 0)) {
J9JSRIData inlineBuffers;
J9CfrMethod *method;
if ((classfile->majorVersion >= 51)
|| (((flags & J9_VERIFY_NO_FALLBACK) == J9_VERIFY_NO_FALLBACK) && (classfile->majorVersion == 50))
) {
errorCode = J9NLS_CFR_ERR_FOUND_JSR_IN_CLASS_VER_51__ID;
buildMethodErrorWithExceptionDetails((J9CfrError *) segment, errorCode, 0, CFR_ThrowVerifyError, 0, 0, &(classfile->methods[0]), classfile->constantPool, 0, -1, 0);
Trc_BCU_j9bcutil_readClassFileBytes_VerifyError_Exception(((J9CfrError *) segment)->errorCode, getJ9CfrErrorDescription(portLib, (J9CfrError *) segment));
Trc_BCU_j9bcutil_readClassFileBytes_Exit(-1);
return -1;
}
memset (&inlineBuffers, 0, sizeof(J9JSRIData));
inlineBuffers.portLib = portLib;
J9_CFR_ALIGN(freePointer, UDATA);
inlineBuffers.freePointer = freePointer;
inlineBuffers.segmentEnd = segmentEnd;
for (i = 0; i < classfile->methodsCount; i++) {
method = &(classfile->methods[i]);
if ((method->j9Flags & CFR_J9FLAG_HAS_JSR) == CFR_J9FLAG_HAS_JSR) {
inlineBuffers.codeAttribute = method->codeAttribute;
inlineBuffers.sourceBuffer = method->codeAttribute->code;
inlineBuffers.sourceBufferSize = method->codeAttribute->codeLength;
inlineBuffers.constantPool = classfile->constantPool;
inlineBuffers.maxStack = method->codeAttribute->maxStack;
inlineBuffers.maxLocals = method->codeAttribute->maxLocals;
inlineBuffers.flags = flags;
inlineBuffers.bytesAddedByJSRInliner = 0;
Trc_BCU_inlineJsrs_Entry((classfile->constantPool[classfile->constantPool[classfile->thisClass].slot1]).slot1, (classfile->constantPool[classfile->constantPool[classfile->thisClass].slot1]).bytes,
(classfile->constantPool[method->nameIndex]).slot1, (classfile->constantPool[method->nameIndex]).bytes,
(classfile->constantPool[method->descriptorIndex]).slot1, (classfile->constantPool[method->descriptorIndex]).bytes);
inlineJsrs(hasRET, classfile, &inlineBuffers);
if (inlineBuffers.errorCode) {
result = (I_32) inlineBuffers.errorCode;
if (inlineBuffers.errorCode == BCT_ERR_VERIFY_ERROR_INLINING) {
buildMethodErrorWithExceptionDetails((J9CfrError *)segment, inlineBuffers.verifyError, inlineBuffers.verboseErrorType, CFR_ThrowVerifyError,
(I_32) i, (U_16) inlineBuffers.verifyErrorPC, method, classfile->constantPool, inlineBuffers.errorLocalIndex, -1, 0);
((J9CfrError *)segment)->errorCatalog = (U_32) J9NLS_BCV_ERR_NO_ERROR__MODULE;
Trc_BCU_j9bcutil_readClassFileBytes_VerifyError_Exception(((J9CfrError *) segment)->errorCode, getJ9CfrErrorDescription(portLib, (J9CfrError *) segment));
Trc_BCU_inlineJsrs_Exit();
result = -1;
}
releaseInlineBuffers (&inlineBuffers);
Trc_BCU_j9bcutil_readClassFileBytes_Exit(result);
return result;
}
classfile->classFileSize += inlineBuffers.bytesAddedByJSRInliner;
Trc_BCU_inlineJsrs_Exit();
}
}
freePointer = inlineBuffers.freePointer;
releaseInlineBuffers (&inlineBuffers);
for (i = 0; i < classfile->methodsCount; i++) {
method = &(classfile->methods[i]);
if (CFR_J9FLAG_HAS_JSR == (method->j9Flags & CFR_J9FLAG_HAS_JSR)) {
method->j9Flags &= ~CFR_J9FLAG_HAS_JSR;
if (!ALLOC_ARRAY(method->codeAttribute->code, method->codeAttribute->codeLength, U_8)) {
Trc_BCU_inlineJsrs_Exit();
return -2;
}
memcpy(method->codeAttribute->code, method->codeAttribute->originalCode, method->codeAttribute->codeLength);
}
}
classfile->j9Flags &= ~CFR_J9FLAG_HAS_JSR;
}
VERBOSE_END(ParseClassFileInlineJSRs);
Trc_BCU_j9bcutil_readClassFileBytes_Exit(0);
if (segmentFreePointer != NULL) {
*segmentFreePointer = freePointer;
}
return 0;
_errorFound:
buildError((J9CfrError *) segment, errorCode, errorAction, offset);
switch(errorAction) {
case CFR_ThrowNoClassDefFoundError:
Trc_BCU_j9bcutil_readClassFileBytes_NoClassDefFoundError_Exception(((J9CfrError *) segment)->errorCode, getJ9CfrErrorDescription(portLib, (J9CfrError *) segment));
break;
default:
Trc_BCU_j9bcutil_readClassFileBytes_ClassFormatError_Exception(((J9CfrError *) segment)->errorCode, getJ9CfrErrorDescription(portLib, (J9CfrError *) segment));
}
Trc_BCU_j9bcutil_readClassFileBytes_Exit(-1);
return -1;
}
#undef VERBOSE_START
#undef VERBOSE_END
static BOOLEAN
utf8EqualUtf8(J9CfrConstantPoolInfo *utf8a, J9CfrConstantPoolInfo *utf8b)
{
if (utf8a->tag !=CFR_CONSTANT_Utf8) {
return FALSE;
}
if (utf8a == utf8b) {
return TRUE;
}
if ((utf8b->tag !=CFR_CONSTANT_Utf8) || (utf8a->slot1 != utf8b->slot1)) {
return FALSE;
}
return memcmp (utf8a->bytes, utf8b->bytes, utf8a->slot1) == 0;
}
static I_32
checkDuplicateMembers (J9PortLibrary* portLib, J9CfrClassFile * classfile, U_8 * segment, U_32 flags, UDATA memberSize)
{
if (flags & CFR_StaticVerification) {
#if DUP_TIMING
PORT_ACCESS_FROM_PORT(portLib);
U_64 startTime;
#endif
J9CfrMember *member;
U_32 i, j, errorCode;
UDATA count;
U_8* data;
if (memberSize == (UDATA) sizeof(J9CfrField)) {
count =classfile->fieldsCount;
data = (U_8*)classfile->fields;
errorCode = J9NLS_CFR_ERR_DUPLICATE_FIELD__ID;
} else {
count = classfile->methodsCount;
data = (U_8*)classfile->methods;
errorCode = J9NLS_CFR_ERR_DUPLICATE_METHOD__ID;
}
if (count >= DUP_HASH_THRESHOLD || DUP_TIMING) {
PORT_ACCESS_FROM_PORT(portLib);
U_16 *sortedIndices;
UDATA tableSize = findSmallestPrimeGreaterThanOrEqualTo(count * 2);
#if DUP_TIMING
startTime = j9time_hires_clock();
#endif
sortedIndices = j9mem_allocate_memory(tableSize * sizeof(U_16), J9MEM_CATEGORY_CLASSES);
if (sortedIndices != NULL) {
I_32 k;
memset(sortedIndices, 0, tableSize * sizeof(U_16));
for (k = (I_32) (count - 1); k >= 0; k--) {
U_32 hash = 0;
J9CfrConstantPoolInfo *name, *sig;
member = (J9CfrMember*)&data[memberSize * k];
name = &classfile->constantPool[member->nameIndex];
sig = &classfile->constantPool[member->descriptorIndex];
for (j = 0; j < name->slot1; j++) {
hash ^= (U_32)RandomValues[name->bytes[j]] << 8;
if (++j < name->slot1) hash ^= (U_32)RandomValues[name->bytes[j]] << 8;
if (++j < name->slot1) hash ^= (U_32)RandomValues[name->bytes[j]] << 16;
}
for (j = 0; j < sig->slot1; j++) {
hash ^= (U_32)RandomValues[sig->bytes[j]] << 8;
if (++j < sig->slot1) hash ^= (U_32)RandomValues[sig->bytes[j]] << 8;
if (++j < sig->slot1) hash ^= (U_32)RandomValues[sig->bytes[j]] << 16;
}
hash %= tableSize;
for (j = hash; sortedIndices[j];) {
J9CfrMember* dup = (J9CfrMember*)&data[memberSize * sortedIndices[j]];
if (memberEqual(classfile, member, dup)) {
goto fail;
}
j = j + 1;
if (j == tableSize) {
j = 0;
}
}
sortedIndices[j] = (U_16) k;
}
j9mem_free_memory(sortedIndices);
#if DUP_TIMING
j9tty_printf(PORTLIB, "Hash table for %6d elements: %lluus\n", count, j9time_hires_delta(startTime, j9time_hires_clock(), J9PORT_TIME_DELTA_IN_MICROSECONDS));
#else
return 0;
#endif
}
}
#if DUP_TIMING
startTime = j9time_hires_clock();
#endif
for (i = 0; i < count; i++) {
member = (J9CfrMember*)&data[memberSize * i];
for (j = 0; j < i; j++) {
J9CfrMember *dup = (J9CfrMember*)&data[memberSize * j];
if (memberEqual(classfile, member, dup)) {
fail:
buildError((J9CfrError *) segment, errorCode, CFR_ThrowClassFormatError, member->romAddress);
return -1;
}
}
}
#if DUP_TIMING
j9tty_printf(PORTLIB, "In-place for %8d elements: %lluus\n", count, j9time_hires_delta(startTime, j9time_hires_clock(), J9PORT_TIME_DELTA_IN_MICROSECONDS));
#endif
}
return 0;
}
static BOOLEAN
memberEqual(J9CfrClassFile * classfile, J9CfrMember* a, J9CfrMember* b)
{
return
utf8EqualUtf8 (&classfile->constantPool[a->nameIndex], &classfile->constantPool[b->nameIndex])
&& utf8EqualUtf8 (&classfile->constantPool[a->descriptorIndex], &classfile->constantPool[b->descriptorIndex]);
}
static I_32
readAnnotations(J9CfrClassFile * classfile, J9CfrAnnotation * pAnnotations, U_32 annotationCount, U_8 * data,
U_8 * dataEnd, U_8 * segment, U_8 * segmentEnd, U_8 ** pIndex, U_8 ** pFreePointer, U_32 flags)
{
J9CfrAnnotation *annotationList = pAnnotations;
U_8 *index = *pIndex;
U_8 *freePointer = *pFreePointer;
U_32 errorCode, offset;
U_32 i, j;
I_32 result;
for (i = 0; i < annotationCount; i++) {
CHECK_EOF(4);
NEXT_U16(annotationList[i].typeIndex, index);
if (annotationList[i].typeIndex >= classfile->constantPoolCount ) {
annotationList[i].typeIndex = 0;
annotationList[i].numberOfElementValuePairs = 0;
return BCT_ERR_INVALID_ANNOTATION;
}
NEXT_U16(annotationList[i].numberOfElementValuePairs, index);
if (!ALLOC_ARRAY(annotationList[i].elementValuePairs, annotationList[i].numberOfElementValuePairs, J9CfrAnnotationElementPair)) {
return BCT_ERR_OUT_OF_ROM;
}
for (j = 0; j < annotationList[i].numberOfElementValuePairs; j++) {
CHECK_EOF(2);
NEXT_U16(annotationList[i].elementValuePairs[j].elementNameIndex, index);
result = readAnnotationElement(classfile, &annotationList[i].elementValuePairs[j].value,
data, dataEnd, segment, segmentEnd, &index, &freePointer, flags);
if (result != 0) {
return result;
}
}
}
*pIndex = index;
*pFreePointer = freePointer;
return 0;
_errorFound:
return -1;
}
static I_32
readTypeAnnotation(J9CfrClassFile * classfile, J9CfrTypeAnnotation * tAnn, U_8 * data,
U_8 * dataEnd, U_8 * segment, U_8 * segmentEnd, U_8 ** pIndex, U_8 ** pFreePointer, U_32 flags)
{
U_8 targetType = 0;
U_8 *index = *pIndex;
U_32 errorCode = 0;
U_32 offset = 0;
U_32 i = 0;
I_32 result = 0;
U_8 *freePointer = *pFreePointer;
CHECK_EOF(1);
NEXT_U8(targetType, index);
tAnn->targetType = targetType;
Trc_BCU_TypeAnnotation(targetType);
switch (targetType) {
case CFR_TARGET_TYPE_TypeParameterGenericClass:
case CFR_TARGET_TYPE_TypeParameterGenericMethod: {
J9CfrTypeParameterTarget *t = &(tAnn->targetInfo.typeParameterTarget);
CHECK_EOF(1);
NEXT_U8(t->typeParameterIndex, index);
};
break;
case CFR_TARGET_TYPE_TypeInExtends: {
J9CfrSupertypeTarget *t = &(tAnn->targetInfo.supertypeTarget);
CHECK_EOF(2);
NEXT_U16(t->supertypeIndex, index);
}
break;
case CFR_TARGET_TYPE_TypeInBoundOfGenericClass:
case CFR_TARGET_TYPE_TypeInBoundOfGenericMethod: {
J9CfrTypeParameterBoundTarget *t = &(tAnn->targetInfo.typeParameterBoundTarget);
CHECK_EOF(2);
NEXT_U8(t->typeParameterIndex, index);
NEXT_U8(t->boundIndex, index);
}
break;
case CFR_TARGET_TYPE_TypeInFieldDecl:
case CFR_TARGET_TYPE_ReturnType:
case CFR_TARGET_TYPE_ReceiverType:
break;
case CFR_TARGET_TYPE_TypeInFormalParam: {
J9CfrMethodFormalParameterTarget *t = &(tAnn->targetInfo.methodFormalParameterTarget);
CHECK_EOF(1);
NEXT_U8(t->formalParameterIndex, index);
};
break;
case CFR_TARGET_TYPE_TypeInThrows: {
J9CfrThrowsTarget *t = &(tAnn->targetInfo.throwsTarget);
CHECK_EOF(2);
NEXT_U16(t->throwsTypeIndex, index);
}
break;
case CFR_TARGET_TYPE_TypeInLocalVar:
case CFR_TARGET_TYPE_TypeInResourceVar: {
U_32 ti;
J9CfrLocalvarTarget *t = &(tAnn->targetInfo.localvarTarget);
CHECK_EOF(2);
NEXT_U16(t->tableLength, index);
if (!ALLOC_ARRAY(t->table, t->tableLength, J9CfrLocalvarTargetEntry)) {
return -2;
}
for (ti=0; ti < t->tableLength; ++ti) {
J9CfrLocalvarTargetEntry *te = &(t->table[ti]);
CHECK_EOF(6);
NEXT_U16(te->startPC, index);
NEXT_U16(te->length, index);
NEXT_U16(te->index, index);
}
};
break;
case CFR_TARGET_TYPE_TypeInExceptionParam: {
J9CfrCatchTarget *t = &(tAnn->targetInfo.catchTarget);
CHECK_EOF(2);
NEXT_U16(t->exceptiontableIndex, index);
}
break;
case CFR_TARGET_TYPE_TypeInInstanceof:
case CFR_TARGET_TYPE_TypeInNew:
case CFR_TARGET_TYPE_TypeInMethodrefNew:
case CFR_TARGET_TYPE_TypeInMethodrefIdentifier: {
J9CfrOffsetTarget *t = &(tAnn->targetInfo.offsetTarget);
CHECK_EOF(2);
NEXT_U16(t->offset, index);
}
break;
case CFR_TARGET_TYPE_TypeInCast:
case CFR_TARGET_TYPE_TypeForGenericConstructorInNew:
case CFR_TARGET_TYPE_TypeForGenericMethodInvocation:
case CFR_TARGET_TYPE_TypeForGenericConstructorInMethodRef:
case CFR_TARGET_TYPE_TypeForGenericMethodInvocationInMethodRef: {
J9CfrTypeArgumentTarget *t = &(tAnn->targetInfo.typeArgumentTarget);
CHECK_EOF(3);
NEXT_U16(t->offset, index);
NEXT_U8(t->typeArgumentIndex, index);
}
break;
default:
errorCode = J9NLS_CFR_ERR_BAD_TARGET_TYPE_TAG;
offset = (U_32) (index - data - 1);
goto _errorFound;
}
CHECK_EOF(1);
NEXT_U8(tAnn->typePath.pathLength, index);
if (!ALLOC_ARRAY(tAnn->typePath.path, tAnn->typePath.pathLength, J9CfrTypePathEntry)) {
return -2;
}
for (i=0; i < tAnn->typePath.pathLength; ++i) {
J9CfrTypePathEntry *entry = &tAnn->typePath.path[i];
CHECK_EOF(2);
NEXT_U8(entry->typePathKind, index);
NEXT_U8(entry->typeArgumentIndex, index);
}
result = readAnnotations(classfile, &(tAnn->annotation), 1, data,
dataEnd, segment, segmentEnd, &index, &freePointer, flags);
*pFreePointer = freePointer;
*pIndex = index;
return result;
_errorFound:
return BCT_ERR_INVALID_ANNOTATION;
}
static I_32
readAnnotationElement(J9CfrClassFile * classfile, J9CfrAnnotationElement ** pAnnotationElement, U_8 * data,
U_8 * dataEnd, U_8 * segment, U_8 * segmentEnd, U_8 ** pIndex, U_8 ** pFreePointer, U_32 flags)
{
J9CfrAnnotationElement *element;
U_8 *index = *pIndex;
U_8 *freePointer = *pFreePointer;
J9CfrAnnotation *annotation;
J9CfrAnnotationElementArray *array;
J9CfrAnnotationElement **arrayWalk;
U_32 errorCode, offset;
U_32 j;
I_32 result;
U_32 annotationTag;
CHECK_EOF(1);
NEXT_U8(annotationTag, index);
switch (annotationTag) {
case 'B':
case 'C':
case 'D':
case 'F':
case 'I':
case 'J':
case 'S':
case 'Z':
case 's':
if (!ALLOC_CAST(element, J9CfrAnnotationElementPrimitive, J9CfrAnnotationElement)) {
return -2;
}
CHECK_EOF(2);
NEXT_U16(((J9CfrAnnotationElementPrimitive *)element)->constValueIndex, index);
break;
case 'e':
{
J9CfrConstantPoolInfo* cpBase = classfile->constantPool;
U_16 cpCount = classfile->constantPoolCount;
U_16 typeNameIndex = 0;
U_16 constNameIndex = 0;
if (!ALLOC_CAST(element, J9CfrAnnotationElementEnum, J9CfrAnnotationElement)) {
return -2;
}
CHECK_EOF(4);
NEXT_U16(((J9CfrAnnotationElementEnum *)element)->typeNameIndex, index);
NEXT_U16(((J9CfrAnnotationElementEnum *)element)->constNameIndex, index);
typeNameIndex = ((J9CfrAnnotationElementEnum *)element)->typeNameIndex;
constNameIndex = ((J9CfrAnnotationElementEnum *)element)->constNameIndex;
if ((0 == typeNameIndex) || (typeNameIndex >= cpCount) || (0 == constNameIndex) || (constNameIndex >= cpCount)) {
return BCT_ERR_INVALID_ANNOTATION_BAD_CP_INDEX_OUT_OF_RANGE;
}
if ((CFR_CONSTANT_Utf8 != cpBase[typeNameIndex].tag) || (CFR_CONSTANT_Utf8 != cpBase[constNameIndex].tag)) {
return BCT_ERR_INVALID_ANNOTATION_BAD_CP_UTF8_STRING;
}
break;
}
case 'c':
if (!ALLOC_CAST(element, J9CfrAnnotationElementClass, J9CfrAnnotationElement)) {
return -2;
}
CHECK_EOF(2);
NEXT_U16(((J9CfrAnnotationElementClass *)element)->classInfoIndex, index);
break;
case '@':
if (!ALLOC_CAST(element, J9CfrAnnotationElementAnnotation, J9CfrAnnotationElement)) {
return -2;
}
annotation = &((J9CfrAnnotationElementAnnotation *)element)->annotationValue;
result = readAnnotations(classfile, annotation, 1, data, dataEnd, segment, segmentEnd, &index, &freePointer, flags);
if (BCT_ERR_NO_ERROR != result) {
return result;
}
break;
case '[':
if (!ALLOC_CAST(element, J9CfrAnnotationElementArray, J9CfrAnnotationElement)) {
return -2;
}
array = (J9CfrAnnotationElementArray *)element;
CHECK_EOF(2);
NEXT_U16(array->numberOfValues, index);
if (!ALLOC_ARRAY(array->values, array->numberOfValues, J9CfrAnnotationElement *)) {
return -2;
}
arrayWalk = array->values;
for (j = 0; j < array->numberOfValues; j++, arrayWalk++) {
result = readAnnotationElement(classfile, arrayWalk, data, dataEnd, segment, segmentEnd, &index, &freePointer, flags);
if (result != 0) {
return result;
}
}
break;
default:
errorCode = J9NLS_CFR_ERR_BAD_ANNOTATION_TAG__ID;
offset = (U_32) (index - data - 1);
goto _errorFound;
}
element->tag = annotationTag;
*pAnnotationElement = element;
*pIndex = index;
*pFreePointer = freePointer;
return 0;
_errorFound:
return BCT_ERR_INVALID_ANNOTATION;
}
static VMINLINE U_16
getUTF8Length(J9CfrConstantPoolInfo* constantPool, U_16 cpIndex)
{
return (U_16) constantPool[cpIndex].slot1;
}
static VMINLINE U_8*
getUTF8Data(J9CfrConstantPoolInfo* constantPool, U_16 cpIndex)
{
return constantPool[cpIndex].bytes;
}
static IDATA
compareMethodIDs(J9CfrConstantPoolInfo* constantPool, J9CfrMethod *a, J9CfrMethod *b)
{
U_16 aNameIndex = a->nameIndex;
U_16 bNameIndex = b->nameIndex;
U_16 aSigIndex = a->descriptorIndex;
U_16 bSigIndex = b->descriptorIndex;
U_8 *aNameData = getUTF8Data(constantPool, aNameIndex);
U_8 *bNameData = getUTF8Data(constantPool, bNameIndex);
U_8 *aSigData = getUTF8Data(constantPool, aSigIndex);
U_8 *bSigData = getUTF8Data(constantPool, bSigIndex);
U_16 aNameLength = getUTF8Length(constantPool, aNameIndex);
U_16 bNameLength = getUTF8Length(constantPool, bNameIndex);
U_16 aSigLength = getUTF8Length(constantPool, aSigIndex);
U_16 bSigLength = getUTF8Length(constantPool, bSigIndex);
return compareMethodNameAndSignature(aNameData, aNameLength, aSigData, aSigLength, bNameData, bNameLength, bSigData, bSigLength);
}
static void
sortMethodIndex(J9CfrConstantPoolInfo* constantPool, J9CfrMethod *list, IDATA start, IDATA end)
{
IDATA scanUp = start;
IDATA scanDown = end;
IDATA result = 0;
J9CfrMethod pivot = list[(start+end)/2];
do {
while (scanUp < scanDown) {
result = compareMethodIDs(constantPool, &pivot, &list[scanUp]);
if (result <= 0) {
break;
}
scanUp += 1;
}
while (scanUp < scanDown) {
result = compareMethodIDs(constantPool, &pivot, &list[scanDown]);
if (result >= 0) {
break;
}
scanDown -= 1;
}
if (scanUp < scanDown) {
J9CfrMethod swap = list[scanDown];
list[scanDown] = list[scanUp];
list[scanUp] = swap;
}
} while (scanUp < scanDown);
Trc_BCU_Assert_Equals(scanUp, scanDown);
if ((end - start) >= 2) {
if (result <= 0) {
scanUp -= 1;
}
if (result >= 0) {
scanDown += 1;
}
if (scanUp > start) {
sortMethodIndex(constantPool, list, start, scanUp);
}
if (scanDown < end) {
sortMethodIndex(constantPool, list, scanDown, end);
}
}
}
#if JAVA_SPEC_VERSION >= 15
I_32
checkClassBytes(J9VMThread *currentThread, U_8* classBytes, UDATA classBytesLength, U_8* segment, U_32 segmentLength)
{
I_32 rc = 0;
U_32 cfrFlags = BCT_JavaMaxMajorVersionShifted | BCT_AnyPreviewVersion | BCT_BasicCheckOnly;
PORT_ACCESS_FROM_VMC(currentThread);
if (NULL != classBytes) {
rc = j9bcutil_readClassFileBytes(PORTLIB, NULL, classBytes, classBytesLength, segment, segmentLength, cfrFlags, NULL, NULL, 0, 0);
}
return rc;
}
#endif