This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 1d672d78c8295c7545148c2fbcc2b1aa403baa84 Author: opencode <[email protected]> AuthorDate: Sun Oct 18 14:25:17 2026 +0200 Reject multiple parameter sets for EL constructor and static calls When an unprefixed function call resolved through the import handler, to a class (constructor invocation) or a static import (static method invocation), AstFunction evaluated only the first set of method parameters and silently discarded any additional sets. Expressions such as ${Integer(1000)(2000)} and, with String.valueOf statically imported, ${valueOf('a')('b')} quietly ignored the trailing sets and returned the single-set result. The other two resolution paths in the same method already reject extra sets: the declared-function path raises error.function.tooManyMethodParameterSets and the lambda path raises error.lambda.tooManyMethodParameterSets after consuming one set per nested lambda. Only the lambda path supports chained parameter sets, since only a lambda can return something callable. Apply the same rule as the declared-function path to the constructor and static method dispatch, merging the two branches so the check runs once before invocation. The check sits inside the resolution guard so names that resolve to neither a class nor a static method continue to report the existing function-not-found error. Adds tests for both resolved paths and a test pinning the unchanged error for unresolved names. --- java/org/apache/el/parser/AstFunction.java | 17 +++++++--- test/org/apache/el/parser/TestAstFunction.java | 46 ++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/java/org/apache/el/parser/AstFunction.java b/java/org/apache/el/parser/AstFunction.java index 049e6882aa..2621d42c2b 100644 --- a/java/org/apache/el/parser/AstFunction.java +++ b/java/org/apache/el/parser/AstFunction.java @@ -124,13 +124,20 @@ public final class AstFunction extends SimpleNode { // Call to a constructor or a static method obj = ctx.getImportHandler().resolveClass(this.localName); - if (obj != null) { - return ctx.getELResolver().invoke(ctx, new ELClass((Class<?>) obj), "<init>", null, - ((AstMethodParameters) this.children[0]).getParameters(ctx)); + String methodName = "<init>"; + if (obj == null) { + obj = ctx.getImportHandler().resolveStatic(this.localName); + methodName = this.localName; } - obj = ctx.getImportHandler().resolveStatic(this.localName); if (obj != null) { - return ctx.getELResolver().invoke(ctx, new ELClass((Class<?>) obj), this.localName, null, + // The result of a constructor or static method call is not + // treated as a lambda expression so there must be just a single + // set of method parameters + if (this.jjtGetNumChildren() != 1) { + throw new ELException(MessageFactory.get("error.function.tooManyMethodParameterSets", + getOutputName())); + } + return ctx.getELResolver().invoke(ctx, new ELClass((Class<?>) obj), methodName, null, ((AstMethodParameters) this.children[0]).getParameters(ctx)); } } diff --git a/test/org/apache/el/parser/TestAstFunction.java b/test/org/apache/el/parser/TestAstFunction.java index e0ae0f6be8..2137afe565 100644 --- a/test/org/apache/el/parser/TestAstFunction.java +++ b/test/org/apache/el/parser/TestAstFunction.java @@ -17,6 +17,7 @@ package org.apache.el.parser; import jakarta.el.ELContext; +import jakarta.el.ELException; import jakarta.el.ELProcessor; import jakarta.el.ExpressionFactory; import jakarta.el.StandardELContext; @@ -43,6 +44,51 @@ public class TestAstFunction { Assert.assertEquals(Integer.valueOf(1000), result); } + @Test + public void testImportConstructorTooManyParameterSets() { + // resolveClass path: the result of a constructor call is not treated as + // a lambda so only a single set of method parameters is valid. The extra + // set must be rejected rather than silently ignored. + ELProcessor processor = new ELProcessor(); + try { + processor.getValue("Integer(1000)(2000)", Object.class); + Assert.fail("An ELException was expected"); + } catch (ELException e) { + // Expected + } + } + + @Test + public void testImportStaticTooManyParameterSets() { + // resolveStatic path: the result of a static method call is not treated + // as a lambda so only a single set of method parameters is valid. The + // extra set must be rejected rather than silently ignored. + ELProcessor processor = new ELProcessor(); + processor.getELManager().getELContext().getImportHandler().importStatic("java.lang.String.valueOf"); + try { + processor.getValue("valueOf('a')('b')", Object.class); + Assert.fail("An ELException was expected"); + } catch (ELException e) { + // Expected + } + } + + @Test + public void testUnresolvedNameTooManyParameterSets() { + // A name that resolves to neither a class nor a static method must still + // report the "function not found" error, not the too-many-parameters + // error. This pins the placement of the parameter-set check so that it + // cannot be hoisted above the resolution. + ELProcessor processor = new ELProcessor(); + try { + processor.getValue("unknown(1)(2)", Object.class); + Assert.fail("An ELException was expected"); + } catch (ELException e) { + Assert.assertTrue("Unexpected message: " + e.getMessage(), + e.getMessage().contains("not found")); + } + } + @Test public void testVarargMethod() throws NoSuchMethodException, SecurityException { ExpressionFactory factory = ExpressionFactory.newInstance(); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
