FULL PRODUCT VERSION :
A DESCRIPTION OF THE PROBLEM :
If there is an array of size close to 2 GB, its size is reported as a negative value to the heap_iteration_callback in IterateThroughHeap
THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: Did not try
THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Did not try
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile a Java class NegativeArraySize (see source code) which creates a big char[] and calls a native method to trigger IterateThroughHeap
2. Compile a C++ agent as a 64-bit dll to get agent.dll
3. Run the test:
<path to 64-bit Java 7 or Java 6>/java -Xmx4G -agentlib:agent -cp . NegativeArraySize
An object with negative size will be reported.
EXPECTED VERSUS ACTUAL BEHAVIOR :
Actual:
"negative size: array_length=1074790398"
Expected:
a negative size is never reported
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
===========================================
The Java class:
===========================================
public class NegativeArraySize {
static native void iterateHeap();
static char[] array = new char[1074790398]; // keep from GC
public static void main(String[] args) {
iterateHeap();
}
}
===========================================
The C++ agent:
===========================================
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <jvmti.h>
static jvmtiEnv* ourJVMTI;
#define ZERO(X) memset(&X, 0, sizeof(X))
/* Check for JVMTI error */
void check_JVMTI_error_impl(jvmtiError err, const char* file, int line) {
if (err != JVMTI_ERROR_NONE) {
char* name = NULL;
ourJVMTI->GetErrorName(err, &name);
fprintf(stderr, "ERROR: JVMTI error err=%d(%s) in %s:%d\n", err, name, file, line);
fflush(stderr);
ourJVMTI->Deallocate((unsigned char *)name);
assert(false);
}
}
#define CALL_JVMTI(call_expr) check_JVMTI_error_impl(ourJVMTI->call_expr, __FILE__, __LINE__)
jint JNICALL my_callback(jlong class_tag, jlong size, jlong* tag_ptr, jint array_length, void*) {
if (size < 0) {
printf("negative size: array_length=%d\n", array_length);
}
return JVMTI_VISIT_OBJECTS;
}
extern "C" JNIEXPORT void JNICALL Java_NegativeArraySize_iterateHeap(JNIEnv* jni, jclass) {
jvmtiHeapCallbacks callbacks;
ZERO(callbacks);
callbacks.heap_iteration_callback = &my_callback;
CALL_JVMTI(
IterateThroughHeap(JVMTI_HEAP_FILTER_TAGGED, NULL, &callbacks, NULL)
);
}
extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* /*reserved*/) {
vm->GetEnv((void **)&ourJVMTI, JVMTI_VERSION);
assert(ourJVMTI);
jvmtiCapabilities capabilities;
ZERO(capabilities);
capabilities.can_tag_objects = 1;
CALL_JVMTI(AddCapabilities(&capabilities));
return 0;
}
---------- END SOURCE ----------