From 6caa932fff6e8cb573b1b84b0cca2478c00b0750 Mon Sep 17 00:00:00 2001 From: Kusal Kithul-Godage Date: Fri, 9 Aug 2024 19:53:59 +1000 Subject: [PATCH] WW-4062 Cache OgnlException thrown on compilation --- .../com/opensymphony/xwork2/ognl/OgnlUtil.java | 17 ++++++++++++++++- .../opensymphony/xwork2/ognl/OgnlUtilTest.java | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java index 52475b8d5..05d0be6c5 100644 --- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java +++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java @@ -601,12 +601,27 @@ public class OgnlUtil { if (enableExpressionCache) { tree = expressionCache.get(expr); } + if (tree instanceof OgnlException) { + // OgnlException was cached, rethrow it with updated stack trace + OgnlException e = (OgnlException) tree; + e.getCause().fillInStackTrace(); + throw e; + } if (tree == null) { - tree = ognlGuard.parseExpression(expr); + try { + tree = ognlGuard.parseExpression(expr); + } catch (OgnlException e) { + tree = e; + } if (enableExpressionCache) { expressionCache.put(expr, tree); } + if (tree instanceof OgnlException) { + // Rethrow OgnlException after caching + throw (OgnlException) tree; + } } + if (EXPR_BLOCKED.equals(tree)) { throw new OgnlException("Expression blocked by OgnlGuard: " + expr); } diff --git a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java index 27a0d0f33..b7ba175f7 100644 --- a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java @@ -1645,6 +1645,21 @@ public class OgnlUtilTest extends XWorkTestCase { assertThrows(OgnlException.class, () -> ognlUtil.getValue(vulnerableExpr, ognlUtil.createDefaultContext(null), null)); } + public void testCompilationErrorsCached() throws Exception { + OgnlException e = assertThrows(OgnlException.class, () -> ognlUtil.compile(".literal.$something")); + StackTraceElement[] stackTrace = e.getStackTrace(); + assertThat(stackTrace).isEmpty(); + StackTraceElement[] causeStackTrace = e.getCause().getStackTrace(); + + OgnlException e2 = assertThrows(OgnlException.class, () -> ognlUtil.compile(".literal.$something")); + StackTraceElement[] stackTrace2 = e.getStackTrace(); + assertThat(stackTrace2).isEmpty(); + StackTraceElement[] causeStackTrace2 = e.getCause().getStackTrace(); + + assertSame(e, e2); // Exception is cached + assertThat(causeStackTrace).isNotEqualTo(causeStackTrace2); // Stack trace refreshed + } + /** * Generate a new OgnlUtil instance (not configured by the {@link ContainerBuilder}) that can be used for * basic tests, with its Expression and BeanInfo factories set to LRU mode.