Skip to content

Commit 0fb7a07

Browse files
authored
Merge pull request #177 from evolvedbinary/6.x.x/hotfix/inline-function-memory-leak
[6.x.x] Fix a memory leak in XPath 3.1 inline function implementation
2 parents 387e9c7 + 68bd164 commit 0fb7a07

2 files changed

Lines changed: 75 additions & 52 deletions

File tree

exist-core/pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,7 @@
11991199
<include>src/test/java/org/exist/xquery/ForwardReferenceTest.java</include>
12001200
<include>src/main/java/org/exist/xquery/Function.java</include>
12011201
<include>src/main/java/org/exist/xquery/FunctionFactory.java</include>
1202+
<include>src/main/java/org/exist/xquery/InlineFunction.java</include>
12021203
<include>src/test/java/org/exist/xquery/InternalModuleTest.java</include>
12031204
<include>src/main/java/org/exist/xquery/Intersect.java</include>
12041205
<include>src/test/java/org/exist/xquery/LexerTest.java</include>
@@ -1997,6 +1998,7 @@
19971998
<exclude>src/test/resources-filtered/org/exist/xquery/import-from-pkg-test.conf.xml</exclude>
19981999
<exclude>src/test/java/org/exist/xquery/ImportFromPkgTest.java</exclude>
19992000
<exclude>src/test/java/org/exist/xquery/ImportModuleTest.java</exclude>
2001+
<exclude>src/main/java/org/exist/xquery/InlineFunction.java</exclude>
20002002
<exclude>src/test/java/org/exist/xquery/InternalModuleTest.java</exclude>
20012003
<exclude>src/main/java/org/exist/xquery/Intersect.java</exclude>
20022004
<exclude>src/main/java/org/exist/xquery/JavaBinding.java</exclude>
Lines changed: 73 additions & 52 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
import java.util.Stack;
2750

@@ -34,69 +57,67 @@
3457

3558
/**
3659
* An XQuery 3.0 inline function expression.
37-
*
38-
* @author wolf
3960
*
61+
* @author wolf
62+
* @author <a href="mailto:adam@evolvedbinary.com">Adam Retter</a>
4063
*/
4164
public class InlineFunction extends AbstractExpression {
4265

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

50-
public InlineFunction(XQueryContext context, UserDefinedFunction function) {
51-
super(context);
52-
this.function = function;
53-
}
68+
private final UserDefinedFunction function;
5469

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

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

96108
@Override
97-
public void resetState(boolean postOptimization) {
109+
public int returnsType() {
110+
return Type.FUNCTION_REFERENCE;
111+
}
112+
113+
@Override
114+
public void resetState(final boolean postOptimization) {
98115
super.resetState(postOptimization);
99-
calls.clear();
116+
117+
if (!postOptimization) {
118+
function.setClosureVariables(null);
119+
}
120+
100121
function.resetState(postOptimization);
101122
}
102-
}
123+
}

0 commit comments

Comments
 (0)