-
Notifications
You must be signed in to change notification settings - Fork 729
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update the error message for invalid class name #8513
Update the error message for invalid class name #8513
Conversation
Already verified in the single test (loading the specified class file with a corrupted constant pool) and personal builds.
|
5d83232
to
de92c1b
Compare
Reviewer: @DanHeidinga |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, I like what you're doing here - making it easier to debug and for users to understand what's wrong.
I'm a little concerned that the implementation is brittle and may be easy to break / crash if the incoming class is malformed in the wrong way.
The class name (errorNo=#1) in the constant pool entry at index (#122) is invalid;
utf8name=(Ljava/lang/Object;ILcom/sun/org/apache/xalan/internal/xsltc/DOM;)Ljava/lang/String;,
class=die/verwandlung/GregorSamsa, offset=0
What is errorNo=#1
? Is that our internal error code or something from the spec? What other values can it take?
Is constant pool entry at index (#122)
an index in the original constantpool or in the ROMClass's cp? If the former, this is good. If the later it won't match what the user sees in the their classfile.
runtime/bcverify/staticverify.c
Outdated
@@ -1635,9 +1640,12 @@ j9bcv_verifyClassStructure (J9PortLibrary * portLib, J9CfrClassFile * classfile, | |||
J9CfrConstantPoolInfo *info; | |||
J9CfrConstantPoolInfo *utf8; | |||
J9CfrMethod *method; | |||
U_32 thisClassIndex = classfile->constantPool[classfile->thisClass].slot1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
U_32 thisClassIndex = classfile->constantPool[classfile->thisClass].slot1; | |
const U_32 thisClassIndex = classfile->constantPool[classfile->thisClass].slot1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const
was added as suggested above.
runtime/bcverify/staticverify.c
Outdated
@@ -1894,6 +1908,12 @@ j9bcv_verifyClassStructure (J9PortLibrary * portLib, J9CfrClassFile * classfile, | |||
|
|||
goto _leaveProc; /* All is well */ | |||
|
|||
_classNameError: | |||
Trc_STV_j9bcv_verifyClassStructure_BadClassNameError(J9NLS_CFR_ERR_CP_BAD_CLASS_NAME__ID, classNameErrNo, cpIndex, className->slot1, className->bytes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if className
is never assigned? Won't this crash dereferencing the null pointer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The className is initialized with NULL and assigned in the case of CFR_CONSTANT_Class
in j9bcv_verifyClassStructure
.
case CFR_CONSTANT_Class:
/* Must be a UTF8. */
utf8 = &classfile->constantPool[info->slot1];
className = utf8;
So It jumps to _classNameError
if anything wrong happens to className
(assigned by utf8
), which means if className
is never assigned with utf8
, then there is no problem to the class name in the constant pool. As a result, there is no way to reach _classNameError
and the tracepoint here.
Considering that any change in the future might unintentionally screws things up by dereferencing a null pointer in the tracepoint, I agree to do the initialization first with J9CfrConstantPoolInfo classNameInfo = {0, 0, 0, 0, 0, NULL, 0}
(all code there was updated accordingly), in which case it will end up with an empty class name if the class name is literally NULL in the constant pool (which in theory should never happen / will crash in bcvCheckClassName
(utf8) prior to _classNameError
.
runtime/nls/cfre/cfrerr.nls
Outdated
J9NLS_CFR_ERR_UNKNOWN_CONSTANT.system_action=The JVM will throw a verification or classloading-related exception such as java.lang.ClassFormatError. | ||
J9NLS_CFR_ERR_UNKNOWN_CONSTANT.user_response=Contact the provider of the classfile for a corrected version. | ||
|
||
# END NON-TRANSLATABLE | ||
|
||
J9NLS_CFR_ERR_BAD_CLASS_NAME=class name is invalid | ||
#Example: JVMCFRE068 The class name (errorNo=#1) in the constant pool entry at index (#120) is invalid; utf8name=([Ljava/lang/String;)V, class=Foo, offset=0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't usually change the NLS messages. Rather we add new ones to the end.
The reason for this is the NLS messages are periodically translated and all the translations need to match, especially with respect to the format strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed and moved the NLS messages to the end of the file.
"The class name (errorNo=#%u) in the constant pool entry at index (#%u) is invalid; utf8name=%.*s, class=%.*s, offset=%u"); | ||
|
||
allocSize = strlen(template) + utf8NameLength + thisClassNameLength + (MAX_INT_SIZE * 3); | ||
errorString = j9mem_allocate_memory(allocSize, OMRMEM_CATEGORY_VM); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this freed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In our case, the calling path is as follows:
createROMClassFromClassFile (/runtime/bcutil/defineclass.c /calling j9mem_free_memory)
|--> buildVerifyErrorString
|---> getJ9CfrErrorDetailMessageNoMethod
|---> getJ9CfrErrorClassNameMessage (calling j9mem_allocate_memory)
Following the existing implementation in allocating/releasing memory, the memory allocated in getJ9CfrErrorClassNameMessage will eventually be released in createROMClassFromClassFile after use as follows:
createROMClassFromClassFile(...)
{
...
case BCT_ERR_GENERIC_ERROR_CUSTOM_MSG: {
/* default value for exceptionNumber (J9VMCONSTANTPOOL_JAVALANGCLASSFORMATERROR) assigned before switch */
----> errorUTF = (U_8 *)buildVerifyErrorString(vm, (J9CfrError *)vm->dynamicLoadBuffers->classFileError, className, classNameLength);
break;
}
...
} else {
if (errorUTF == NULL) {
J9_VM_FUNCTION(currentThread, setCurrentException)(currentThread, exceptionNumber, NULL);
} else {
PORT_ACCESS_FROM_JAVAVM(vm);
J9_VM_FUNCTION(currentThread, setCurrentExceptionUTF)(currentThread, exceptionNumber, (const char*)errorUTF);
--------> j9mem_free_memory(errorUTF);
}
}
The change is to add code so as to improve the readability of the error message being thrown out when an invalid class name stored in the constant pool is captured during the bytecode verification. Related: eclipse-openj9#7684 Signed-off-by: Cheng Jin <[email protected]>
de92c1b
to
51f5c7b
Compare
The
The intention of the PR is to identify the issue with the class name detected in
|
I totally understand your concern as this is the first time for verification to capture a corrupted constant pool of a class file. So we need to carefully evaluate all situations to ensure they are safely addressed without any new problem introduced unexpectedly. |
Can one of the admins verify this patch? |
The change is to add code so as to improve the readability
of the error message being thrown out when an invalid class
name stored in the constant pool is captured during the bytecode
verification.
Related: #7684
Signed-off-by: Cheng Jin [email protected]