Skip to content

Commit

Permalink
Prevent long strings from causing a regexp buffer overflow exception.
Browse files Browse the repository at this point in the history
This bug was reported here: sass#104
  • Loading branch information
Jason Hutchens committed Nov 29, 2011
1 parent cc73198 commit 3db1961
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 7 deletions.
2 changes: 2 additions & 0 deletions doc-src/SASS_CHANGELOG.md
Expand Up @@ -15,6 +15,8 @@
been successfully compiled. Thanks to [Christian Peters](https://github.com/ChristianPeters).
* Allow absolute paths to be used in an importer with a different root.
* Don't destructively modify the options when running `Sass::Plugin.force_update`.
* Prevent Regexp buffer overflows when parsing long strings.
Thanks to [Agworld](https://github.com/Agworld).

### Deprecations -- Must Read!

Expand Down
13 changes: 9 additions & 4 deletions lib/sass/scss/parser.rb
Expand Up @@ -437,7 +437,7 @@ def declaration_or_ruleset
end

def selector_sequence
if sel = tok(STATIC_SELECTOR)
if sel = tok(STATIC_SELECTOR, true)
return [sel]
end

Expand Down Expand Up @@ -681,7 +681,7 @@ def value!
# we don't parse it at all, and instead return a plain old string
# containing the value.
# This results in a dramatic speed increase.
if val = tok(STATIC_VALUE)
if val = tok(STATIC_VALUE, true)
return space, Sass::Script::String.new(val.strip)
end
return space, sass_script(:parse)
Expand Down Expand Up @@ -770,7 +770,7 @@ def _interp_string(type)
end

def interp_ident(start = IDENT)
return unless val = tok(start) || interpolation || tok(IDENT_HYPHEN_INTERP)
return unless val = tok(start) || interpolation || tok(IDENT_HYPHEN_INTERP, true)
res = [val]
while val = tok(NAME) || interpolation
res << val
Expand Down Expand Up @@ -944,9 +944,14 @@ def self.prior_snippet(scanner)
# This is important because `#tok` is called all the time.
NEWLINE = "\n"

def tok(rx)
def tok(rx, last_group_lookahead = false)
res = @scanner.scan(rx)
if res
if last_group_lookahead
last_group = @scanner[-1]
@scanner.pos -= last_group.length
res.chomp!(last_group)
end
@line += res.count(NEWLINE)
@expected = nil
if !@strs.empty? && rx != COMMENT && rx != SINGLE_LINE_COMMENT
Expand Down
6 changes: 3 additions & 3 deletions lib/sass/scss/rx.rb
Expand Up @@ -112,17 +112,17 @@ def self.quote(str, flags = 0)
INTERP_START = /#\{/
MOZ_ANY = quote(":-moz-any(", Regexp::IGNORECASE)

IDENT_HYPHEN_INTERP = /-(?=#\{)/
IDENT_HYPHEN_INTERP = /-(#\{)/
STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|\\#{NL}|#{ESCAPE})*)\"/
STRING2_NOINTERP = /\'((?:[^\n\r\f\\'#]|#(?!\{)|\\#{NL}|#{ESCAPE})*)\'/
STRING_NOINTERP = /#{STRING1_NOINTERP}|#{STRING2_NOINTERP}/
# Can't use IDENT here, because it seems to take exponential time on 1.8.
# We could use it for 1.9 only, but I don't want to introduce a cross-version
# behavior difference.
# In any case, almost all CSS idents will be matched by this.
STATIC_VALUE = /(-?#{NMSTART}|#{STRING_NOINTERP}|\s(?!%)|#[a-f0-9]|[,%]|#{NUM}|\!important)+(?=[;}])/i
STATIC_VALUE = /(-?#{NMSTART}|#{STRING_NOINTERP}|\s(?!%)|#[a-f0-9]|[,%]|#{NUM}|\!important)+([;}])/i

STATIC_SELECTOR = /(#{NMCHAR}|\s|[,>+*]|[:#.]#{NMSTART})+(?=[{])/i
STATIC_SELECTOR = /(#{NMCHAR}|\s|[,>+*]|[:#.]#{NMSTART})+([{])/i
end
end
end

0 comments on commit 3db1961

Please sign in to comment.