tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WebGLValidateStrings.cpp (4848B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "WebGLValidateStrings.h"
      7 
      8 #include <regex>
      9 
     10 #include "WebGLTypes.h"
     11 #include "nsPrintfCString.h"
     12 
     13 namespace mozilla {
     14 
     15 /* GLSL ES 3.00 p17:
     16  - Comments are delimited by / * and * /, or by // and a newline.
     17 
     18  - '//' style comments include the initial '//' marker and continue up to, but
     19 not including, the terminating newline.
     20 
     21  - '/ * ... * /' comments include both the start and end marker.
     22 
     23  - The begin comment delimiters (/ * or //) are not recognized as comment
     24 delimiters inside of a comment, hence comments cannot be nested.
     25 
     26  - Comments are treated syntactically as a single space.
     27 */
     28 
     29 std::string CommentsToSpaces(const std::string& src) {
     30  constexpr auto flags =
     31      std::regex::ECMAScript | std::regex::nosubs | std::regex::optimize;
     32 
     33  static const auto RE_COMMENT_BEGIN = std::regex("/[*/]", flags);
     34  static const auto RE_LINE_COMMENT_END = std::regex(R"([^\\]\n)", flags);
     35  static const auto RE_BLOCK_COMMENT_END = std::regex(R"(\*/)", flags);
     36 
     37  std::string ret;
     38  ret.reserve(src.size());
     39 
     40  // Replace all comments with block comments with the right number of newlines.
     41  // Line positions may be off, but line numbers will be accurate, which is more
     42  // important.
     43 
     44  auto itr = src.begin();
     45  const auto end = src.end();
     46  std::smatch match;
     47  while (std::regex_search(itr, end, match, RE_COMMENT_BEGIN)) {
     48    MOZ_ASSERT(match.length() == 2);
     49    const auto commentBegin = itr + match.position();
     50    ret.append(itr, commentBegin);
     51 
     52    itr = commentBegin + match.length();
     53 
     54    const bool isBlockComment = (*(commentBegin + 1) == '*');
     55    const auto* endRegex = &RE_LINE_COMMENT_END;
     56    if (isBlockComment) {
     57      endRegex = &RE_BLOCK_COMMENT_END;
     58    }
     59 
     60    if (isBlockComment) {
     61      ret += "/*";
     62    }
     63 
     64    auto commentEnd = end;
     65    if (!isBlockComment && itr != end && *itr == '\n') {
     66      commentEnd = itr + 1;  // '//\n'
     67    } else if (std::regex_search(itr, end, match, *endRegex)) {
     68      commentEnd = itr + match.position() + match.length();
     69    } else {
     70      return ret;
     71    }
     72 
     73    for (; itr != commentEnd; ++itr) {
     74      const auto cur = *itr;
     75      if (cur == '\n') {
     76        ret += cur;
     77      }
     78    }
     79    if (isBlockComment) {
     80      ret += "*/";
     81    }
     82  }
     83 
     84  ret.append(itr, end);
     85  return ret;
     86 }
     87 
     88 ////////////////////////////////////////////////////////////////////////////////
     89 
     90 static constexpr bool IsValidGLSLChar(const char c) {
     91  if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
     92      ('0' <= c && c <= '9')) {
     93    return true;
     94  }
     95 
     96  switch (c) {
     97    case ' ':
     98    case '\t':
     99    case '\v':
    100    case '\f':
    101    case '\r':
    102    case '\n':
    103    case '_':
    104    case '.':
    105    case '+':
    106    case '-':
    107    case '/':
    108    case '*':
    109    case '%':
    110    case '<':
    111    case '>':
    112    case '[':
    113    case ']':
    114    case '(':
    115    case ')':
    116    case '{':
    117    case '}':
    118    case '^':
    119    case '|':
    120    case '&':
    121    case '~':
    122    case '=':
    123    case '!':
    124    case ':':
    125    case ';':
    126    case ',':
    127    case '?':
    128      return true;
    129 
    130    default:
    131      return false;
    132  }
    133 }
    134 
    135 static constexpr bool IsValidForPreprocOrGlsl(const char c) {
    136  switch (c) {
    137    case '#':
    138    case '\\':
    139      return true;
    140 
    141    default:
    142      return IsValidGLSLChar(c);
    143  }
    144 }
    145 
    146 ////
    147 
    148 static constexpr char INVALID_GLSL_CHAR = '$';
    149 
    150 std::string CrushGlslToAscii(const std::string& u8) {
    151  static_assert(!IsValidForPreprocOrGlsl(INVALID_GLSL_CHAR));
    152  auto ascii = u8;
    153  for (auto& c : ascii) {
    154    if (MOZ_UNLIKELY(!IsValidForPreprocOrGlsl(c))) {
    155      c = INVALID_GLSL_CHAR;
    156    }
    157  }
    158  return ascii;
    159 }
    160 
    161 Maybe<webgl::ErrorInfo> CheckGLSLVariableName(const bool webgl2,
    162                                              const std::string& name) {
    163  if (name.empty()) return {};
    164 
    165  const uint32_t maxSize = webgl2 ? 1024 : 256;
    166  if (name.size() > maxSize) {
    167    const auto info = nsPrintfCString(
    168        "Identifier is %zu characters long, exceeds the"
    169        " maximum allowed length of %u characters.",
    170        name.size(), maxSize);
    171    return Some(webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE, info.BeginReading()});
    172  }
    173 
    174  for (const auto cur : name) {
    175    if (!IsValidGLSLChar(cur)) {
    176      const auto info =
    177          nsPrintfCString("String contains the illegal character 0x%x'.", cur);
    178      return Some(
    179          webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE, info.BeginReading()});
    180    }
    181  }
    182 
    183  if (name.find("webgl_") == 0 || name.find("_webgl_") == 0) {
    184    return Some(webgl::ErrorInfo{
    185        LOCAL_GL_INVALID_OPERATION,
    186        "String matches reserved GLSL prefix pattern /_?webgl_/."});
    187  }
    188 
    189  return {};
    190 }
    191 
    192 }  // namespace mozilla