Skip to content

Commit 95ebbe3

Browse files
authored
Merge pull request #176 from evolvedbinary/7.x.x/hotfix/inline-function-memory-leak
[7.x.x] Fix a memory leak in XPath 3.1 inline function implementation
2 parents a3b32f3 + 9917e1f commit 95ebbe3

2 files changed

Lines changed: 74 additions & 51 deletions

File tree

exist-core/pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,7 @@
12261226
<include>src/test/java/org/exist/xquery/ForwardReferenceTest.java</include>
12271227
<include>src/main/java/org/exist/xquery/Function.java</include>
12281228
<include>src/main/java/org/exist/xquery/FunctionFactory.java</include>
1229+
<include>src/main/java/org/exist/xquery/InlineFunction.java</include>
12291230
<include>src/main/java/org/exist/xquery/Intersect.java</include>
12301231
<include>src/test/java/org/exist/xquery/LexerTest.java</include>
12311232
<include>src/main/java/org/exist/xquery/LocationStep.java</include>
@@ -2037,6 +2038,7 @@
20372038
<exclude>src/test/resources-filtered/org/exist/xquery/import-from-pkg-test.conf.xml</exclude>
20382039
<exclude>src/test/java/org/exist/xquery/ImportFromPkgTest.java</exclude>
20392040
<exclude>src/test/java/org/exist/xquery/ImportModuleTest.java</exclude>
2041+
<exclude>src/main/java/org/exist/xquery/InlineFunction.java</exclude>
20402042
<exclude>src/main/java/org/exist/xquery/Intersect.java</exclude>
20412043
<exclude>src/main/java/org/exist/xquery/JavaBinding.java</exclude>
20422044
<exclude>src/test/resources-filtered/org/exist/xquery/JavaBindingTest.conf.xml</exclude>
Lines changed: 72 additions & 51 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
*
@@ -21,7 +45,6 @@
2145
*/
2246
package org.exist.xquery;
2347

24-
import java.util.ArrayDeque;
2548
import java.util.List;
2649

2750
import org.exist.dom.QName;
@@ -33,69 +56,67 @@
3356

3457
/**
3558
* An XQuery 3.0 inline function expression.
36-
*
37-
* @author wolf
3859
*
60+
* @author wolf
61+
* @author <a href="mailto:adam@evolvedbinary.com">Adam Retter</a>
3962
*/
4063
public class InlineFunction extends AbstractExpression {
4164

42-
public final static QName INLINE_FUNCTION_QNAME = QName.EMPTY_QNAME;
43-
44-
private UserDefinedFunction function;
45-
private ArrayDeque<FunctionCall> calls = new ArrayDeque<>();
46-
47-
private AnalyzeContextInfo cachedContextInfo;
65+
public static final QName INLINE_FUNCTION_QNAME = QName.EMPTY_QNAME;
4866

49-
public InlineFunction(XQueryContext context, UserDefinedFunction function) {
50-
super(context);
51-
this.function = function;
52-
}
67+
private final UserDefinedFunction function;
5368

54-
@Override
55-
public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
69+
private AnalyzeContextInfo cachedContextInfo;
70+
71+
public InlineFunction(final XQueryContext context, final UserDefinedFunction function) {
72+
super(context);
73+
this.function = function;
74+
}
5675

76+
@Override
77+
public void analyze(final AnalyzeContextInfo contextInfo) throws XPathException {
5778
cachedContextInfo = new AnalyzeContextInfo(contextInfo);
5879
cachedContextInfo.addFlag(SINGLE_STEP_EXECUTION);
5980
cachedContextInfo.setParent(this);
60-
}
61-
62-
@Override
63-
public void dump(ExpressionDumper dumper) {
64-
dumper.display("function");
65-
function.dump(dumper);
66-
}
67-
68-
/**
69-
* Wraps a function call around the function and returns a
70-
* reference to it. Make sure local variables in the context
71-
* are visible.
72-
*/
73-
public Sequence eval(Sequence contextSequence, Item contextItem)
74-
throws XPathException {
75-
// local variable context is known within inline function
76-
final List<ClosureVariable> closureVars = context.getLocalStack();
77-
78-
final FunctionCall call = new FunctionCall(context, function);
79-
call.getFunction().setClosureVariables(closureVars);
80-
call.setLocation(function.getLine(), function.getColumn());
81-
call.analyze(new AnalyzeContextInfo(cachedContextInfo));
82-
83-
// push the created function call to the stack so we can clear
84-
// it after execution
85-
calls.push(call);
86-
87-
return new FunctionReference(this, call);
88-
}
89-
90-
@Override
91-
public int returnsType() {
92-
return Type.FUNCTION;
93-
}
81+
}
82+
83+
@Override
84+
public void dump(final ExpressionDumper dumper) {
85+
dumper.display("function");
86+
function.dump(dumper);
87+
}
88+
89+
/**
90+
* Wraps a function call around the function and returns a
91+
* reference to it. Make sure local variables in the context
92+
* are visible.
93+
*/
94+
@Override
95+
public Sequence eval(final Sequence contextSequence, final Item contextItem) throws XPathException {
96+
// local variable context is known within inline function
97+
final List<ClosureVariable> closureVars = context.getLocalStack();
98+
99+
final FunctionCall call = new FunctionCall(context, function);
100+
call.getFunction().setClosureVariables(closureVars);
101+
call.setLocation(function.getLine(), function.getColumn());
102+
call.analyze(new AnalyzeContextInfo(cachedContextInfo));
103+
104+
return new FunctionReference(this, call);
105+
}
94106

95107
@Override
96-
public void resetState(boolean postOptimization) {
108+
public int returnsType() {
109+
return Type.FUNCTION;
110+
}
111+
112+
@Override
113+
public void resetState(final boolean postOptimization) {
97114
super.resetState(postOptimization);
98-
calls.clear();
115+
116+
if (!postOptimization) {
117+
function.setClosureVariables(null);
118+
}
119+
99120
function.resetState(postOptimization);
100121
}
101122
}

0 commit comments

Comments
 (0)