559247: OQL method call improvements
Varargs calls and restrictions on classes/methods
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=559247
Change-Id: Ie1555937af43181ca29142b964a8f1c808101f26
diff --git a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/Messages.java b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/Messages.java
index 6e2d5e6..a29997b 100644
--- a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/Messages.java
+++ b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/Messages.java
@@ -44,6 +44,7 @@
public static String IndexWriter_StoredError;
public static String IndexWriter_StoredException;
public static String MethodCallExpression_Error_MethodNotFound;
+ public static String MethodCallExpression_Error_MethodProhibited;
public static String MultiplePathsFromGCRootsComputerImpl_FindingPaths;
public static String SnapshotFactoryImpl_ClassIDNotFound;
public static String SnapshotFactoryImpl_ClassImplNotFound;
diff --git a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/messages.properties b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/messages.properties
index 7aad84c..8c4ce8c 100644
--- a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/messages.properties
+++ b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/messages.properties
@@ -37,6 +37,7 @@
IndexWriter_StoredError=stored error from writer
IndexWriter_StoredException=stored IO exception from writer
MethodCallExpression_Error_MethodNotFound=Method {0}({1}) not found in object {2} of type {3}
+MethodCallExpression_Error_MethodProhibited=Method {0} prohibited by method filter {1} from {2}
MultiplePathsFromGCRootsComputerImpl_FindingPaths=Finding paths
SnapshotFactoryImpl_EmptyOutbounds=Empty outbounds for index {0} address {1} type {2}
SnapshotFactoryImpl_Error_NoParserRegistered=No parser registered for file ''{0}''
@@ -127,4 +128,4 @@
OQLParser_Missing_return_statement_in_function=Missing return statement in function
ThreadStackHelper_InvalidThread=Invalid thread {0}: {1}
-ThreadStackHelper_InvalidThreadLocal=Invalid thread local {0} for thread {1} : {2}
\ No newline at end of file
+ThreadStackHelper_InvalidThreadLocal=Invalid thread local {0} for thread {1} : {2}
diff --git a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/MethodCallExpression.java b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/MethodCallExpression.java
index e58d53e..4ce1dd0 100644
--- a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/MethodCallExpression.java
+++ b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/MethodCallExpression.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2012 SAP AG and IBM Corporation.
+ * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -11,9 +11,12 @@
*******************************************************************************/
package org.eclipse.mat.parser.internal.oql.compiler;
+import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.security.AccessControlException;
+import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
@@ -64,7 +67,7 @@
/*
* Finding the right method is tricky as the arguments have already been boxed.
- * E.g. consider overloaded methods
+ * E.g. consider overloaded methods
* remove(int)
* remove(Object)
* with argument Integer(1).
@@ -73,7 +76,9 @@
final Class<? extends Object> subjectClass = subject.getClass();
Method[] methods;
methods = subjectClass.getMethods();
- if (!Modifier.isPublic(subjectClass.getModifiers()))
+ // If we checkMethodAccess then an interface method may be allowed even if the class method isn't
+ boolean alwaysInterfaces = true;
+ if (!Modifier.isPublic(subjectClass.getModifiers()) || alwaysInterfaces)
{
// Non-public class public methods are only accessible via
// interfaces. For example java.util.Arrays$ArrayList.get()
@@ -97,6 +102,17 @@
{
firstChoiceMethods(extraMethods, subjectClass, arguments);
}
+ // Add static methods if a class object is passed
+ if (subject instanceof Class)
+ {
+ for (Method m : ((Class<?>)subject).getMethods())
+ {
+ if (Modifier.isStatic(m.getModifiers()) && Modifier.isPublic(m.getModifiers()))
+ {
+ extraMethods.add(m);
+ }
+ }
+ }
if (extraMethods.size() > 0)
{
// Then add the original methods
@@ -105,12 +121,14 @@
extraMethods = new ArrayList<Method>(new LinkedHashSet<Method>(extraMethods));
methods = extraMethods.toArray(new Method[extraMethods.size()]);
}
+ SnapshotException deferred = null;
nextMethod: for (int ii = 0; ii < methods.length; ii++)
{
if (methods[ii].getName().equals(this.name))
{
Class<?>[] parameterTypes = methods[ii].getParameterTypes();
- if (parameterTypes.length == arguments.length)
+ if (parameterTypes.length == arguments.length ||
+ methods[ii].isVarArgs() && parameterTypes.length < arguments.length)
{
Object savedArgs[] = null;
for (int jj = 0; jj < arguments.length; jj++)
@@ -119,7 +137,8 @@
{
arguments[jj] = null;
}
- if (arguments[jj] != null && !isConvertible(parameterTypes[jj], arguments[jj]))
+ if (!(methods[ii].isVarArgs() && jj >= parameterTypes.length - 1) &&
+ arguments[jj] != null && !isConvertible(parameterTypes[jj], arguments[jj]))
{
// we do some special magic here...
if (parameterTypes[jj].isAssignableFrom(Pattern.class))
@@ -148,7 +167,17 @@
try
{
- return methods[ii].invoke(subject, arguments);
+ checkMethodAccess(methods[ii]);
+ if (methods[ii].isVarArgs())
+ {
+ Object args2[] = convertVarArgs(parameterTypes, arguments);
+ if (args2 != null)
+ return methods[ii].invoke(subject, args2);
+ }
+ else
+ {
+ return methods[ii].invoke(subject, arguments);
+ }
}
catch (IllegalArgumentException e)
{
@@ -162,15 +191,24 @@
{
throw new SnapshotException(e);
}
+ catch (SecurityException e)
+ {
+ // Perhaps another method works
+ deferred = new SnapshotException(methods[ii].toString(), e);
+ }
}
}
}
+ if (deferred != null)
+ throw deferred;
StringBuilder argTypes = new StringBuilder();
for (Object arg : arguments)
{
if (argTypes.length() > 0)
argTypes.append(", "); //$NON-NLS-1$
+ if (arg == ConstantExpression.NULL)
+ arg = null;
argTypes.append(arg != null ? unboxedType(arg.getClass()).getName() : null);
}
throw new SnapshotException(MessageUtil.format(Messages.MethodCallExpression_Error_MethodNotFound,
@@ -191,10 +229,12 @@
boolean unbox = false;
for (Object args : arguments)
{
+ if (args == ConstantExpression.NULL)
+ args = null;
if (args != null)
argumentTypes1[i] = args.getClass();
argumentTypes2[i] = unboxedType(argumentTypes1[i]);
- if (argumentTypes2 != argumentTypes1)
+ if (argumentTypes2[i] != argumentTypes1[i])
unbox = true;
i++;
}
@@ -254,11 +294,11 @@
}
else if (arg == Double.class)
{
- arg =double.class;
+ arg = double.class;
}
return arg;
}
-
+
/**
* Can method invocation convert the argument via unboxing/widening conversion?
*/
@@ -271,7 +311,7 @@
parameterType == boolean.class || parameterType == Boolean.class))
return true;
if (argumentType == Byte.class && (
- parameterType == byte.class || parameterType == Byte.class
+ parameterType == byte.class || parameterType == Byte.class
|| parameterType == short.class || parameterType == Short.class
|| parameterType == int.class || parameterType == Integer.class
|| parameterType == long.class || parameterType == Long.class
@@ -313,6 +353,91 @@
return false;
}
+ /**
+ * Check whether to allow this method call.
+ * Syntax for mat.oqlmethodFilter
+ * com.package1.* only classes/methods in this package
+ * com.package1.** classes/methods in this package or subpackages
+ * com.package* classes/methods starting with the prefix
+ * com.*#methodname prefix before * and suffix after * must match
+ * ! means not allowed
+ * ; separates components
+ * Throws an exception if not allowed.
+ */
+ private void checkMethodAccess(Method method)
+ {
+ /*
+ * Default allows a few safe methods.
+ */
+ String match = System.getProperty("mat.oql.methodFilter", //$NON-NLS-1$
+ "!java.lang.ClassLoader#*;!java.lang.Compiler#*;!java.lang.Process*;!java.lang.Runtime#*;!java.lang.SecurityManager#*;!java.lang.System#*;!java.lang.Thread*;java.lang.*;java.util.*;org.eclipse.mat.snapshot.*;org.eclipse.mat.snapshot.model.*;!*"); //$NON-NLS-1$
+ String nm = method.getDeclaringClass().getName()+"#"+method.getName(); //$NON-NLS-1$
+ for (String pt : match.split(";")) //$NON-NLS-1$
+ {
+ boolean not = pt.startsWith("!"); //$NON-NLS-1$
+ if (not)
+ pt = pt.substring(1);
+ boolean m;
+ if (pt.endsWith(".**")) //$NON-NLS-1$
+ m = nm.startsWith(pt.substring(0, pt.length() - 2));
+ else if (pt.endsWith(".*")) //$NON-NLS-1$
+ m = nm.startsWith(pt.substring(0, pt.length() - 1))
+ && !nm.substring(pt.length() - 1).contains("."); //$NON-NLS-1$
+ else if (pt.endsWith("*")) //$NON-NLS-1$
+ m = nm.startsWith(pt.substring(0, pt.length() - 1));
+ else if (pt.contains("*")) //$NON-NLS-1$)
+ {
+ int i = pt.indexOf("*"); //$NON-NLS-1$)
+ m = nm.startsWith(pt.substring(0, i)) && nm.endsWith(pt.substring(i + 1));
+ }
+ else
+ m = nm.equals(pt);
+ if (not && m)
+ throw new AccessControlException(MessageFormat.format(Messages.MethodCallExpression_Error_MethodProhibited, nm, "!" + pt, match)); //$NON-NLS-1$
+ if (m)
+ break;
+ }
+ }
+
+ /**
+ * Collect varargs arguments into an array.
+ * @param parameterTypes
+ * @param arguments
+ * @return null if the arguments won't convert
+ */
+ private Object[] convertVarArgs(Class<?>[] parameterTypes, Object arguments[])
+ {
+ /*
+ * If there is one var args argument and it looks like it matches the object array,
+ * then don't wrap it.
+ */
+ if (!(arguments.length == parameterTypes.length
+ && (arguments[arguments.length - 1] == null || parameterTypes[parameterTypes.length - 1]
+ .isAssignableFrom(arguments[arguments.length - 1].getClass()))))
+ {
+ Object args2[] = new Object[parameterTypes.length];
+ for (int i = 0; i < parameterTypes.length - 1; ++i)
+ {
+ args2[i] = arguments[i];
+ }
+ Class<?> componentType = parameterTypes[parameterTypes.length - 1].getComponentType();
+ Object varargs[] = (Object[]) Array.newInstance(componentType,
+ arguments.length - (parameterTypes.length - 1));
+ args2[parameterTypes.length - 1] = varargs;
+ for (int i = parameterTypes.length - 1; i < arguments.length; ++i)
+ {
+ if (arguments[i] != null && !componentType.isAssignableFrom(arguments[i].getClass()))
+ return null;
+ varargs[i - (parameterTypes.length - 1)] = arguments[i];
+ }
+ return args2;
+ }
+ else
+ {
+ return arguments;
+ }
+ }
+
@Override
public boolean isContextDependent(EvaluationContext ctx)
{
diff --git a/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/OQLTest.java b/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/OQLTest.java
index 963319c..65c07a5 100644
--- a/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/OQLTest.java
+++ b/plugins/org.eclipse.mat.tests/src/org/eclipse/mat/tests/snapshot/OQLTest.java
@@ -12,22 +12,24 @@
*******************************************************************************/
package org.eclipse.mat.tests.snapshot;
+import static org.hamcrest.CoreMatchers.isA;
+import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.hamcrest.Matchers.lessThanOrEqualTo;
+import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.anyOf;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
+import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
@@ -48,10 +50,11 @@
import org.eclipse.mat.snapshot.model.IClass;
import org.eclipse.mat.snapshot.model.IObject;
import org.eclipse.mat.tests.TestSnapshots;
-import org.eclipse.mat.util.IProgressListener;
import org.eclipse.mat.util.MessageUtil;
import org.eclipse.mat.util.VoidProgressListener;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
@SuppressWarnings("nls")
public class OQLTest
@@ -105,15 +108,15 @@
{
Object result = execute("select s.@objectId, s.value, s.count, s.offset from java.lang.String s");
- assert result instanceof IResultTable : "'SELECT x, y, z' must return a result of type IResultTable";
+ assertThat("'SELECT x, y, z' must return a result of type IResultTable", result, instanceOf(IResultTable.class));
IResultTable table = (IResultTable) result;
- assert table.getRowCount() == 492 : "492 objects of type java.lang.String expected";
- assert table.getColumns().length == 4 : "4 columns expected";
+ assertThat("492 objects of type java.lang.String expected", table.getRowCount(), equalTo(492));
+ assertThat("4 columns expected", table.getColumns().length, equalTo(4));
// check if context is available
Object row = table.getRow(0);
int objectId = (Integer) table.getColumnValue(row, 0);
- assert objectId == table.getContext(row).getObjectId() : "Result must return underlying object id as context";
+ assertThat("Result must return underlying object id as context", objectId, equalTo(table.getContext(row).getObjectId()));
checkGetOQL(table);
}
@@ -150,13 +153,13 @@
public void testSelectObjects() throws SnapshotException
{
int[] objectIds = (int[]) execute("select objects dominators(s) from objects 0x1295e2f8 s");
- assert objectIds.length == 7;
+ assertThat(objectIds.length, equalTo(7));
objectIds = (int[]) execute("select objects dominators(s) from objects ${snapshot}.getClassesByName(\"java.lang.String\", false) s");
- assert objectIds.length == 2;
+ assertThat(objectIds.length, equalTo(2));
objectIds = (int[]) execute("select objects dominators(s) from objects (select * from java.lang.String) s");
- assert objectIds.length == 465;
+ assertThat(objectIds.length, equalTo(465));
}
@Test
@@ -250,12 +253,12 @@
public void testUnion() throws SnapshotException
{
int[] objectIds = (int[]) execute("select * from objects 0 union (select * from objects 1)");
- assert objectIds.length == 2;
+ assertThat(objectIds.length, equalTo(2));
IResultTable table = (IResultTable) execute("select toString(s) from objects 0x17c180b8 s union (select toHex(s.@objectAddress) from objects 1 s)");
- assert table.getRowCount() == 2;
- assert "main".equals(table.getColumnValue(table.getRow(0), 0));
- assert "0x12832b50".equals(table.getColumnValue(table.getRow(1), 0));
+ assertThat(table.getRowCount(), equalTo(2));
+ assertThat(table.getColumnValue(table.getRow(0), 0), equalTo((Object)"main"));
+ assertThat(table.getColumnValue(table.getRow(1), 0), equalTo((Object)"0x12832b50"));
checkGetOQL(table);
}
@@ -445,25 +448,25 @@
{
Object result = execute("select * from \"java.lang.*\"");
- assert result instanceof int[] : "'SELECT *' must return a result of type int[]";
+ assertThat("'SELECT *' must return a result of type int[]", result, instanceOf(int[].class));
int[] objectIds = (int[]) result;
- assert objectIds.length == 1198 : "1198 objects of type java.lang.* expected";
+ assertThat("1198 objects of type java.lang.* expected", objectIds.length, equalTo(1198));
}
@Test
public void testFromAddress() throws SnapshotException
{
Object result = execute("select * from objects 0x0");
- assert result instanceof int[] : "'SELECT *' must return a result of type int[]";
+ assertThat("'SELECT *' must return a result of type int[]", result, instanceOf(int[].class));
int[] objectIds = (int[]) result;
- assert objectIds.length == 1 : "one object matching 0x0 expected";
+ assertThat("one object matching 0x0 expected", objectIds.length, equalTo(1));
}
@Test
public void testFromObject() throws SnapshotException
{
int[] objectIds = (int[]) execute("SELECT * FROM ${snapshot}.getClassesByName(\"java.lang.ref.Reference\", true)");
- assert objectIds.length == 21 : "expected 21 instanceof of java.lang.ref.Reference";
+ assertThat("expected 21 instanceof of java.lang.ref.Reference", objectIds.length, equalTo(21));
}
@Test
@@ -540,7 +543,7 @@
+ "FROM java.lang.Class c " //
+ "WHERE c implements org.eclipse.mat.snapshot.model.IClass )";
int[] objectIds = (int[]) execute(oql);
- assert objectIds.length == 2058 : "expected 2058 instances of IClass";
+ assertThat("expected 2058 instances of IClass", objectIds.length, equalTo(2058));
}
@Test
@@ -559,7 +562,7 @@
public void testFromInstanceOf() throws SnapshotException
{
int[] objectIds = (int[]) execute("SELECT * FROM INSTANCEOF java.lang.ref.Reference");
- assert objectIds.length == 21 : "expected 21 instances of java.lang.ref.Reference";
+ assertThat("expected 21 instances of java.lang.ref.Reference", objectIds.length, equalTo(21));
ISnapshot snapshot = TestSnapshots.getSnapshot(TestSnapshots.SUN_JDK5_64BIT, false);
@@ -567,45 +570,49 @@
assertNotNull(rClasses);
Set<IClass> classes = new HashSet<IClass>(rClasses);
for (int id : objectIds)
+ {
+ assertThat(MessageUtil.format("Object {0} not an instance of java.lang.ref.Reference ", id),
+ classes, hasItems(snapshot.getClassOf(id)));
assert classes.contains(snapshot.getClassOf(id)) : MessageUtil.format(
"Object {0} not an instance of java.lang.ref.Reference ", id);
+ }
}
@Test
public void testWhereRelationalOperators() throws SnapshotException
{
int[] objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.count > 51");
- assert objectIds.length == 16;
+ assertThat(objectIds.length, equalTo(16));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.count >= 51");
- assert objectIds.length == 19;
+ assertThat(objectIds.length, equalTo(19));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.count < 51");
- assert objectIds.length == 473;
+ assertThat(objectIds.length, equalTo(473));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.count <= 51");
- assert objectIds.length == 476;
+ assertThat(objectIds.length, equalTo(476));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE toString(s) LIKE \"java.*\"");
- assert objectIds.length == 27;
+ assertThat(objectIds.length, equalTo(27));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE toString(s) NOT LIKE \"java.*\"");
- assert objectIds.length == 492 - 27;
+ assertThat(objectIds.length, equalTo(492 - 27));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.value IN dominators(s)");
- assert objectIds.length == 492 - 27;
+ assertThat(objectIds.length, equalTo(492 - 27));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.value NOT IN dominators(s)");
- assert objectIds.length == 27;
+ assertThat(objectIds.length, equalTo(27));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE toString(s) = \"file.separator\"");
- assert objectIds.length == 1;
+ assertThat(objectIds.length, equalTo(1));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.count > 100 AND s.@retainedHeapSize > s.@usedHeapSize");
- assert objectIds.length == 6;
+ assertThat(objectIds.length, equalTo(6));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.count > 1000 OR s.value.@length > 1000");
- assert objectIds.length == 3;
+ assertThat(objectIds.length, equalTo(3));
}
/**
@@ -634,16 +641,16 @@
public void testWhereArithmetic() throws SnapshotException
{
int[] objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.count < s.value.@length * 0.5");
- assert objectIds.length == 16;
+ assertThat(objectIds.length, equalTo(16));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.count < s.value.@length / 2");
- assert objectIds.length == 16;
+ assertThat(objectIds.length, equalTo(16));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.count < s.value.@length - 20");
- assert objectIds.length == 16;
+ assertThat(objectIds.length, equalTo(16));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.count + 20 < s.value.@length");
- assert objectIds.length == 16;
+ assertThat(objectIds.length, equalTo(16));
}
@Test
@@ -661,19 +668,19 @@
public void testWhereLiterals() throws SnapshotException
{
int[] objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE ( s.count > 1000 ) = true");
- assert objectIds.length == 3;
+ assertThat(objectIds.length, equalTo(3));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE dominators(s).size() = 0");
- assert objectIds.length == 27;
+ assertThat(objectIds.length, equalTo(27));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE dominators(s).length = 0");
- assert objectIds.length == 27;
+ assertThat(objectIds.length, equalTo(27));
objectIds = (int[]) execute("SELECT * FROM java.lang.String s WHERE s.@retainedHeapSize > 1024L");
- assert objectIds.length == 4;
+ assertThat(objectIds.length, equalTo(4));
objectIds = (int[]) execute("SELECT * FROM java.lang.Thread s WHERE s.@GCRootInfo != null");
- assert objectIds.length == 4;
+ assertThat(objectIds.length, equalTo(4));
}
@Test
@@ -683,30 +690,30 @@
int objectId = ((int[]) execute("select * from objects 0x17c38b80 s"))[0];
IResultTable result = (IResultTable) execute("select toString(s) from objects 0x17c38b80 s");
- assert "little".equals(result.getColumnValue(result.getRow(0), 0));
+ assertThat(result.getColumnValue(result.getRow(0), 0), equalTo((Object)"little"));
result = (IResultTable) execute("select toHex(s.@objectAddress) from objects 0x17c38b80 s");
- assert "0x17c38b80".equals(result.getColumnValue(result.getRow(0), 0));
+ assertThat(result.getColumnValue(result.getRow(0), 0), equalTo((Object)"0x17c38b80"));
result = (IResultTable) execute("select dominators(s).length from objects 0x17c38b80 s");
- assert Integer.valueOf(1).equals(result.getColumnValue(result.getRow(0), 0));
+ assertThat(result.getColumnValue(result.getRow(0), 0), equalTo((Object)1));
result = (IResultTable) execute("select outbounds(s) from objects 0x17c38b80 s");
int[] outbounds = (int[]) result.getColumnValue(result.getRow(0), 0);
- assert outbounds.length == 2;
- assert Arrays.toString(snapshot.getOutboundReferentIds(objectId)).equals(Arrays.toString(outbounds));
+ assertThat(outbounds.length, equalTo(2));
+ assertThat(outbounds, equalTo(snapshot.getOutboundReferentIds(objectId)));
result = (IResultTable) execute("select inbounds(s) from objects 0x17c38b80 s");
int[] inbounds = (int[]) result.getColumnValue(result.getRow(0), 0);
- assert inbounds.length == 1;
- assert Arrays.toString(snapshot.getInboundRefererIds(objectId)).equals(Arrays.toString(inbounds));
+ assertThat(inbounds.length, equalTo(1));
+ assertThat(inbounds, equalTo(snapshot.getInboundRefererIds(objectId)));
result = (IResultTable) execute("select classof(s) from objects 0x17c38b80 s");
IClass obj = (IClass) result.getColumnValue(result.getRow(0), 0);
- assert "java.lang.String".equals(obj.getName());
+ assertThat(obj.getName(), equalTo("java.lang.String"));
result = (IResultTable) execute("select dominatorof(s) from objects 0x17c38b80 s");
- assert result.getColumnValue(result.getRow(0), 0) != null;
+ assertNotNull(result.getColumnValue(result.getRow(0), 0));
}
@Test(expected = SnapshotException.class)
@@ -780,7 +787,10 @@
IOQLQuery q1 = SnapshotFactory.createQuery(queryString);
String s = q1.toString();
IOQLQuery q2 = SnapshotFactory.createQuery(s);
- execute(s);
+ String s2 = q2.toString();
+ assertEquals(s, s2);
+ IResultTable r = (IResultTable)execute(s);
+ checkGetOQL(r);
}
/**
@@ -791,7 +801,7 @@
public void testAndClause() throws SnapshotException
{
IResultTable res = (IResultTable)execute("SELECT s.value FROM INSTANCEOF java.lang.Number s WHERE (s.value and true)");
- assert 3 == res.getRowCount() : "3 non-zero Numbers expected";
+ assertThat("3 non-zero Numbers expected", res.getRowCount(), equalTo(3));
}
@Test
@@ -1330,6 +1340,7 @@
assertThat(irt.getRowCount(), equalTo(1));
assertThat(irt.getColumns().length, equalTo(11));
Object row = irt.getRow(0);
+ assertNotNull(row);
checkGetOQL(irt);
}
@@ -1339,6 +1350,7 @@
assertThat(irt.getRowCount(), equalTo(1));
assertThat(irt.getColumns().length, equalTo(11));
Object row = irt.getRow(0);
+ assertNotNull(row);
checkGetOQL(irt);
}
@@ -1350,6 +1362,7 @@
assertThat(irt.getRowCount(), equalTo(1));
assertThat(irt.getColumns().length, equalTo(11));
Object row = irt.getRow(0);
+ assertNotNull(row);
checkGetOQL(irt);
}
@@ -1371,6 +1384,7 @@
assertThat(irt.getRowCount(), equalTo(1));
assertThat(irt.getColumns().length, equalTo(11));
Object row = irt.getRow(0);
+ assertNotNull(row);
checkGetOQL(irt);
}
@@ -1865,6 +1879,141 @@
assertThat("Multiple objects expected", objs.length, greaterThanOrEqualTo(2));
}
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ /**
+ * Test method calls disallowed.
+ * @throws SnapshotException
+ */
+ @Test
+ public void testMethodCallClassLoader() throws SnapshotException
+ {
+ expectedException.expectCause(isA(java.security.AccessControlException.class));
+ Object o = execute("SELECT s.@class.forName(\"java.lang.ClassLoader\").getSystemClassLoader() FROM OBJECTS 1 s");
+ assertNull(o);
+ }
+
+ /**
+ * Test method calls disallowed.
+ * @throws SnapshotException
+ */
+ @Test
+ public void testMethodCallCompiler() throws SnapshotException
+ {
+ expectedException.expectCause(isA(java.security.AccessControlException.class));
+ Object o = execute("SELECT s.@class.forName(\"java.lang.Compiler\").disable() FROM OBJECTS 1 s");
+ assertNull(o);
+ }
+
+ /**
+ * Test method calls disallowed.
+ * @throws SnapshotException
+ */
+ @Test
+ public void testMethodCallProcess() throws SnapshotException
+ {
+ expectedException.expectCause(isA(java.security.AccessControlException.class));
+ Object o = execute("SELECT s.@class.forName(\"java.lang.ProcessBuilder\").getConstructor(s.@class.forName(\"[Ljava.lang.String;\")).newInstance(\"calc\") FROM OBJECTS 1 s");
+ assertNull(o);
+ }
+
+ /**
+ * Test method calls disallowed.
+ * @throws SnapshotException
+ */
+ @Test
+ public void testMethodCallRuntime() throws SnapshotException
+ {
+ expectedException.expectCause(isA(java.security.AccessControlException.class));
+ Object o = execute("SELECT s.@class.forName(\"java.lang.Runtime\").getRuntime() FROM OBJECTS 1 s");
+ assertNull(o);
+ }
+
+ /**
+ * Test method calls disallowed.
+ * @throws SnapshotException
+ */
+ @Test
+ public void testMethodCallSecurityManager() throws SnapshotException
+ {
+ expectedException.expectCause(isA(java.security.AccessControlException.class));
+ Object o = execute("SELECT s.@class.forName(\"java.lang.SecurityManager\").newInstance().checkExec(\"calc\") FROM OBJECTS 1 s");
+ assertNull(o);
+ }
+
+ /**
+ * Test method calls disallowed.
+ * @throws SnapshotException
+ */
+ @Test
+ public void testMethodCallSystem() throws SnapshotException
+ {
+ expectedException.expectCause(isA(java.security.AccessControlException.class));
+ Object o = execute("SELECT s.@class.forName(\"java.lang.System\").currentTimeMillis() FROM OBJECTS 1 s");
+ assertNull(o);
+ }
+
+ /**
+ * Test method calls disallowed.
+ * @throws SnapshotException
+ */
+ @Test
+ public void testMethodCallThread() throws SnapshotException
+ {
+ expectedException.expectCause(isA(java.security.AccessControlException.class));
+ Object o = execute("SELECT s.@class.forName(\"java.lang.Thread\").activeCount() FROM OBJECTS 1 s");
+ assertNull(o);
+ }
+
+ /**
+ * Test method calls allowed.
+ * @throws SnapshotException
+ */
+ @Test
+ public void testMethodCallInteger() throws SnapshotException
+ {
+ Object result = execute("SELECT eval(123).intValue() FROM OBJECTS 1 s");
+ assertThat(result, instanceOf(IResultTable.class));
+ IResultTable table = (IResultTable) result;
+ Object row = table.getRow(1);
+ assertThat(table.getColumnValue(row, 0), equalTo((Object)123));
+ }
+
+ /**
+ * Test method calls allowed.
+ * @throws SnapshotException
+ */
+ @Test
+ public void testMethodCallVarArgs1() throws SnapshotException
+ {
+ Object result = execute("SELECT s.@class.forName(\"java.util.Arrays\").asList(1) FROM OBJECTS 1 s");
+ assertThat(result, instanceOf(IResultTable.class));
+ IResultTable table = (IResultTable) result;
+ Object row = table.getRow(0);
+ Object item = table.getColumnValue(row, 0);
+ assertThat(item, instanceOf(List.class));
+ List<?> al = (List<?>)item;
+ assertThat(al.size(), equalTo(1));
+ }
+
+ /**
+ * Test method calls allowed.
+ * @throws SnapshotException
+ */
+ @Test
+ public void testMethodCallVarArgs5() throws SnapshotException
+ {
+ Object result = execute("SELECT s.@class.forName(\"java.util.Arrays\").asList(1,2,3,4,5) FROM OBJECTS 1 s");
+ assertThat(result, instanceOf(IResultTable.class));
+ IResultTable table = (IResultTable) result;
+ Object row = table.getRow(0);
+ Object item = table.getColumnValue(row, 0);
+ assertThat(item, instanceOf(List.class));
+ List<?> al = (List<?>)item;
+ assertThat(al.size(), equalTo(5));
+ }
+
// //////////////////////////////////////////////////////////////
// internal helpers
// //////////////////////////////////////////////////////////////