This is an automated email from the ASF dual-hosted git repository. henrib pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-jexl.git
The following commit(s) were added to refs/heads/master by this push: new c70235e JEXL-275: lexical shade does not trigger undefined var if safe mode is true Task #JEXL-275 - Allow safe navigation as option c70235e is described below commit c70235e2ff12371bed4aca356de4abdf7d7bf64c Author: henrib <hen...@apache.org> AuthorDate: Wed Jun 10 13:50:00 2020 +0200 JEXL-275: lexical shade does not trigger undefined var if safe mode is true Task #JEXL-275 - Allow safe navigation as option --- .../org/apache/commons/jexl3/JexlException.java | 8 ++- .../apache/commons/jexl3/internal/Interpreter.java | 2 +- .../commons/jexl3/internal/InterpreterBase.java | 12 +++-- .../org/apache/commons/jexl3/Issues200Test.java | 15 ++++++ .../java/org/apache/commons/jexl3/JXLTTest.java | 62 ++++++++++++++++++---- 5 files changed, 83 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/apache/commons/jexl3/JexlException.java b/src/main/java/org/apache/commons/jexl3/JexlException.java index 01b2018..5ed8a6e 100644 --- a/src/main/java/org/apache/commons/jexl3/JexlException.java +++ b/src/main/java/org/apache/commons/jexl3/JexlException.java @@ -1031,9 +1031,13 @@ public class JexlException extends RuntimeException { * @param xinvoke the invocation exception * @return a JexlException */ - public static RuntimeException tryFailed(InvocationTargetException xinvoke) { - return new JexlException.TryFailed(xinvoke); // fail + public static JexlException tryFailed(InvocationTargetException xinvoke) { + Throwable cause = xinvoke.getCause(); + return cause instanceof JexlException + ? (JexlException) cause + : new JexlException.TryFailed(xinvoke); // fail } + /** * Detailed info message about this error. diff --git a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java index 07cc421..10679ac 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java +++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java @@ -1703,7 +1703,7 @@ public class Interpreter extends InterpreterBase { ? null : unsolvableMethod(node, methodName, argv); } catch (JexlException.TryFailed xany) { - throw invocationException(node, methodName, xany.getCause()); + throw invocationException(node, methodName, xany); } catch (JexlException xthru) { throw xthru; } catch (Exception xany) { diff --git a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java index cee0905..0b05b4d 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java +++ b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java @@ -290,10 +290,14 @@ public abstract class InterpreterBase extends ParserVisitor { } String name = identifier.getName(); Object value = context.get(name); - if (value == null && !context.has(name) - && !(identifier.jjtGetParent() instanceof ASTAssignment && isSafe()) - && !(identifier.jjtGetParent() instanceof ASTReference)) { - return unsolvableVariable(identifier, name, true); // undefined + if (value == null && !context.has(name)) { + boolean ignore = (isSafe() + && (symbol >= 0 + || identifier.jjtGetParent() instanceof ASTAssignment)) + || (identifier.jjtGetParent() instanceof ASTReference); + if (!ignore) { + return unsolvableVariable(identifier, name, true); // undefined + } } return value; } diff --git a/src/test/java/org/apache/commons/jexl3/Issues200Test.java b/src/test/java/org/apache/commons/jexl3/Issues200Test.java index 3045efd..cdc72f2 100644 --- a/src/test/java/org/apache/commons/jexl3/Issues200Test.java +++ b/src/test/java/org/apache/commons/jexl3/Issues200Test.java @@ -651,6 +651,21 @@ public class Issues200Test extends JexlTestCase { } @Test + public void test275d() throws Exception { + JexlContext ctxt = new MapContext(); + ctxt.set("out", System.out); + JexlEngine jexl = new JexlBuilder().strict(true).safe(true).create(); + + JexlScript e = jexl.createScript("{ var xyz = 42 } out.println(xyz)"); + try { + Object o = e.execute(ctxt); + Assert.assertNull(o); + } catch (JexlException.Variable xvar) { + Assert.fail("should not have thrown" + xvar); + } + } + + @Test public void test278() throws Exception { String[] srcs = new String[]{ "return union x143('arg',5,6) ", diff --git a/src/test/java/org/apache/commons/jexl3/JXLTTest.java b/src/test/java/org/apache/commons/jexl3/JXLTTest.java index cbea516..f68894b 100644 --- a/src/test/java/org/apache/commons/jexl3/JXLTTest.java +++ b/src/test/java/org/apache/commons/jexl3/JXLTTest.java @@ -46,30 +46,30 @@ public class JXLTTest extends JexlTestCase { private static final Log LOGGER = LogFactory.getLog(JxltEngine.class); private final MapContext vars = new MapContext(); private JexlEvalContext context = null; + private final JexlBuilder BUILDER; private final JexlEngine ENGINE; private final JxltEngine JXLT; - public JXLTTest(JexlEngine jexl) { + public JXLTTest(JexlBuilder builder) { super("JXLTTest"); - ENGINE = jexl; + BUILDER = builder; + ENGINE = BUILDER.create(); JXLT = ENGINE.createJxltEngine(); } @Parameterized.Parameters - public static List<JexlEngine> engines() { + public static List<JexlBuilder> engines() { JexlFeatures f = new JexlFeatures(); f.lexical(true).lexicalShade(true); - return Arrays.<JexlEngine>asList(new JexlEngine[] { + return Arrays.<JexlBuilder>asList(new JexlBuilder[] { new JexlBuilder().silent(false) .lexical(true).lexicalShade(true) - .cache(128).strict(true).create(), - + .cache(128).strict(true), new JexlBuilder().features(f).silent(false) - .cache(128).strict(true).create(), - + .cache(128).strict(true), new JexlBuilder().silent(false) - .cache(128).strict(true).create(), + .cache(128).strict(true), }); } @@ -1088,4 +1088,48 @@ public class JXLTTest extends JexlTestCase { Assert.assertFalse(xvar.isUndefined()); } } + + @Test + public void testTemplateOutOfScope() throws Exception { + JexlOptions opts = new JexlOptions(); + opts.setCancellable(false); + opts.setStrict(false); + opts.setLexical(false); + opts.setLexicalShade(false); + opts.setSharedInstance(true); + JexlContext ctxt = new PragmaticContext(opts); + String src = "$$if (false) { var tab = 42; }\n" + + "${tab}"; + JxltEngine.Template tmplt; + JexlFeatures features = BUILDER.features(); + try { + tmplt = JXLT.createTemplate("$$", new StringReader(src)); + } catch (JexlException xparse) { + if (features != null && features.isLexicalShade()) { + return; + } + throw xparse; + } + Writer strw = new StringWriter(); + opts.setSafe(true); + try { + tmplt.evaluate(ctxt, strw); + Assert.assertTrue(strw.toString().isEmpty()); + } catch (JexlException.Variable xvar) { + Assert.fail("safe should prevent local shade"); + } + opts.setStrict(true); + opts.setSafe(false); + try { + tmplt.evaluate(ctxt, strw); + Assert.fail("tab var is undefined"); + } catch (JexlException.Variable xvar) { + Assert.assertTrue("tab".equals(xvar.getVariable())); + Assert.assertTrue(xvar.isUndefined()); + } catch (JexlException xany) { + Assert.assertTrue(xany.getMessage().contains("tab")); + } + + } + }