Fixes #715 - stack too deep in comment scan.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Sun, 3 Jan 2016 14:48:42 +0000 (14:48 +0000)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Sun, 3 Jan 2016 15:30:37 +0000 (15:30 +0000)
Using recursion was a short sighted idea.

History.md
lib/imports/inliner.js
test/integration-test.js

index 9965dc0..882a53c 100644 (file)
@@ -9,6 +9,7 @@
 * Fixed issue [#693](https://github.com/jakubpawlowicz/clean-css/issues/693) - restructuring edge case.
 * Fixed issue [#711](https://github.com/jakubpawlowicz/clean-css/issues/711) - border fuzzy matching.
 * Fixed issue [#714](https://github.com/jakubpawlowicz/clean-css/issues/714) - stringifying property level at rules.
+* Fixed issue [#715](https://github.com/jakubpawlowicz/clean-css/issues/715) - stack too deep in comment scan.
 
 [3.4.8 / 2015-11-13](https://github.com/jakubpawlowicz/clean-css/compare/v3.4.7...v3.4.8)
 ==================
index 9a58651..c6686a7 100644 (file)
@@ -123,32 +123,30 @@ function commentScanner(data) {
     if (noComments)
       return false;
 
-    // idx can be still within last matched comment (many @import statements inside one comment)
-    if (idx > lastStartIndex && idx < lastEndIndex)
-      return true;
-
-    comment = data.match(commentRegex);
-
-    if (!comment) {
-      noComments = true;
-      return false;
-    }
-
-    // get the indexes relative to the current data chunk
-    lastStartIndex = localStartIndex = comment.index;
-    localEndIndex = localStartIndex + comment[0].length;
-
-    // calculate the indexes relative to the full original data
-    globalEndIndex = localEndIndex + lastEndIndex;
-    globalStartIndex = globalEndIndex - comment[0].length;
-
-    // chop off data up to and including current comment block
-    data = data.substring(localEndIndex);
-    lastEndIndex = globalEndIndex;
-
-    // re-run scan if comment ended before the idx
-    if (globalEndIndex < idx)
-      return scanner(idx);
+    do {
+      // idx can be still within last matched comment (many @import statements inside one comment)
+      if (idx > lastStartIndex && idx < lastEndIndex)
+        return true;
+
+      comment = data.match(commentRegex);
+
+      if (!comment) {
+        noComments = true;
+        return false;
+      }
+
+      // get the indexes relative to the current data chunk
+      lastStartIndex = localStartIndex = comment.index;
+      localEndIndex = localStartIndex + comment[0].length;
+
+      // calculate the indexes relative to the full original data
+      globalEndIndex = localEndIndex + lastEndIndex;
+      globalStartIndex = globalEndIndex - comment[0].length;
+
+      // chop off data up to and including current comment block
+      data = data.substring(localEndIndex);
+      lastEndIndex = globalEndIndex;
+    } while (globalEndIndex < idx);
 
     return globalEndIndex > idx && idx > globalStartIndex;
   };
index ecc8ef9..3c1f09c 100644 (file)
@@ -4,6 +4,17 @@ var path = require('path');
 var optimizerContext = require('./test-helper').optimizerContext;
 var lineBreak = require('os').EOL;
 
+function generateComments(count) {
+  var output = [];
+  var i;
+
+  for (i = 0; i < count; i++) {
+    output.push('/* */');
+  }
+
+  return output.join('');
+}
+
 vows.describe('integration tests')
   .addBatch(
     optimizerContext('identity', {
@@ -2075,6 +2086,10 @@ vows.describe('integration tests')
       'remote inside local after imported content': [
         '@import url(test/fixtures/partials/one.css);@import url(test/fixtures/partials/remote.css);',
         '.one{color:red}'
+      ],
+      'scanning comments and stack too deep exception': [
+        generateComments(30000) + '@import url(fonts.google.com/some.css);',
+        ''
       ]
     }, { root: process.cwd() })
   )