From 02428e022a1804426fc7e06ff158f186a9f281ca Mon Sep 17 00:00:00 2001
From: xzyfer <xzyfer@gmail.com>
Date: Wed, 4 Jul 2018 21:45:59 +1000
Subject: [PATCH] Fix possible out of band read in prelexer

Fixes #2656
---
 src/lexer.cpp | 13 ++++++++++++-
 src/lexer.hpp | 14 +++++++-------
 2 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/src/lexer.cpp b/src/lexer.cpp
index be7f67713..5a5464cf8 100644
--- a/src/lexer.cpp
+++ b/src/lexer.cpp
@@ -33,30 +33,35 @@ namespace Sass {
 
     bool is_alpha(const char& chr)
     {
+      if (!chr) return false;
       return unsigned(chr - 'A') <= 'Z' - 'A' ||
              unsigned(chr - 'a') <= 'z' - 'a';
     }
 
     bool is_space(const char& chr)
     {
+      if (!chr) return false;
       // adapted the technique from is_alpha
       return chr == ' ' || unsigned(chr - '\t') <= '\r' - '\t';
     }
 
     bool is_digit(const char& chr)
     {
+      if (!chr) return false;
       // adapted the technique from is_alpha
       return unsigned(chr - '0') <= '9' - '0';
     }
 
     bool is_number(const char& chr)
     {
+      if (!chr) return false;
       // adapted the technique from is_alpha
       return is_digit(chr) || chr == '-' || chr == '+';
     }
 
     bool is_xdigit(const char& chr)
     {
+      if (!chr) return false;
       // adapted the technique from is_alpha
       return unsigned(chr - '0') <= '9' - '0' ||
              unsigned(chr - 'a') <= 'f' - 'a' ||
@@ -65,6 +70,7 @@ namespace Sass {
 
     bool is_punct(const char& chr)
     {
+      if (!chr) return false;
       // locale independent
       return chr == '.';
     }
@@ -77,6 +83,7 @@ namespace Sass {
     // check if char is outside ascii range
     bool is_unicode(const char& chr)
     {
+      if (!chr) return false;
       // check for unicode range
       return unsigned(chr) > 127;
     }
@@ -85,6 +92,7 @@ namespace Sass {
     // but with specific ranges (copied from Ruby Sass)
     bool is_nonascii(const char& chr)
     {
+      if (!chr) return false;
       unsigned int cmp = unsigned(chr);
       return (
         (cmp >= 128 && cmp <= 15572911) ||
@@ -97,6 +105,7 @@ namespace Sass {
     // valid in a uri (copied from Ruby Sass)
     bool is_uri_character(const char& chr)
     {
+      if (!chr) return false;
       unsigned int cmp = unsigned(chr);
       return (cmp > 41 && cmp < 127) ||
              cmp == ':' || cmp == '/';
@@ -106,6 +115,7 @@ namespace Sass {
     // valid for escaping (copied from Ruby Sass)
     bool is_escapable_character(const char& chr)
     {
+      if (!chr) return false;
       unsigned int cmp = unsigned(chr);
       return cmp > 31 && cmp < 127;
     }
@@ -113,6 +123,7 @@ namespace Sass {
     // Match word character (look ahead)
     bool is_character(const char& chr)
     {
+      if (!chr) return false;
       // valid alpha, numeric or unicode char (plus hyphen)
       return is_alnum(chr) || is_unicode(chr) || chr == '-';
     }
@@ -148,7 +159,7 @@ namespace Sass {
     const char* any_char(const char* src) { return *src ? src + 1 : src; }
 
     // Match word boundary (zero-width lookahead).
-    const char* word_boundary(const char* src) { return is_character(*src) || *src == '#' ? 0 : src; }
+    const char* word_boundary(const char* src) { return (*src && (is_character(*src) || *src == '#')) ? 0 : src; }
 
     // Match linefeed /(?:\n|\r\n?)/
     const char* re_linebreak(const char* src)
diff --git a/src/lexer.hpp b/src/lexer.hpp
index 5838c291c..16627d796 100644
--- a/src/lexer.hpp
+++ b/src/lexer.hpp
@@ -90,7 +90,7 @@ namespace Sass {
     // Regex equivalent: /(?:x)/
     template <char chr>
     const char* exactly(const char* src) {
-      return *src == chr ? src + 1 : 0;
+      return (*src && *src == chr) ? src + 1 : 0;
     }
 
     // Match the full string literal.
@@ -99,10 +99,9 @@ namespace Sass {
     const char* exactly(const char* src) {
       if (str == NULL) return 0;
       const char* pre = str;
-      if (src == NULL) return 0;
       // there is a small chance that the search string
       // is longer than the rest of the string to look at
-      while (*pre && *src == *pre) {
+      while (*src && *pre && *src == *pre) {
         ++src, ++pre;
       }
       // did the matcher finish?
@@ -115,7 +114,7 @@ namespace Sass {
     // only define lower case alpha chars
     template <char chr>
     const char* insensitive(const char* src) {
-      return *src == chr || *src+32 == chr ? src + 1 : 0;
+      return (*src && (*src == chr || *src+32 == chr)) ? src + 1 : 0;
     }
 
     // Match the full string literal.
@@ -128,7 +127,7 @@ namespace Sass {
       if (src == NULL) return 0;
       // there is a small chance that the search string
       // is longer than the rest of the string to look at
-      while (*pre && (*src == *pre || *src+32 == *pre)) {
+      while (*src && *pre && (*src == *pre || *src+32 == *pre)) {
         ++src, ++pre;
       }
       // did the matcher finish?
@@ -139,6 +138,7 @@ namespace Sass {
     // Regex equivalent: /[axy]/
     template <const char* char_class>
     const char* class_char(const char* src) {
+      if (src == NULL) return 0;
       const char* cc = char_class;
       while (*cc && *src != *cc) ++cc;
       return *cc ? src + 1 : 0;
@@ -157,7 +157,7 @@ namespace Sass {
     // Regex equivalent: /[^axy]/
     template <const char* neg_char_class>
     const char* neg_class_char(const char* src) {
-      if (*src == 0) return 0;
+      if (src == NULL) return 0;
       const char* cc = neg_char_class;
       while (*cc && *src != *cc) ++cc;
       return *cc ? 0 : src + 1;
@@ -261,7 +261,7 @@ namespace Sass {
     // Regex equivalent: /(?:$mx)*?(?=$delim)\b/
     template <prelexer mx, prelexer delim>
     const char* non_greedy(const char* src) {
-      while (!delim(src)) {
+      while (*src && !delim(src)) {
         const char* p = mx(src);
         if (p == src) return 0;
         if (p == 0) return 0;

