blob: 0b78bf28519adfe0f57f23c98b8e8737d4d40b6c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.cql3.validation.entities;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import org.junit.Test;
import org.apache.cassandra.cql3.CQLTester;
import org.apache.cassandra.cql3.functions.UDFByteCodeVerifier;
import org.apache.cassandra.cql3.validation.entities.udfverify.CallClone;
import org.apache.cassandra.cql3.validation.entities.udfverify.CallComDatastax;
import org.apache.cassandra.cql3.validation.entities.udfverify.CallFinalize;
import org.apache.cassandra.cql3.validation.entities.udfverify.CallOrgApache;
import org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithField;
import org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithInitializer;
import org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithInitializer2;
import org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithInitializer3;
import org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithStaticInitializer;
import org.apache.cassandra.cql3.validation.entities.udfverify.GoodClass;
import org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronized;
import org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronizedWithNotify;
import org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronizedWithNotifyAll;
import org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronizedWithWait;
import org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronizedWithWaitL;
import org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronizedWithWaitLI;
import static org.junit.Assert.assertEquals;
/**
* Test the Java UDF byte code verifier.
*/
public class UFVerifierTest extends CQLTester
{
@Test
public void testByteCodeVerifier()
{
new UDFByteCodeVerifier().verify(readClass(GoodClass.class));
}
@Test
public void testClassWithField()
{
assertEquals(new HashSet<>(Collections.singletonList("field declared: field")),
new UDFByteCodeVerifier().verify(readClass(ClassWithField.class)));
}
@Test
public void testClassWithInitializer()
{
assertEquals(new HashSet<>(Arrays.asList("field declared: field",
"initializer declared")),
new UDFByteCodeVerifier().verify(readClass(ClassWithInitializer.class)));
}
@Test
public void testClassWithInitializer2()
{
assertEquals(new HashSet<>(Arrays.asList("field declared: field",
"initializer declared")),
new UDFByteCodeVerifier().verify(readClass(ClassWithInitializer2.class)));
}
@Test
public void testClassWithInitializer3()
{
assertEquals(new HashSet<>(Collections.singletonList("initializer declared")),
new UDFByteCodeVerifier().verify(readClass(ClassWithInitializer3.class)));
}
@Test
public void testClassWithStaticInitializer()
{
assertEquals(new HashSet<>(Collections.singletonList("static initializer declared")),
new UDFByteCodeVerifier().verify(readClass(ClassWithStaticInitializer.class)));
}
@Test
public void testUseOfSynchronized()
{
assertEquals(new HashSet<>(Collections.singletonList("use of synchronized")),
new UDFByteCodeVerifier().verify(readClass(UseOfSynchronized.class)));
}
@Test
public void testUseOfSynchronizedWithNotify()
{
assertEquals(new HashSet<>(Arrays.asList("use of synchronized", "call to java.lang.Object.notify()")),
new UDFByteCodeVerifier().verify(readClass(UseOfSynchronizedWithNotify.class)));
}
@Test
public void testUseOfSynchronizedWithNotifyAll()
{
assertEquals(new HashSet<>(Arrays.asList("use of synchronized", "call to java.lang.Object.notifyAll()")),
new UDFByteCodeVerifier().verify(readClass(UseOfSynchronizedWithNotifyAll.class)));
}
@Test
public void testUseOfSynchronizedWithWait()
{
assertEquals(new HashSet<>(Arrays.asList("use of synchronized", "call to java.lang.Object.wait()")),
new UDFByteCodeVerifier().verify(readClass(UseOfSynchronizedWithWait.class)));
}
@Test
public void testUseOfSynchronizedWithWaitL()
{
assertEquals(new HashSet<>(Arrays.asList("use of synchronized", "call to java.lang.Object.wait()")),
new UDFByteCodeVerifier().verify(readClass(UseOfSynchronizedWithWaitL.class)));
}
@Test
public void testUseOfSynchronizedWithWaitI()
{
assertEquals(new HashSet<>(Arrays.asList("use of synchronized", "call to java.lang.Object.wait()")),
new UDFByteCodeVerifier().verify(readClass(UseOfSynchronizedWithWaitLI.class)));
}
@Test
public void testCallClone()
{
assertEquals(new HashSet<>(Collections.singletonList("call to java.lang.Object.clone()")),
new UDFByteCodeVerifier().verify(readClass(CallClone.class)));
}
@Test
public void testCallFinalize()
{
assertEquals(new HashSet<>(Collections.singletonList("call to java.lang.Object.finalize()")),
new UDFByteCodeVerifier().verify(readClass(CallFinalize.class)));
}
@Test
public void testCallComDatastax()
{
assertEquals(new HashSet<>(Collections.singletonList("call to com.datastax.driver.core.DataType.cint()")),
new UDFByteCodeVerifier().addDisallowedPackage("com/").verify(readClass(CallComDatastax.class)));
}
@Test
public void testCallOrgApache()
{
assertEquals(new HashSet<>(Collections.singletonList("call to org.apache.cassandra.config.DatabaseDescriptor.getClusterName()")),
new UDFByteCodeVerifier().addDisallowedPackage("org/").verify(readClass(CallOrgApache.class)));
}
@SuppressWarnings("resource")
private static byte[] readClass(Class<?> clazz)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
URL res = clazz.getClassLoader().getResource(clazz.getName().replace('.', '/') + ".class");
assert res != null;
try (InputStream input = res.openConnection().getInputStream())
{
int i;
while ((i = input.read()) != -1)
out.write(i);
return out.toByteArray();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
@Test
public void testInvalidByteCodeUDFs() throws Throwable
{
assertInvalidByteCode("try\n" +
"{\n" +
" clone();\n" +
"}\n" +
"catch (CloneNotSupportedException e)\n" +
"{\n" +
" throw new RuntimeException(e);\n" +
"}\n" +
"return 0d;", "Java UDF validation failed: [call to java.lang.Object.clone()]");
assertInvalidByteCode("try\n" +
"{\n" +
" finalize();\n" +
"}\n" +
"catch (Throwable e)\n" +
"{\n" +
" throw new RuntimeException(e);\n" +
"}\n" +
"return 0d;", "Java UDF validation failed: [call to java.lang.Object.finalize()]");
assertInvalidByteCode('\n' +
"return 0d;\n" +
" }\n" +
'\n' +
" Object field;\n" +
'\n' +
" {", "Java UDF validation failed: [field declared: field]");
assertInvalidByteCode('\n' +
"return 0d;\n" +
" }\n" +
'\n' +
" final Object field;\n" +
'\n' +
" {\n" +
"field = new Object();", "Java UDF validation failed: [field declared: field, initializer declared]");
assertInvalidByteCode('\n' +
"return 0d;\n" +
" }\n" +
'\n' +
" Object field = new Object();\n" +
'\n' +
" {\n" +
"Math.sin(1d);", "Java UDF validation failed: [field declared: field, initializer declared]");
assertInvalidByteCode('\n' +
"return 0d;\n" +
" }\n" +
'\n' +
" {\n" +
"Math.sin(1d);", "Java UDF validation failed: [initializer declared]");
assertInvalidByteCode('\n' +
"return 0d;\n" +
" }\n" +
'\n' +
" static\n" +
" {\n" +
"Math.sin(1d);", "Java UDF validation failed: [static initializer declared]");
assertInvalidByteCode("synchronized (this)\n" +
"{\n" +
" Math.sin(1d);\n" +
"}\n" +
"return 0d;", "Java UDF validation failed: [use of synchronized]");
assertInvalidByteCode("synchronized (this)\n" +
"{\n" +
" notify();\n" +
"}\n" +
"return 0d;", "Java UDF validation failed: [call to java.lang.Object.notify(), use of synchronized]");
assertInvalidByteCode("synchronized (this)\n" +
"{\n" +
" notifyAll();\n" +
"}\n" +
"return 0d;", "Java UDF validation failed: [call to java.lang.Object.notifyAll(), use of synchronized]");
assertInvalidByteCode("synchronized (this)\n" +
"{\n" +
" try\n" +
" {\n" +
" wait();\n" +
" }\n" +
" catch (InterruptedException e)\n" +
" {\n" +
" throw new RuntimeException(e);\n" +
" }\n" +
"}\n" +
"return 0d;", "Java UDF validation failed: [call to java.lang.Object.wait(), use of synchronized]");
assertInvalidByteCode("synchronized (this)\n" +
"{\n" +
" try\n" +
" {\n" +
" wait(1000L);\n" +
" }\n" +
" catch (InterruptedException e)\n" +
" {\n" +
" throw new RuntimeException(e);\n" +
" }\n" +
"}\n" +
"return 0d;", "Java UDF validation failed: [call to java.lang.Object.wait(), use of synchronized]");
assertInvalidByteCode("synchronized (this)\n" +
"{\n" +
" try\n" +
" {\n" +
" wait(1000L, 100);\n" +
" }\n" +
" catch (InterruptedException e)\n" +
" {\n" +
" throw new RuntimeException(e);\n" +
" }\n" +
"}\n" +
"return 0d;", "Java UDF validation failed: [call to java.lang.Object.wait(), use of synchronized]");
assertInvalidByteCode("try {" +
" java.nio.ByteBuffer.allocateDirect(123); return 0d;" +
"} catch (Exception t) {" +
" throw new RuntimeException(t);" +
'}', "Java UDF validation failed: [call to java.nio.ByteBuffer.allocateDirect()]");
assertInvalidByteCode("try {" +
" java.net.InetAddress.getLocalHost(); return 0d;" +
"} catch (Exception t) {" +
" throw new RuntimeException(t);" +
'}', "Java UDF validation failed: [call to java.net.InetAddress.getLocalHost()]");
assertInvalidByteCode("try {" +
" java.net.InetAddress.getAllByName(\"localhost\"); return 0d;" +
"} catch (Exception t) {" +
" throw new RuntimeException(t);" +
'}', "Java UDF validation failed: [call to java.net.InetAddress.getAllByName()]");
assertInvalidByteCode("try {" +
" java.net.Inet4Address.getByName(\"127.0.0.1\"); return 0d;" +
"} catch (Exception t) {" +
" throw new RuntimeException(t);" +
'}', "Java UDF validation failed: [call to java.net.Inet4Address.getByName()]");
assertInvalidByteCode("try {" +
" java.net.Inet6Address.getByAddress(new byte[]{127,0,0,1}); return 0d;" +
"} catch (Exception t) {" +
" throw new RuntimeException(t);" +
'}', "Java UDF validation failed: [call to java.net.Inet6Address.getByAddress()]");
assertInvalidByteCode("try {" +
" java.net.NetworkInterface.getNetworkInterfaces(); return 0d;" +
"} catch (Exception t) {" +
" throw new RuntimeException(t);" +
'}', "Java UDF validation failed: [call to java.net.NetworkInterface.getNetworkInterfaces()]");
}
private void assertInvalidByteCode(String body, String error) throws Throwable
{
assertInvalidMessage(error,
"CREATE FUNCTION " + KEYSPACE + ".mustBeInvalid ( input double ) " +
"CALLED ON NULL INPUT " +
"RETURNS double " +
"LANGUAGE java AS $$" + body + "$$");
}
}