Skip to content

Commit 461baec

Browse files
committed
Painless: Fix Bug with Duplicate PainlessClasses (#32110)
When building the PainlessMethods and PainlessFields they stored a reference to a PainlessClass. This reference was prior to "freezing" the PainlessClass so the data was both incomplete and mutable. This has been replaced with a target java class instead since the PainlessClass is accessible through a java class now and it requires no special modifications to get around a chicken and egg issue.
1 parent 3c11b4e commit 461baec

File tree

11 files changed

+62
-55
lines changed

11 files changed

+62
-55
lines changed

modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,8 @@ static MethodHandle lookupReference(PainlessLookup painlessLookup, MethodHandles
334334
}
335335
int arity = interfaceMethod.arguments.size();
336336
PainlessMethod implMethod = lookupMethodInternal(painlessLookup, receiverClass, name, arity);
337-
return lookupReferenceInternal(painlessLookup, methodHandlesLookup, interfaceType, implMethod.owner.name,
338-
implMethod.name, receiverClass);
337+
return lookupReferenceInternal(painlessLookup, methodHandlesLookup, interfaceType,
338+
PainlessLookupUtility.anyTypeToPainlessTypeName(implMethod.target), implMethod.name, receiverClass);
339339
}
340340

341341
/** Returns a method handle to an implementation of clazz, given method reference signature. */

modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -102,22 +102,22 @@ public FunctionRef(Class<?> expected, PainlessMethod interfaceMethod, PainlessMe
102102
interfaceMethodType = interfaceMethod.getMethodType().dropParameterTypes(0, 1);
103103

104104
// the Painless$Script class can be inferred if owner is null
105-
if (delegateMethod.owner == null) {
105+
if (delegateMethod.target == null) {
106106
delegateClassName = CLASS_NAME;
107107
isDelegateInterface = false;
108108
} else if (delegateMethod.augmentation != null) {
109109
delegateClassName = delegateMethod.augmentation.getName();
110110
isDelegateInterface = delegateMethod.augmentation.isInterface();
111111
} else {
112-
delegateClassName = delegateMethod.owner.clazz.getName();
113-
isDelegateInterface = delegateMethod.owner.clazz.isInterface();
112+
delegateClassName = delegateMethod.target.getName();
113+
isDelegateInterface = delegateMethod.target.isInterface();
114114
}
115115

116116
if ("<init>".equals(delegateMethod.name)) {
117117
delegateInvokeType = H_NEWINVOKESPECIAL;
118118
} else if (Modifier.isStatic(delegateMethod.modifiers)) {
119119
delegateInvokeType = H_INVOKESTATIC;
120-
} else if (delegateMethod.owner.clazz.isInterface()) {
120+
} else if (delegateMethod.target.isInterface()) {
121121
delegateInvokeType = H_INVOKEINTERFACE;
122122
} else {
123123
delegateInvokeType = H_INVOKEVIRTUAL;

modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessField.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@
2323

2424
public final class PainlessField {
2525
public final String name;
26-
public final PainlessClass owner;
26+
public final Class<?> target;
2727
public final Class<?> clazz;
2828
public final String javaName;
2929
public final int modifiers;
3030
public final MethodHandle getter;
3131
public final MethodHandle setter;
3232

33-
PainlessField(String name, String javaName, PainlessClass owner, Class<?> clazz, int modifiers,
33+
PainlessField(String name, String javaName, Class<?> target, Class<?> clazz, int modifiers,
3434
MethodHandle getter, MethodHandle setter) {
3535
this.name = name;
3636
this.javaName = javaName;
37-
this.owner = owner;
37+
this.target = target;
3838
this.clazz = clazz;
3939
this.modifiers = modifiers;
4040
this.getter = getter;

modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ private void addConstructor(String ownerStructName, WhitelistConstructor whiteli
310310
}
311311

312312
painlessConstructor = methodCache.computeIfAbsent(buildMethodCacheKey(ownerStruct.name, "<init>", painlessParametersTypes),
313-
key -> new PainlessMethod("<init>", ownerStruct, null, void.class, painlessParametersTypes,
313+
key -> new PainlessMethod("<init>", ownerStruct.clazz, null, void.class, painlessParametersTypes,
314314
asmConstructor, javaConstructor.getModifiers(), javaHandle));
315315
ownerStruct.constructors.put(painlessMethodKey, painlessConstructor);
316316
} else if (painlessConstructor.arguments.equals(painlessParametersTypes) == false){
@@ -419,7 +419,7 @@ private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName,
419419

420420
painlessMethod = methodCache.computeIfAbsent(
421421
buildMethodCacheKey(ownerStruct.name, whitelistMethod.javaMethodName, painlessParametersTypes),
422-
key -> new PainlessMethod(whitelistMethod.javaMethodName, ownerStruct, null, painlessReturnClass,
422+
key -> new PainlessMethod(whitelistMethod.javaMethodName, ownerStruct.clazz, null, painlessReturnClass,
423423
painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle));
424424
ownerStruct.staticMethods.put(painlessMethodKey, painlessMethod);
425425
} else if ((painlessMethod.name.equals(whitelistMethod.javaMethodName) && painlessMethod.rtn == painlessReturnClass &&
@@ -445,7 +445,7 @@ private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName,
445445

446446
painlessMethod = methodCache.computeIfAbsent(
447447
buildMethodCacheKey(ownerStruct.name, whitelistMethod.javaMethodName, painlessParametersTypes),
448-
key -> new PainlessMethod(whitelistMethod.javaMethodName, ownerStruct, javaAugmentedClass, painlessReturnClass,
448+
key -> new PainlessMethod(whitelistMethod.javaMethodName, ownerStruct.clazz, javaAugmentedClass, painlessReturnClass,
449449
painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle));
450450
ownerStruct.methods.put(painlessMethodKey, painlessMethod);
451451
} else if ((painlessMethod.name.equals(whitelistMethod.javaMethodName) && painlessMethod.rtn.equals(painlessReturnClass) &&
@@ -501,7 +501,7 @@ private void addField(String ownerStructName, WhitelistField whitelistField) {
501501
painlessField = fieldCache.computeIfAbsent(
502502
buildFieldCacheKey(ownerStruct.name, whitelistField.javaFieldName, painlessFieldClass.getName()),
503503
key -> new PainlessField(whitelistField.javaFieldName, javaField.getName(),
504-
ownerStruct, painlessFieldClass, javaField.getModifiers(), null, null));
504+
ownerStruct.clazz, painlessFieldClass, javaField.getModifiers(), null, null));
505505
ownerStruct.staticMembers.put(whitelistField.javaFieldName, painlessField);
506506
} else if (painlessField.clazz != painlessFieldClass) {
507507
throw new IllegalArgumentException("illegal duplicate static fields [" + whitelistField.javaFieldName + "] " +
@@ -530,7 +530,7 @@ private void addField(String ownerStructName, WhitelistField whitelistField) {
530530
painlessField = fieldCache.computeIfAbsent(
531531
buildFieldCacheKey(ownerStruct.name, whitelistField.javaFieldName, painlessFieldClass.getName()),
532532
key -> new PainlessField(whitelistField.javaFieldName, javaField.getName(),
533-
ownerStruct, painlessFieldClass, javaField.getModifiers(), javaMethodHandleGetter, javaMethodHandleSetter));
533+
ownerStruct.clazz, painlessFieldClass, javaField.getModifiers(), javaMethodHandleGetter, javaMethodHandleSetter));
534534
ownerStruct.members.put(whitelistField.javaFieldName, painlessField);
535535
} else if (painlessField.clazz != painlessFieldClass) {
536536
throw new IllegalArgumentException("illegal duplicate member fields [" + whitelistField.javaFieldName + "] " +
@@ -615,8 +615,8 @@ private void copyStruct(String struct, List<String> children) {
615615

616616
for (PainlessField field : child.members.values()) {
617617
if (owner.members.get(field.name) == null) {
618-
owner.members.put(field.name,
619-
new PainlessField(field.name, field.javaName, owner, field.clazz, field.modifiers, field.getter, field.setter));
618+
owner.members.put(field.name, new PainlessField(
619+
field.name, field.javaName, owner.clazz, field.clazz, field.modifiers, field.getter, field.setter));
620620
}
621621
}
622622
}

modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupUtility.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public static Class<?> painlessTypeNameToPainlessType(String painlessTypeName, M
158158
painlessTypeName.charAt(arrayIndex++) == ']') {
159159
++arrayDimensions;
160160
} else {
161-
throw new IllegalArgumentException("invalid painless type [" + painlessTypeName + "].");
161+
throw new IllegalArgumentException("painless type [" + painlessTypeName + "] not found");
162162
}
163163
}
164164

@@ -192,7 +192,7 @@ public static Class<?> painlessTypeNameToPainlessType(String painlessTypeName, M
192192
try {
193193
return Class.forName(javaDescriptor);
194194
} catch (ClassNotFoundException cnfe) {
195-
throw new IllegalStateException("painless type [" + painlessTypeName + "] not found", cnfe);
195+
throw new IllegalArgumentException("painless type [" + painlessTypeName + "] not found", cnfe);
196196
}
197197
}
198198

@@ -207,7 +207,7 @@ public static void validatePainlessType(Class<?> painlessType, Collection<Class<
207207
}
208208

209209
if (javaClasses.contains(painlessType) == false) {
210-
throw new IllegalStateException("painless type [" + painlessTypeName + "] not found");
210+
throw new IllegalArgumentException("painless type [" + painlessTypeName + "] not found");
211211
}
212212
}
213213

modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessMethod.java

+8-7
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.elasticsearch.painless.MethodWriter;
2323
import org.objectweb.asm.Opcodes;
24+
import org.objectweb.asm.Type;
2425

2526
import java.lang.invoke.MethodHandle;
2627
import java.lang.invoke.MethodType;
@@ -30,19 +31,19 @@
3031

3132
public class PainlessMethod {
3233
public final String name;
33-
public final PainlessClass owner;
34+
public final Class<?> target;
3435
public final Class<?> augmentation;
3536
public final Class<?> rtn;
3637
public final List<Class<?>> arguments;
3738
public final org.objectweb.asm.commons.Method method;
3839
public final int modifiers;
3940
public final MethodHandle handle;
4041

41-
public PainlessMethod(String name, PainlessClass owner, Class<?> augmentation, Class<?> rtn, List<Class<?>> arguments,
42+
public PainlessMethod(String name, Class<?> target, Class<?> augmentation, Class<?> rtn, List<Class<?>> arguments,
4243
org.objectweb.asm.commons.Method method, int modifiers, MethodHandle handle) {
4344
this.name = name;
4445
this.augmentation = augmentation;
45-
this.owner = owner;
46+
this.target = target;
4647
this.rtn = rtn;
4748
this.arguments = Collections.unmodifiableList(arguments);
4849
this.method = method;
@@ -85,11 +86,11 @@ public MethodType getMethodType() {
8586
for (int i = 0; i < arguments.size(); i++) {
8687
params[i] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(arguments.get(i));
8788
}
88-
returnValue = owner.clazz;
89+
returnValue = target;
8990
} else {
9091
// virtual/interface method: add receiver class
9192
params = new Class<?>[1 + arguments.size()];
92-
params[0] = owner.clazz;
93+
params[0] = target;
9394
for (int i = 0; i < arguments.size(); i++) {
9495
params[i + 1] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(arguments.get(i));
9596
}
@@ -106,8 +107,8 @@ public void write(MethodWriter writer) {
106107
clazz = augmentation;
107108
type = org.objectweb.asm.Type.getType(augmentation);
108109
} else {
109-
clazz = owner.clazz;
110-
type = owner.type;
110+
clazz = target;
111+
type = Type.getType(target);
111112
}
112113

113114
if (Modifier.isStatic(modifiers)) {

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EListInit.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.elasticsearch.painless.lookup.PainlessMethod;
2727
import org.elasticsearch.painless.lookup.PainlessMethodKey;
2828
import org.elasticsearch.painless.lookup.def;
29+
import org.objectweb.asm.Type;
2930

3031
import java.util.ArrayList;
3132
import java.util.List;
@@ -90,7 +91,7 @@ void write(MethodWriter writer, Globals globals) {
9091

9192
writer.newInstance(MethodWriter.getType(actual));
9293
writer.dup();
93-
writer.invokeConstructor(constructor.owner.type, constructor.method);
94+
writer.invokeConstructor(Type.getType(constructor.target), constructor.method);
9495

9596
for (AExpression value : values) {
9697
writer.dup();

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EMapInit.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.elasticsearch.painless.lookup.PainlessMethod;
2727
import org.elasticsearch.painless.lookup.PainlessMethodKey;
2828
import org.elasticsearch.painless.lookup.def;
29+
import org.objectweb.asm.Type;
2930

3031
import java.util.HashMap;
3132
import java.util.List;
@@ -109,7 +110,7 @@ void write(MethodWriter writer, Globals globals) {
109110

110111
writer.newInstance(MethodWriter.getType(actual));
111112
writer.dup();
112-
writer.invokeConstructor(constructor.owner.type, constructor.method);
113+
writer.invokeConstructor(Type.getType(constructor.target), constructor.method);
113114

114115
for (int index = 0; index < keys.size(); ++index) {
115116
AExpression key = keys.get(index);

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENewObj.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.elasticsearch.painless.lookup.PainlessClass;
2727
import org.elasticsearch.painless.lookup.PainlessMethod;
2828
import org.elasticsearch.painless.lookup.PainlessMethodKey;
29+
import org.objectweb.asm.Type;
2930

3031
import java.util.List;
3132
import java.util.Objects;
@@ -104,7 +105,7 @@ void write(MethodWriter writer, Globals globals) {
104105
argument.write(writer, globals);
105106
}
106107

107-
writer.invokeConstructor(constructor.owner.type, constructor.method);
108+
writer.invokeConstructor(Type.getType(constructor.target), constructor.method);
108109
}
109110

110111
@Override

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/PSubField.java

+7-6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.elasticsearch.painless.MethodWriter;
2626
import org.elasticsearch.painless.lookup.PainlessField;
2727
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
28+
import org.objectweb.asm.Type;
2829

2930
import java.lang.reflect.Modifier;
3031
import java.util.Objects;
@@ -63,9 +64,9 @@ void write(MethodWriter writer, Globals globals) {
6364
writer.writeDebugInfo(location);
6465

6566
if (java.lang.reflect.Modifier.isStatic(field.modifiers)) {
66-
writer.getStatic(field.owner.type, field.javaName, MethodWriter.getType(field.clazz));
67+
writer.getStatic(Type.getType(field.target), field.javaName, MethodWriter.getType(field.clazz));
6768
} else {
68-
writer.getField(field.owner.type, field.javaName, MethodWriter.getType(field.clazz));
69+
writer.getField(Type.getType(field.target), field.javaName, MethodWriter.getType(field.clazz));
6970
}
7071
}
7172

@@ -94,9 +95,9 @@ void load(MethodWriter writer, Globals globals) {
9495
writer.writeDebugInfo(location);
9596

9697
if (java.lang.reflect.Modifier.isStatic(field.modifiers)) {
97-
writer.getStatic(field.owner.type, field.javaName, MethodWriter.getType(field.clazz));
98+
writer.getStatic(Type.getType(field.target), field.javaName, MethodWriter.getType(field.clazz));
9899
} else {
99-
writer.getField(field.owner.type, field.javaName, MethodWriter.getType(field.clazz));
100+
writer.getField(Type.getType(field.target), field.javaName, MethodWriter.getType(field.clazz));
100101
}
101102
}
102103

@@ -105,9 +106,9 @@ void store(MethodWriter writer, Globals globals) {
105106
writer.writeDebugInfo(location);
106107

107108
if (java.lang.reflect.Modifier.isStatic(field.modifiers)) {
108-
writer.putStatic(field.owner.type, field.javaName, MethodWriter.getType(field.clazz));
109+
writer.putStatic(Type.getType(field.target), field.javaName, MethodWriter.getType(field.clazz));
109110
} else {
110-
writer.putField(field.owner.type, field.javaName, MethodWriter.getType(field.clazz));
111+
writer.putField(Type.getType(field.target), field.javaName, MethodWriter.getType(field.clazz));
111112
}
112113
}
113114

0 commit comments

Comments
 (0)