Skip to content

Commit 6726e21

Browse files
authored
Merge pull request #182 from evolvedbinary/7.x.x/hotfix/lookup-operator-memory-leak
[7.x.x] Fix a memory leak in the XPath 3.1 Lookup Operator implementation
2 parents 95ebbe3 + 254e18d commit 6726e21

3 files changed

Lines changed: 99 additions & 34 deletions

File tree

exist-core/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,10 +1230,12 @@
12301230
<include>src/main/java/org/exist/xquery/Intersect.java</include>
12311231
<include>src/test/java/org/exist/xquery/LexerTest.java</include>
12321232
<include>src/main/java/org/exist/xquery/LocationStep.java</include>
1233+
<include>src/main/java/org/exist/xquery/Lookup.java</include>
12331234
<include>src/main/java/org/exist/xquery/Module.java</include>
12341235
<include>src/main/java/org/exist/xquery/NamedFunctionReference.java</include>
12351236
<include>src/main/java/org/exist/xquery/NameTest.java</include>
12361237
<include>src/test/java/org/exist/xquery/NodeTypeTest.java</include>
1238+
<include>src/main/java/org/exist/xquery/OpNumeric.java</include>
12371239
<include>src/main/java/org/exist/xquery/Optimizer.java</include>
12381240
<include>src/main/java/org/exist/xquery/Option.java</include>
12391241
<include>src/main/java/org/exist/xquery/PathExpr.java</include>
@@ -2045,11 +2047,13 @@
20452047
<exclude>src/test/java/org/exist/xquery/JavaBindingTest.java</exclude>
20462048
<exclude>src/test/java/org/exist/xquery/LexerTest.java</exclude>
20472049
<exclude>src/main/java/org/exist/xquery/LocationStep.java</exclude>
2050+
<exclude>src/main/java/org/exist/xquery/Lookup.java</exclude>
20482051
<exclude>src/main/java/org/exist/xquery/Materializable.java</exclude>
20492052
<exclude>src/main/java/org/exist/xquery/Module.java</exclude>
20502053
<exclude>src/main/java/org/exist/xquery/NamedFunctionReference.java</exclude>
20512054
<exclude>src/main/java/org/exist/xquery/NameTest.java</exclude>
20522055
<exclude>src/test/java/org/exist/xquery/NodeTypeTest.java</exclude>
2056+
<exclude>src/main/java/org/exist/xquery/OpNumeric.java</exclude>
20532057
<exclude>src/main/java/org/exist/xquery/Optimizer.java</exclude>
20542058
<exclude>src/main/java/org/exist/xquery/Option.java</exclude>
20552059
<exclude>src/main/java/org/exist/xquery/PathExpr.java</exclude>

exist-core/src/main/java/org/exist/xquery/Lookup.java

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
* admin@evolvedbinary.com
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; version 2.1.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*
21+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+
* The original license header is included below.
23+
*
24+
* =====================================================================
25+
*
226
* eXist-db Open Source Native XML Database
327
* Copyright (C) 2001 The eXist-db Authors
428
*
@@ -27,39 +51,41 @@
2751
import org.exist.xquery.util.ExpressionDumper;
2852
import org.exist.xquery.value.*;
2953

54+
import javax.annotation.Nullable;
55+
3056
/**
3157
* Implements the XQuery 3.1 lookup operator on maps and arrays.
3258
*
3359
* @author Wolfgang
3460
*/
3561
public class Lookup extends AbstractExpression {
3662

37-
private Expression contextExpression;
38-
private Sequence keys = null;
39-
private Expression keyExpression = null;
63+
private final Expression contextExpression;
64+
private @Nullable Sequence keys = null;
65+
private @Nullable Expression keyExpression = null;
4066

41-
public Lookup(XQueryContext context, Expression ctxExpr) {
67+
public Lookup(final XQueryContext context, final Expression contextExpression) {
4268
super(context);
43-
this.contextExpression = ctxExpr;
69+
this.contextExpression = contextExpression;
4470
}
4571

46-
public Lookup(XQueryContext context, Expression ctxExpr, String keyString) {
47-
this(context, ctxExpr);
48-
this.keys = new StringValue(ctxExpr, keyString);
72+
public Lookup(final XQueryContext context, final Expression contextExpression, final String keyString) {
73+
this(context, contextExpression);
74+
this.keys = new StringValue(contextExpression, keyString);
4975
}
5076

51-
public Lookup(XQueryContext context, Expression ctxExpr, int position) {
52-
this(context, ctxExpr);
53-
this.keys = new IntegerValue(ctxExpr, position);
77+
public Lookup(final XQueryContext context, final Expression contextExpression, final int position) {
78+
this(context, contextExpression);
79+
this.keys = new IntegerValue(contextExpression, position);
5480
}
5581

56-
public Lookup(XQueryContext context, Expression ctxExpr, Expression keyExpression) {
57-
this(context, ctxExpr);
82+
public Lookup(final XQueryContext context, final Expression contextExpression, @Nullable final Expression keyExpression) {
83+
this(context, contextExpression);
5884
this.keyExpression = keyExpression;
5985
}
6086

6187
@Override
62-
public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
88+
public void analyze(final AnalyzeContextInfo contextInfo) throws XPathException {
6389
final AnalyzeContextInfo contextCopy = new AnalyzeContextInfo(contextInfo);
6490
if (contextExpression != null) {
6591
contextExpression.analyze(contextCopy);
@@ -70,16 +96,18 @@ public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
7096
}
7197

7298
@Override
73-
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
99+
public Sequence eval(Sequence contextSequence, final Item contextItem) throws XPathException {
74100
if (contextItem != null) {
75101
contextSequence = contextItem.toSequence();
76102
}
77-
Sequence leftSeq;
103+
104+
final Sequence leftSeq;
78105
if (contextExpression == null && contextSequence == null) {
79-
throw new XPathException(this, ErrorCodes.XPDY0002,
80-
"Lookup has nothing to select, the context item is absent");
106+
throw new XPathException(this, ErrorCodes.XPDY0002, "Lookup has nothing to select, the context item is absent");
107+
81108
} else if (contextExpression == null) {
82109
leftSeq = contextSequence;
110+
83111
} else {
84112
leftSeq = contextExpression.eval(contextSequence, null);
85113
}
@@ -90,39 +118,44 @@ public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathExc
90118
return Sequence.EMPTY_SEQUENCE;
91119
}
92120

93-
94121
if (!(Type.subTypeOf(contextType, Type.MAP_ITEM) || Type.subTypeOf(contextType, Type.ARRAY_ITEM))) {
95-
throw new XPathException(this, ErrorCodes.XPTY0004,
96-
"expression to the left of a lookup operator needs to be a sequence of maps or arrays");
122+
throw new XPathException(this, ErrorCodes.XPTY0004, "expression to the left of a lookup operator needs to be a sequence of maps or arrays");
97123
}
124+
98125
if (keyExpression != null) {
99126
keys = keyExpression.eval(contextSequence, null);
100127
if (keys.isEmpty()) {
101128
return Sequence.EMPTY_SEQUENCE;
102129
}
103130
}
131+
104132
try {
105133
final ValueSequence result = new ValueSequence();
106-
for (SequenceIterator i = leftSeq.iterate(); i.hasNext(); ) {
134+
for (final SequenceIterator i = leftSeq.iterate(); i.hasNext(); ) {
107135
final LookupSupport item = (LookupSupport) i.nextItem();
136+
108137
if (keys != null) {
109-
for (SequenceIterator j = keys.iterate(); j.hasNext(); ) {
138+
for (final SequenceIterator j = keys.iterate(); j.hasNext(); ) {
110139
final AtomicValue key = j.nextItem().atomize();
111-
Sequence value = item.get(key);
140+
final Sequence value = item.get(key);
112141
if (value != null) {
113142
result.addAll(value);
114143
}
115144
}
116-
} else if(item instanceof ArrayType) {
145+
146+
} else if (item instanceof ArrayType) {
117147
result.addAll(item.keys());
118-
} else if(item instanceof AbstractMapType) {
119-
for(final IEntry<AtomicValue, Sequence> entry : ((AbstractMapType)item)) {
148+
149+
} else if (item instanceof AbstractMapType) {
150+
for (final IEntry<AtomicValue, Sequence> entry : ((AbstractMapType)item)) {
120151
result.addAll(entry.value());
121152
}
122153
}
123154
}
155+
124156
return result;
125-
} catch (XPathException e) {
157+
158+
} catch (final XPathException e) {
126159
e.setLocation(getLine(), getColumn(), getSource());
127160
throw e;
128161
}
@@ -139,29 +172,35 @@ public Cardinality getCardinality() {
139172
}
140173

141174
@Override
142-
public void dump(ExpressionDumper dumper) {
175+
public void dump(final ExpressionDumper dumper) {
143176
if (contextExpression != null) {
144177
contextExpression.dump(dumper);
145178
}
179+
146180
dumper.display("?");
181+
147182
if (keyExpression == null && keys != null && keys.getItemCount() > 0) {
148183
try {
149184
dumper.display(keys.itemAt(0).getStringValue());
150-
} catch (XPathException e) {
185+
} catch (final XPathException e) {
151186
// impossible
152187
}
188+
153189
} else if (keyExpression != null) {
154190
keyExpression.dump(dumper);
155191
}
156192
}
157193

158194
@Override
159-
public void resetState(boolean postOptimization) {
195+
public void resetState(final boolean postOptimization) {
160196
super.resetState(postOptimization);
197+
161198
if (contextExpression != null) {
162199
contextExpression.resetState(postOptimization);
163200
}
201+
164202
if (keyExpression != null) {
203+
keys = null;
165204
keyExpression.resetState(postOptimization);
166205
}
167206
}

exist-core/src/main/java/org/exist/xquery/OpNumeric.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
* admin@evolvedbinary.com
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; version 2.1.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*
21+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+
* The original license header is included below.
23+
*
24+
* =====================================================================
25+
*
226
* eXist-db Open Source Native XML Database
327
* Copyright (C) 2001 The eXist-db Authors
428
*
@@ -25,7 +49,6 @@
2549
import java.util.TreeMap;
2650

2751
import com.evolvedbinary.j8fu.tuple.Tuple2;
28-
import org.exist.dom.persistent.NodeSet;
2952
import org.exist.storage.DBBroker;
3053
import org.exist.xquery.Constants.ArithmeticOperator;
3154
import org.exist.xquery.util.ExpressionDumper;
@@ -38,14 +61,13 @@
3861
import static com.evolvedbinary.j8fu.tuple.Tuple.Tuple;
3962

4063
/**
41-
* numeric operation on two operands by +, -, *, div, mod etc..
64+
* numeric operation on two operands by +, -, *, div, mod etc.
4265
*
4366
*/
4467
public class OpNumeric extends BinaryOp {
4568

4669
protected final ArithmeticOperator operator;
4770
protected int returnType = Type.ANY_ATOMIC_TYPE;
48-
protected NodeSet temp = null;
4971
protected DBBroker broker;
5072

5173
public OpNumeric(final XQueryContext context, final ArithmeticOperator operator) {

0 commit comments

Comments
 (0)