Author: jboynes
Date: Thu Apr  5 17:48:41 2018
New Revision: 1828458

URL: http://svn.apache.org/viewvc?rev=1828458&view=rev
Log:
57434 - Fix race condition in ELEvaluator for 1.0 expressions

Modified:
    tomcat/taglibs/standard/trunk/CHANGES.txt
    
tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/lang/jstl/ELEvaluator.java
    
tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/lang/jstl/Evaluator.java

Modified: tomcat/taglibs/standard/trunk/CHANGES.txt
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/CHANGES.txt?rev=1828458&r1=1828457&r2=1828458&view=diff
==============================================================================
--- tomcat/taglibs/standard/trunk/CHANGES.txt (original)
+++ tomcat/taglibs/standard/trunk/CHANGES.txt Thu Apr  5 17:48:41 2018
@@ -1,5 +1,6 @@
 Changes in 1.2.6 release
 60950 JSTL TransformSupport XSL import not finding relative path
+57434 Race condition in EL1.0 validation
 
 Changes in 1.2.5 release
 - Set version identifiers correctly, no other changes.

Modified: 
tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/lang/jstl/ELEvaluator.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/lang/jstl/ELEvaluator.java?rev=1828458&r1=1828457&r2=1828458&view=diff
==============================================================================
--- 
tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/lang/jstl/ELEvaluator.java
 (original)
+++ 
tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/lang/jstl/ELEvaluator.java
 Thu Apr  5 17:48:41 2018
@@ -102,13 +102,13 @@ public class ELEvaluator {
      * growth.
      * <p>NOTE: use LinkedHashmap if a dependency on J2SE 1.4+ is ok
      */
-    static Map sCachedExpressionStrings = null;
+    private static Map sCachedExpressionStrings = null;
 
     /**
      * The mapping from ExpectedType to Maps mapping literal String to
      * parsed value *
      */
-    static Map sCachedExpectedTypes = new HashMap();
+    private static final Map sCachedExpectedTypes = new HashMap();
 
     /**
      * The static Logger *
@@ -123,11 +123,12 @@ public class ELEvaluator {
     /**
      * Flag if the cache should be bypassed *
      */
-    boolean mBypassCache;
+    private volatile boolean mBypassCache;
 
     /**
      * The PageContext *
      */
+    // TODO: Find a better way to override the expression cache size that does 
not need this field.
     PageContext pageContext;
 
 
@@ -256,40 +257,46 @@ public class ELEvaluator {
             return "";
         }
 
-        if (!(mBypassCache) && (sCachedExpressionStrings == null)) {
-            createExpressionStringMap();
+        if (mBypassCache) {
+            return parseExpressionUncached(pExpressionString);
         }
 
+        Map cache = getOrCreateExpressionStringMap(pageContext);
+
         // See if it's in the cache
-        Object ret =
-                mBypassCache ?
-                        null :
-                        sCachedExpressionStrings.get(pExpressionString);
+        Object ret = cache.get(pExpressionString);
+        if (ret != null) {
+            return ret;
+        }
 
-        if (ret == null) {
-            // Parse the expression
+        ret = parseExpressionUncached(pExpressionString);
+        cache.put(pExpressionString, ret);
+        return ret;
+    }
+
+    /**
+     * Parse an expression string bypassing the cache.
+     *
+     * This allows expressions to be validated at translation time without 
polluting the cache.
+     *
+     * @param pExpressionString the text to parse
+     * @return the parse result
+     * @throws ELException if there was a problem parsing the expression text
+     */
+    public Object parseExpressionUncached(String pExpressionString) throws 
ELException {
+        try {
             Reader r = new StringReader(pExpressionString);
             ELParser parser = new ELParser(r);
-            try {
-                ret = parser.ExpressionString();
-                if (!mBypassCache) {
-                    sCachedExpressionStrings.put(pExpressionString, ret);
-                }
-            }
-            catch (ParseException exc) {
-                throw new ELException
-                        (formatParseException(pExpressionString,
-                                exc));
-            }
-            catch (TokenMgrError exc) {
-                // Note - this should never be reached, since the parser is
-                // constructed to tokenize any input (illegal inputs get
-                // parsed to <BADLY_ESCAPED_STRING_LITERAL> or
-                // <ILLEGAL_CHARACTER>
-                throw new ELException(exc.getMessage());
-            }
+            return parser.ExpressionString();
+        } catch (ParseException exc) {
+            throw new ELException(formatParseException(pExpressionString, 
exc));
+        } catch (TokenMgrError exc) {
+            // Note - this should never be reached, since the parser is
+            // constructed to tokenize any input (illegal inputs get
+            // parsed to <BADLY_ESCAPED_STRING_LITERAL> or
+            // <ILLEGAL_CHARACTER>
+            throw new ELException(exc.getMessage());
         }
-        return ret;
     }
 
     //-------------------------------------
@@ -358,31 +365,35 @@ public class ELEvaluator {
      * Creates LRU map of expression strings. If context parameter
      * specifying cache size is present use that as the maximum size
      * of the LRU map otherwise use default.
-     */
-    private synchronized void createExpressionStringMap() {
-        if (sCachedExpressionStrings != null) {
-            return;
-        }
-
-        final int maxSize;
-        if ((pageContext != null) && (pageContext.getServletContext() != 
null)) {
-            String value = 
pageContext.getServletContext().getInitParameter(EXPR_CACHE_PARAM);
-            if (value != null) {
-                maxSize = Integer.valueOf(value);
+     *
+     * TODO: Using the context parameter means the cache is sized based on the 
configuration
+     * of the first web application that calls this. This might be a problem 
if this jar is
+     * installed in the application server's classpath rather than the 
application's.
+     */
+    private static synchronized Map getOrCreateExpressionStringMap(PageContext 
pageContext) {
+        if (sCachedExpressionStrings == null) {
+
+            final int maxSize;
+            if ((pageContext != null) && (pageContext.getServletContext() != 
null)) {
+                String value = 
pageContext.getServletContext().getInitParameter(EXPR_CACHE_PARAM);
+                if (value != null) {
+                    maxSize = Integer.valueOf(value);
+                } else {
+                    maxSize = MAX_SIZE;
+                }
             } else {
                 maxSize = MAX_SIZE;
             }
-        } else {
-            maxSize = MAX_SIZE;
-        }
 
-        // fall through if it couldn't find the parameter
-        sCachedExpressionStrings = Collections.synchronizedMap(new 
LinkedHashMap() {
-            @Override
-            protected boolean removeEldestEntry(Map.Entry eldest) {
-                return size() > maxSize;
-            }
-        });
+            // fall through if it couldn't find the parameter
+            sCachedExpressionStrings = Collections.synchronizedMap(new 
LinkedHashMap() {
+                @Override
+                protected boolean removeEldestEntry(Map.Entry eldest) {
+                    return size() > maxSize;
+                }
+            });
+        }
+        return sCachedExpressionStrings;
     }
 
     //-------------------------------------

Modified: 
tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/lang/jstl/Evaluator.java
URL: 
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/lang/jstl/Evaluator.java?rev=1828458&r1=1828457&r2=1828458&view=diff
==============================================================================
--- 
tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/lang/jstl/Evaluator.java
 (original)
+++ 
tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/lang/jstl/Evaluator.java
 Thu Apr  5 17:48:41 2018
@@ -67,9 +67,7 @@ public class Evaluator
     public String validate(String pAttributeName,
                            String pAttributeValue) {
         try {
-            sEvaluator.setBypassCache(true);
-            sEvaluator.parseExpressionString(pAttributeValue);
-            sEvaluator.setBypassCache(false);
+            sEvaluator.parseExpressionUncached(pAttributeValue);
             return null;
         }
         catch (ELException exc) {



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to