Repository: cassandra Updated Branches: refs/heads/trunk d62b2cf7c -> 93b64f7b3
"class declared as inner class" error when using UDF patch by Robert Stupp; reviewed by Tyler Hobbs for CASSANDRA-11391 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/93b64f7b Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/93b64f7b Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/93b64f7b Branch: refs/heads/trunk Commit: 93b64f7b355a64d752e7f73d8ad4127004616c70 Parents: d62b2cf Author: Robert Stupp <sn...@snazy.de> Authored: Sat Apr 30 18:30:13 2016 +0200 Committer: Robert Stupp <sn...@snazy.de> Committed: Sat Apr 30 18:30:13 2016 +0200 ---------------------------------------------------------------------- .../cql3/functions/JavaBasedUDFunction.java | 2 +- .../cql3/functions/UDFByteCodeVerifier.java | 6 +- .../cql3/validation/entities/UFTest.java | 13 ++++ .../validation/entities/UFVerifierTest.java | 75 +++++++++++++++----- .../entities/udfverify/ClassWithInnerClass.java | 47 ++++++++++++ .../udfverify/ClassWithInnerClass2.java | 49 +++++++++++++ .../udfverify/ClassWithStaticInnerClass.java | 47 ++++++++++++ .../entities/udfverify/UsingMapEntry.java | 50 +++++++++++++ 8 files changed, 270 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java b/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java index 15103be..ccfc7cf 100644 --- a/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java +++ b/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java @@ -294,7 +294,7 @@ public final class JavaBasedUDFunction extends UDFunction } // Verify the UDF bytecode against use of probably dangerous code - Set<String> errors = udfByteCodeVerifier.verify(targetClassLoader.classData(targetClassName)); + Set<String> errors = udfByteCodeVerifier.verify(targetClassName, targetClassLoader.classData(targetClassName)); String validDeclare = "not allowed method declared: " + executeInternalName + '('; for (Iterator<String> i = errors.iterator(); i.hasNext();) { http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/src/java/org/apache/cassandra/cql3/functions/UDFByteCodeVerifier.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/functions/UDFByteCodeVerifier.java b/src/java/org/apache/cassandra/cql3/functions/UDFByteCodeVerifier.java index 4bab883..cfaa70f 100644 --- a/src/java/org/apache/cassandra/cql3/functions/UDFByteCodeVerifier.java +++ b/src/java/org/apache/cassandra/cql3/functions/UDFByteCodeVerifier.java @@ -80,8 +80,9 @@ public final class UDFByteCodeVerifier return this; } - public Set<String> verify(byte[] bytes) + public Set<String> verify(String clsName, byte[] bytes) { + String clsNameSl = clsName.replace('.', '/'); Set<String> errors = new TreeSet<>(); // it's a TreeSet for unit tests ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM5) { @@ -134,7 +135,8 @@ public final class UDFByteCodeVerifier public void visitInnerClass(String name, String outerName, String innerName, int access) { - errors.add("class declared as inner class"); + if (clsNameSl.equals(outerName)) // outerName might be null, which is true for anonymous inner classes + errors.add("class declared as inner class"); super.visitInnerClass(name, outerName, innerName, access); } }; http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java index 1f1ed92..3cd5be7 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java @@ -2624,6 +2624,19 @@ public class UFTest extends CQLTester assertRows(execute("SELECT " + f + "(udt) FROM %s"), row(tuple("baz", 88))); + + createFunction(KEYSPACE, "map", + "CREATE FUNCTION %s(my_map map<text, text>)\n" + + " CALLED ON NULL INPUT\n" + + " RETURNS text\n" + + " LANGUAGE java\n" + + " AS $$\n" + + " String buffer = \"\";\n" + + " for(java.util.Map.Entry<String, String> entry: my_map.entrySet()) {\n" + + " buffer = buffer + entry.getKey() + \": \" + entry.getValue() + \", \";\n" + + " }\n" + + " return buffer;\n" + + " $$;\n"); } @Test http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/test/unit/org/apache/cassandra/cql3/validation/entities/UFVerifierTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFVerifierTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFVerifierTest.java index 0b78bf2..9a8e682 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFVerifierTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFVerifierTest.java @@ -25,6 +25,7 @@ import java.net.URL; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.Set; import org.junit.Test; @@ -38,7 +39,10 @@ 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.ClassWithInnerClass; +import org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithInnerClass2; import org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithStaticInitializer; +import org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithStaticInnerClass; 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; @@ -46,6 +50,7 @@ import org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronized 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 org.apache.cassandra.cql3.validation.entities.udfverify.UsingMapEntry; import static org.junit.Assert.assertEquals; @@ -57,14 +62,14 @@ public class UFVerifierTest extends CQLTester @Test public void testByteCodeVerifier() { - new UDFByteCodeVerifier().verify(readClass(GoodClass.class)); + verify(GoodClass.class); } @Test public void testClassWithField() { assertEquals(new HashSet<>(Collections.singletonList("field declared: field")), - new UDFByteCodeVerifier().verify(readClass(ClassWithField.class))); + verify(ClassWithField.class)); } @Test @@ -72,7 +77,7 @@ public class UFVerifierTest extends CQLTester { assertEquals(new HashSet<>(Arrays.asList("field declared: field", "initializer declared")), - new UDFByteCodeVerifier().verify(readClass(ClassWithInitializer.class))); + verify(ClassWithInitializer.class)); } @Test @@ -80,91 +85,129 @@ public class UFVerifierTest extends CQLTester { assertEquals(new HashSet<>(Arrays.asList("field declared: field", "initializer declared")), - new UDFByteCodeVerifier().verify(readClass(ClassWithInitializer2.class))); + verify(ClassWithInitializer2.class)); } @Test public void testClassWithInitializer3() { assertEquals(new HashSet<>(Collections.singletonList("initializer declared")), - new UDFByteCodeVerifier().verify(readClass(ClassWithInitializer3.class))); + verify(ClassWithInitializer3.class)); } @Test public void testClassWithStaticInitializer() { assertEquals(new HashSet<>(Collections.singletonList("static initializer declared")), - new UDFByteCodeVerifier().verify(readClass(ClassWithStaticInitializer.class))); + verify(ClassWithStaticInitializer.class)); } @Test public void testUseOfSynchronized() { assertEquals(new HashSet<>(Collections.singletonList("use of synchronized")), - new UDFByteCodeVerifier().verify(readClass(UseOfSynchronized.class))); + verify(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))); + verify(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))); + verify(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))); + verify(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))); + verify(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))); + verify(UseOfSynchronizedWithWaitLI.class)); } @Test public void testCallClone() { assertEquals(new HashSet<>(Collections.singletonList("call to java.lang.Object.clone()")), - new UDFByteCodeVerifier().verify(readClass(CallClone.class))); + verify(CallClone.class)); } @Test public void testCallFinalize() { assertEquals(new HashSet<>(Collections.singletonList("call to java.lang.Object.finalize()")), - new UDFByteCodeVerifier().verify(readClass(CallFinalize.class))); + verify(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))); + verify("com/", 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))); + verify("org/", CallOrgApache.class)); + } + + @Test + public void testClassStaticInnerClass() + { + assertEquals(new HashSet<>(Collections.singletonList("class declared as inner class")), + verify(ClassWithStaticInnerClass.class)); + } + + @Test + public void testUsingMapEntry() + { + assertEquals(Collections.emptySet(), + verify(UsingMapEntry.class)); + } + + @Test + public void testClassInnerClass() + { + assertEquals(new HashSet<>(Collections.singletonList("class declared as inner class")), + verify(ClassWithInnerClass.class)); + } + + @Test + public void testClassInnerClass2() + { + assertEquals(Collections.emptySet(), + verify(ClassWithInnerClass2.class)); + } + + private Set<String> verify(Class cls) + { + return new UDFByteCodeVerifier().verify(cls.getName(), readClass(cls)); + } + + private Set<String> verify(String disallowedPkg, Class cls) + { + return new UDFByteCodeVerifier().addDisallowedPackage(disallowedPkg).verify(cls.getName(), readClass(cls)); } @SuppressWarnings("resource") http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass.java b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass.java new file mode 100644 index 0000000..2166771 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass.java @@ -0,0 +1,47 @@ +/* + * 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.udfverify; + +import java.nio.ByteBuffer; +import java.util.List; + +import com.datastax.driver.core.TypeCodec; +import org.apache.cassandra.cql3.functions.JavaUDF; +import org.apache.cassandra.cql3.functions.UDFContext; + +/** + * Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}. + */ +public final class ClassWithInnerClass extends JavaUDF +{ + public ClassWithInnerClass(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext) + { + super(returnDataType, argDataTypes, udfContext); + } + + protected ByteBuffer executeImpl(int protocolVersion, List<ByteBuffer> params) + { + return null; + } + + // this is NOT fine + final class ClassWithInner_Inner { + + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass2.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass2.java b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass2.java new file mode 100644 index 0000000..9c18510 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass2.java @@ -0,0 +1,49 @@ +/* + * 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.udfverify; + +import java.nio.ByteBuffer; +import java.util.List; + +import com.datastax.driver.core.TypeCodec; +import org.apache.cassandra.cql3.functions.JavaUDF; +import org.apache.cassandra.cql3.functions.UDFContext; + +/** + * Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}. + */ +public final class ClassWithInnerClass2 extends JavaUDF +{ + public ClassWithInnerClass2(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext) + { + super(returnDataType, argDataTypes, udfContext); + } + + protected ByteBuffer executeImpl(int protocolVersion, List<ByteBuffer> params) + { + // this is fine + new Runnable() { + public void run() + { + + } + }.run(); + return null; + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithStaticInnerClass.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithStaticInnerClass.java b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithStaticInnerClass.java new file mode 100644 index 0000000..fada145 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithStaticInnerClass.java @@ -0,0 +1,47 @@ +/* + * 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.udfverify; + +import java.nio.ByteBuffer; +import java.util.List; + +import com.datastax.driver.core.TypeCodec; +import org.apache.cassandra.cql3.functions.JavaUDF; +import org.apache.cassandra.cql3.functions.UDFContext; + +/** + * Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}. + */ +public final class ClassWithStaticInnerClass extends JavaUDF +{ + public ClassWithStaticInnerClass(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext) + { + super(returnDataType, argDataTypes, udfContext); + } + + protected ByteBuffer executeImpl(int protocolVersion, List<ByteBuffer> params) + { + return null; + } + + // this is NOT fine + static final class ClassWithStaticInner_Inner { + + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/UsingMapEntry.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/UsingMapEntry.java b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/UsingMapEntry.java new file mode 100644 index 0000000..5091dc1 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/UsingMapEntry.java @@ -0,0 +1,50 @@ +/* + * 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.udfverify; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.datastax.driver.core.TypeCodec; +import org.apache.cassandra.cql3.functions.JavaUDF; +import org.apache.cassandra.cql3.functions.UDFContext; + +/** + * Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}. + */ +public final class UsingMapEntry extends JavaUDF +{ + public UsingMapEntry(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext) + { + super(returnDataType, argDataTypes, udfContext); + } + + protected ByteBuffer executeImpl(int protocolVersion, List<ByteBuffer> params) + { + Map<String, String> map = new HashMap<>(); + // Map.Entry is passed in as an "inner class usage" + for (Map.Entry<String, String> stringStringEntry : map.entrySet()) + { + + } + return null; + } +}