allVars field in org.mvel2.util.VariableSpaceModel class should be defined as final.
[Background]
It is reported that NPE like (*1) rarely occurs at (*2-1) in org.mvel2.util.SimpleVariableSpaceModel#createFactory(Object[]) when workload is very high.
(*1) NullPointerException
2021-09-12 03:29:44.164 ERROR [stderr] (default task-26) Caused by: java.lang.NullPointerException 2021-09-12 03:29:44.164 ERROR [stderr] (default task-26) at org.mvel2.util.SimpleVariableSpaceModel.createFactory(SimpleVariableSpaceModel.java:18) 2021-09-12 03:29:44.164 ERROR [stderr] (default task-26) at org.drools.core.base.mvel.MVELCompilationUnit.createFactory(MVELCompilationUnit.java:298) 2021-09-12 03:29:44.164 ERROR [stderr] (default task-26) at org.drools.core.rule.constraint.MvelConditionEvaluator.evaluate(MvelConditionEvaluator.java:117) 2021-09-12 03:29:44.164 ERROR [stderr] (default task-26) at org.drools.core.rule.constraint.MvelConditionEvaluator.evaluate(MvelConditionEvaluator.java:98) 2021-09-12 03:29:44.164 ERROR [stderr] (default task-26) at org.drools.core.rule.constraint.MvelConstraint.evaluate(MvelConstraint.java:275) 2021-09-12 03:29:44.164 ERROR [stderr] (default task-26) ... 153 more
(*2) Excerpt from org/mvel2/util/SimpleVariableSpaceModel.java
: : 12 public class SimpleVariableSpaceModel extends VariableSpaceModel { 13 public SimpleVariableSpaceModel(String[] varNames) { 14 this.allVars = varNames; 15 } 16 17 public VariableResolverFactory createFactory(Object[] vals) { 18 VariableResolver[] resolvers = new VariableResolver[allVars.length]; <---------- (*2-1) NPE occurs here. 19 for (int i = 0; i < resolvers.length; i++) { 20 if (i >= vals.length) { 21 resolvers[i] = new SimpleValueResolver(null); 22 } 23 else { 24 resolvers[i] = new IndexVariableResolver(i, vals); 25 } 26 } 27 28 return new IndexedVariableResolverFactory(allVars, resolvers); 29 } 30 } : :
allVars field in VariableSpaceModel class is currently defined without final. According to (*3) and (*4) in [1], a non-final field is not guaranteed to be seen its expected value after the object's constructor finishes, and it may be related to the NPE issue above.
allVars is a field which does not need to be modified after initialization, so it should be defined as final to eliminate the possibility to cause the NPE issue due to being non-final field.
[1] The Java Language Specification (Java SE 11 Edition) - 17.5. final Field Semantics
https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.5
(Excerpt from [1])
17.5. final Field Semantics
:
:
Example 17.5-1. final Fields In The Java Memory Model
The program below illustrates how final fields compare to normal fields.class FinalFieldExample { final int x; int y; static FinalFieldExample f; public FinalFieldExample() { x = 3; y = 4; } static void writer() { f = new FinalFieldExample(); } static void reader() { if (f != null) { int i = f.x; // guaranteed to see 3 int j = f.y; // could see 0 <---------- (*3) } } }The class FinalFieldExample has a final int field x and a non-final int field y. One thread might execute the method writer and another might execute the method reader.
Because the writer method writes f after the object's constructor finishes, the reader method will be guaranteed to see the properly initialized value for f.x: it will read the value 3. However, f.y is not final; the reader method is therefore not guaranteed to see the value 4 for it. <---------- (*4)
- incorporates
-
DROOLS-6741 Upgrade to mvel 2.4.14+
- Closed