6436034: Instance filter doesn't filter event if it occurs in native method

Use 'GetLocalInstance' JVMTI extension if it exists

Reviewed-by: coleenp, dcubed
This commit is contained in:
Keith McGuigan 2011-01-12 11:47:35 -05:00
parent 677a39996a
commit 8867f6b298
6 changed files with 284 additions and 25 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -133,27 +133,60 @@ set_event_notification(jvmtiEventMode mode, EventIndex ei)
return error;
}
typedef struct {
int major;
int minor;
} version_type;
typedef struct {
version_type runtime;
version_type compiletime;
} compatible_versions_type;
/*
* List of explicitly compatible JVMTI versions, specified as
* { runtime version, compile-time version } pairs. -1 is a wildcard.
*/
static int nof_compatible_versions = 3;
static compatible_versions_type compatible_versions_list[] = {
/*
* FIXUP: Allow version 0 to be compatible with anything
* Special check for FCS of 1.0.
*/
{ { 0, -1 }, { -1, -1 } },
{ { -1, -1 }, { 0, -1 } },
/*
* 1.2 is runtime compatible with 1.1 -- just make sure to check the
* version before using any new 1.2 features
*/
{ { 1, 1 }, { 1, 2 } }
};
/* Logic to determine JVMTI version compatibility */
static jboolean
compatible_versions(jint major_runtime, jint minor_runtime,
jint major_compiletime, jint minor_compiletime)
{
#if 1 /* FIXUP: We allow version 0 to be compatible with anything */
/* Special check for FCS of 1.0. */
if ( major_runtime == 0 || major_compiletime == 0 ) {
return JNI_TRUE;
/*
* First check to see if versions are explicitly compatible via the
* list specified above.
*/
int i;
for (i = 0; i < nof_compatible_versions; ++i) {
version_type runtime = compatible_versions_list[i].runtime;
version_type comptime = compatible_versions_list[i].compiletime;
if ((major_runtime == runtime.major || runtime.major == -1) &&
(minor_runtime == runtime.minor || runtime.minor == -1) &&
(major_compiletime == comptime.major || comptime.major == -1) &&
(minor_compiletime == comptime.minor || comptime.minor == -1)) {
return JNI_TRUE;
}
}
#endif
/* Runtime major version must match. */
if ( major_runtime != major_compiletime ) {
return JNI_FALSE;
}
/* Runtime minor version must be >= the version compiled with. */
if ( minor_runtime < minor_compiletime ) {
return JNI_FALSE;
}
/* Assumed compatible */
return JNI_TRUE;
return major_runtime == major_compiletime &&
minor_runtime >= minor_compiletime;
}
/* OnLoad startup:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -39,6 +39,7 @@
#include "stepControl.h"
#include "threadControl.h"
#include "SDE.h"
#include "jvmti.h"
typedef struct ClassFilter {
jclass clazz;
@ -275,6 +276,24 @@ patternStringMatch(char *classname, const char *pattern)
}
}
static jboolean isVersionGte12x() {
jint version;
jvmtiError err =
JVMTI_FUNC_PTR(gdata->jvmti,GetVersionNumber)(gdata->jvmti, &version);
if (err == JVMTI_ERROR_NONE) {
jint major, minor;
major = (version & JVMTI_VERSION_MASK_MAJOR)
>> JVMTI_VERSION_SHIFT_MAJOR;
minor = (version & JVMTI_VERSION_MASK_MINOR)
>> JVMTI_VERSION_SHIFT_MINOR;
return (major > 1 || major == 1 && minor >= 2);
} else {
return JNI_FALSE;
}
}
/* Return the object instance in which the event occurred */
/* Return NULL if static or if an error occurs */
static jobject
@ -286,6 +305,14 @@ eventInstance(EventInfo *evinfo)
jint modifiers = 0;
jvmtiError error;
static jboolean got_version = JNI_FALSE;
static jboolean is_version_gte_12x = JNI_FALSE;
if (!got_version) {
is_version_gte_12x = isVersionGte12x();
got_version = JNI_TRUE;
}
switch (evinfo->ei) {
case EI_SINGLE_STEP:
case EI_BREAKPOINT:
@ -314,11 +341,18 @@ eventInstance(EventInfo *evinfo)
/* fail if error or static (0x8) */
if (error == JVMTI_ERROR_NONE && thread!=NULL && (modifiers & 0x8) == 0) {
FrameNumber fnum = 0;
/* get slot zero object "this" */
error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
(gdata->jvmti, thread, fnum, 0, &object);
if (error != JVMTI_ERROR_NONE)
if (is_version_gte_12x) {
/* Use new 1.2.x function, GetLocalInstance */
error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInstance)
(gdata->jvmti, thread, fnum, &object);
} else {
/* get slot zero object "this" */
error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
(gdata->jvmti, thread, fnum, 0, &object);
}
if (error != JVMTI_ERROR_NONE) {
object = NULL;
}
}
return object;

View File

@ -209,7 +209,7 @@ createNewJPLISAgent(JavaVM * vm, JPLISAgent **agent_ptr) {
*agent_ptr = NULL;
jnierror = (*vm)->GetEnv( vm,
(void **) &jvmtienv,
JVMTI_VERSION);
JVMTI_VERSION_1_1);
if ( jnierror != JNI_OK ) {
initerror = JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT;
} else {
@ -990,7 +990,7 @@ retransformableEnvironment(JPLISAgent * agent) {
}
jnierror = (*agent->mJVM)->GetEnv( agent->mJVM,
(void **) &retransformerEnv,
JVMTI_VERSION);
JVMTI_VERSION_1_1);
if ( jnierror != JNI_OK ) {
return NULL;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -41,8 +41,9 @@ enum {
JVMTI_VERSION_1 = 0x30010000,
JVMTI_VERSION_1_0 = 0x30010000,
JVMTI_VERSION_1_1 = 0x30010100,
JVMTI_VERSION_1_2 = 0x30010200,
JVMTI_VERSION = 0x30000000 + (1 * 0x10000) + (1 * 0x100) + 102 /* version: 1.1.102 */
JVMTI_VERSION = 0x30000000 + (1 * 0x10000) + (2 * 0x100) + 1 /* version: 1.2.1 */
};
JNIEXPORT jint JNICALL
@ -1774,6 +1775,12 @@ typedef struct jvmtiInterface_1_ {
jobject object,
jlong* size_ptr);
/* 155 : Get Local Instance */
jvmtiError (JNICALL *GetLocalInstance) (jvmtiEnv* env,
jthread thread,
jint depth,
jobject* value_ptr);
} jvmtiInterface_1;
struct _jvmtiEnv {
@ -2031,6 +2038,12 @@ struct _jvmtiEnv {
return functions->GetLocalObject(this, thread, depth, slot, value_ptr);
}
jvmtiError GetLocalInstance(jthread thread,
jint depth,
jobject* value_ptr) {
return functions->GetLocalInstance(this, thread, depth, value_ptr);
}
jvmtiError GetLocalInt(jthread thread,
jint depth,
jint slot,
@ -2518,3 +2531,4 @@ struct _jvmtiEnv {
#endif /* __cplusplus */
#endif /* !_JAVA_JVMTI_H_ */

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6426034
* @summary Instance filter doesn't filter event if it occurs in native method
*
* @author Keith McGuigan
*
* @library scaffold
* @run build JDIScaffold VMConnection
* @compile -XDignore.symbol.file NativeInstanceFilterTarg.java
* @run main/othervm NativeInstanceFilter
*/
/*
* This test tests instance filters for events generated from a native method
*/
import java.util.*;
import com.sun.jdi.*;
import com.sun.jdi.event.*;
import com.sun.jdi.request.*;
public class NativeInstanceFilter extends JDIScaffold {
static int unfilteredEvents = 0;
public static void main(String args[]) throws Exception {
new NativeInstanceFilter().startTests();
}
public NativeInstanceFilter() {
super();
}
static EventRequestManager requestManager = null;
static MethodExitRequest request = null;
private void listen() {
TargetAdapter adapter = new TargetAdapter() {
EventSet set = null;
ObjectReference instance = null;
public boolean eventSetReceived(EventSet set) {
this.set = set;
return false;
}
public boolean methodExited(MethodExitEvent event) {
String name = event.method().name();
if (instance == null && name.equals("latch")) {
// Grab the instance (return value) and set up as filter
System.out.println("Setting up instance filter");
instance = (ObjectReference)event.returnValue();
requestManager.deleteEventRequest(request);
request = requestManager.createMethodExitRequest();
request.addInstanceFilter(instance);
request.enable();
} else if (instance != null && name.equals("intern")) {
// If not for the filter, this will be called twice
System.out.println("method exit event (String.intern())");
++unfilteredEvents;
}
set.resume();
return false;
}
};
addListener(adapter);
}
protected void runTests() throws Exception {
String[] args = new String[2];
args[0] = "-connect";
args[1] = "com.sun.jdi.CommandLineLaunch:main=NativeInstanceFilterTarg";
connect(args);
waitForVMStart();
// VM has started, but hasn't started running the test program yet.
requestManager = vm().eventRequestManager();
ReferenceType referenceType =
resumeToPrepareOf("NativeInstanceFilterTarg").referenceType();
request = requestManager.createMethodExitRequest();
request.enable();
listen();
vm().resume();
waitForVMDeath();
if (unfilteredEvents != 1) {
throw new Exception(
"Failed: Event from native frame not filtered out.");
}
System.out.println("Passed: Event filtered out.");
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import sun.misc.Version;
public class NativeInstanceFilterTarg {
public static void main(String args[]) {
boolean runTest = jvmSupportsJVMTI_12x();
String s1 = "abc";
String s2 = "def";
latch(s1);
s1.intern();
if (runTest) {
s2.intern(); // this is the call that generates events that ought
// to be filtered out.
} else {
System.out.println("Neutering test since JVMTI 1.2 not supported");
}
}
// Used by debugger to get an instance to filter with
public static String latch(String s) { return s; }
public static boolean jvmSupportsJVMTI_12x() {
// This fix requires the JVM to support JVMTI 1.2, which doesn't
// happen until HSX 20.0, build 05.
int major = Version.jvmMajorVersion();
int minor = Version.jvmMinorVersion();
int micro = Version.jvmMicroVersion();
int build = Version.jvmBuildNumber();
return (major > 20 || major == 20 &&
(minor > 0 || micro > 0 || build >= 5));
}
}