This is an automated email from the ASF dual-hosted git repository.

matthiasblaesing pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new c673cdc  [NETBEANS-1872] Prevent backtracking loops in CSS Parser 
(#1417)
c673cdc is described below

commit c673cdc07ff14ae0cb3b9615abb7447be627a30c
Author: Matthias Bläsing <[email protected]>
AuthorDate: Sun Aug 11 11:25:28 2019 +0200

    [NETBEANS-1872] Prevent backtracking loops in CSS Parser (#1417)
    
    The references issue found cases, where the CSS grammar lead to
    an inifite backtracking loop. This patch works around that limitation
    by requireing that the parsing progresses.
    
    The implementation counts the read calls issued without progressing
    through the stream. If the read count withouth progress exceeds
    10.000.000 reads, parsing is stopped.
    
    The number was found experimentally - it needs to be large enough to
    handle real world cases and low enough that progress happens early
    enough.
---
 .../modules/css/lib/nbparser/CssParser.java        |  17 ++-
 .../lib/nbparser/ProgressingFailedException.java   |  38 ++++++
 .../css/lib/nbparser/ProgressingTokenStream.java   | 132 +++++++++++++++++++++
 3 files changed, 185 insertions(+), 2 deletions(-)

diff --git 
a/ide/css.lib/src/org/netbeans/modules/css/lib/nbparser/CssParser.java 
b/ide/css.lib/src/org/netbeans/modules/css/lib/nbparser/CssParser.java
index caffd49..d93ac83 100644
--- a/ide/css.lib/src/org/netbeans/modules/css/lib/nbparser/CssParser.java
+++ b/ide/css.lib/src/org/netbeans/modules/css/lib/nbparser/CssParser.java
@@ -19,6 +19,7 @@
 package org.netbeans.modules.css.lib.nbparser;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -94,14 +95,26 @@ public class CssParser extends Parser {
             CharSequence source = tooLargeSnapshot ? "" : snapshot.getText();
             
             ExtCss3Lexer lexer = new ExtCss3Lexer(source, mimeType);
-            TokenStream tokenstream = new CommonTokenStream(lexer);
+            TokenStream tokenstream = new ProgressingTokenStream(
+                10_000_000,
+                new CommonTokenStream(lexer));
             NbParseTreeBuilder builder = new NbParseTreeBuilder(source);
             ExtCss3Parser parser = new ExtCss3Parser(tokenstream, builder, 
mimeType);
 
             if (cancelled.get()) {
                 return;
             }
-            parser.styleSheet();
+
+            try {
+                parser.styleSheet();
+            } catch (ProgressingFailedException pfe) {
+                LOG.log(Level.INFO, "CSS/SASS/LESS document exceeded maximum 
reads: " + snapshot.getSource().getFileObject());
+                this.tree = null;
+                this.problems = Arrays.asList(new ProblemDescription(
+                    0, snapshot.getText().length(), "Failed to parse 
CSS/SASS/LESS document", ProblemDescription.Keys.PARSING.name(), 
ProblemDescription.Type.FATAL
+                ));
+                return;
+            }
 
             if (cancelled.get()) {
                 return;
diff --git 
a/ide/css.lib/src/org/netbeans/modules/css/lib/nbparser/ProgressingFailedException.java
 
b/ide/css.lib/src/org/netbeans/modules/css/lib/nbparser/ProgressingFailedException.java
new file mode 100644
index 0000000..18a725a
--- /dev/null
+++ 
b/ide/css.lib/src/org/netbeans/modules/css/lib/nbparser/ProgressingFailedException.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.css.lib.nbparser;
+
+public class ProgressingFailedException extends RuntimeException {
+
+    public ProgressingFailedException() {
+    }
+
+    public ProgressingFailedException(String message) {
+        super(message);
+    }
+
+    public ProgressingFailedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public ProgressingFailedException(Throwable cause) {
+        super(cause);
+    }
+
+}
diff --git 
a/ide/css.lib/src/org/netbeans/modules/css/lib/nbparser/ProgressingTokenStream.java
 
b/ide/css.lib/src/org/netbeans/modules/css/lib/nbparser/ProgressingTokenStream.java
new file mode 100644
index 0000000..73abaf7
--- /dev/null
+++ 
b/ide/css.lib/src/org/netbeans/modules/css/lib/nbparser/ProgressingTokenStream.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.css.lib.nbparser;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenSource;
+import org.antlr.runtime.TokenStream;
+
+public class ProgressingTokenStream implements TokenStream {
+    private final int maxReadCalls;
+    private final TokenStream backingStream;
+
+    public ProgressingTokenStream(int maxReadCalls, TokenStream backingStream) 
{
+        this.maxReadCalls = maxReadCalls;
+        this.backingStream = backingStream;
+    }
+
+    @Override
+    public Token LT(int k) {
+        Token t = backingStream.LT(k);
+        limitReadCalls(t);
+        return t;
+    }
+
+    @Override
+    public Token get(int i) {
+        Token t = backingStream.get(i);
+        limitReadCalls(t);
+        return t;
+    }
+
+    private int highestReachedIndex = 0;
+    private int readCalls = 0;
+
+    private void limitReadCalls(Token t) throws RuntimeException {
+        int index = t.getTokenIndex();
+        if (index > highestReachedIndex) {
+            highestReachedIndex = index;
+            readCalls = 0;
+        }
+        readCalls++;
+        if (readCalls > maxReadCalls) {
+            throw new ProgressingFailedException("Excessive read calls");
+        }
+    }
+
+    @Override
+    public int range() {
+        return backingStream.range();
+    }
+
+    @Override
+    public TokenSource getTokenSource() {
+        return backingStream.getTokenSource();
+    }
+
+    @Override
+    public String toString(int i, int i1) {
+        return backingStream.toString(i, i1);
+    }
+
+    @Override
+    public String toString(Token token, Token token1) {
+        return backingStream.toString(token, token1);
+    }
+
+    @Override
+    public void consume() {
+        backingStream.consume();
+    }
+
+    @Override
+    public int LA(int i) {
+        return backingStream.LA(i);
+    }
+
+    @Override
+    public int mark() {
+        return backingStream.mark();
+    }
+
+    @Override
+    public int index() {
+        return backingStream.index();
+    }
+
+    @Override
+    public void rewind(int i) {
+        backingStream.rewind(i);
+    }
+
+    @Override
+    public void rewind() {
+        backingStream.rewind();
+    }
+
+    @Override
+    public void release(int i) {
+        backingStream.release(i);
+    }
+
+    @Override
+    public void seek(int i) {
+        backingStream.seek(i);
+    }
+
+    @Override
+    public int size() {
+        return backingStream.size();
+    }
+
+    @Override
+    public String getSourceName() {
+        return backingStream.getSourceName();
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to