Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/canvas/WebGLValidateStrings.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "WebGLContext.h"
9
10
namespace mozilla {
11
12
bool
13
TruncateComments(const nsAString& src, nsAString* const out)
14
0
{
15
0
    const size_t dstByteCount = src.Length() * sizeof(src[0]);
16
0
    const UniqueBuffer dst(malloc(dstByteCount));
17
0
    if (!dst)
18
0
        return false;
19
0
20
0
    auto srcItr = src.BeginReading();
21
0
    const auto srcEnd = src.EndReading();
22
0
    const auto dstBegin = (decltype(src[0])*)dst.get();
23
0
    auto dstItr = dstBegin;
24
0
25
0
    const auto fnEmitUntil = [&](const decltype(srcItr)& nextSrcItr) {
26
0
        while (srcItr != nextSrcItr) {
27
0
            *dstItr = *srcItr;
28
0
            ++srcItr;
29
0
            ++dstItr;
30
0
        }
31
0
    };
32
0
33
0
    const auto fnFindSoonestOf = [&](const nsString* needles, size_t needleCount,
34
0
                                     size_t* const out_foundId)
35
0
    {
36
0
        auto foundItr = srcItr;
37
0
        while (foundItr != srcEnd) {
38
0
            const auto haystack = Substring(foundItr, srcEnd);
39
0
            for (size_t i = 0; i < needleCount; i++) {
40
0
                if (StringBeginsWith(haystack, needles[i])) {
41
0
                    *out_foundId = i;
42
0
                    return foundItr;
43
0
                }
44
0
            }
45
0
            ++foundItr;
46
0
        }
47
0
        *out_foundId = needleCount;
48
0
        return foundItr;
49
0
    };
50
0
51
0
    ////
52
0
53
0
    const nsString commentBeginnings[] = { NS_LITERAL_STRING("//"),
54
0
                                           NS_LITERAL_STRING("/*"),
55
0
                                           nsString() }; // Final empty string for "found
56
0
                                                         // nothing".
57
0
    const nsString lineCommentEndings[] = { NS_LITERAL_STRING("\\\n"),
58
0
                                            NS_LITERAL_STRING("\n"),
59
0
                                            nsString() };
60
0
    const nsString blockCommentEndings[] = { NS_LITERAL_STRING("\n"),
61
0
                                             NS_LITERAL_STRING("*/"),
62
0
                                             nsString() };
63
0
64
0
    while (srcItr != srcEnd) {
65
0
        size_t foundId;
66
0
        fnEmitUntil( fnFindSoonestOf(commentBeginnings, 2, &foundId) );
67
0
        fnEmitUntil(srcItr + commentBeginnings[foundId].Length()); // Final empty string
68
0
                                                                   // allows us to skip
69
0
                                                                   // forward here
70
0
                                                                   // unconditionally.
71
0
        switch (foundId) {
72
0
        case 0: // line comment
73
0
            while (true) {
74
0
                size_t endId;
75
0
                srcItr = fnFindSoonestOf(lineCommentEndings, 2, &endId);
76
0
                fnEmitUntil(srcItr + lineCommentEndings[endId].Length());
77
0
                if (endId == 0)
78
0
                    continue;
79
0
                break;
80
0
            }
81
0
            break;
82
0
83
0
        case 1: // block comment
84
0
            while (true) {
85
0
                size_t endId;
86
0
                srcItr = fnFindSoonestOf(blockCommentEndings, 2, &endId);
87
0
                fnEmitUntil(srcItr + blockCommentEndings[endId].Length());
88
0
                if (endId == 0)
89
0
                    continue;
90
0
                break;
91
0
            }
92
0
            break;
93
0
94
0
        default: // not found
95
0
            break;
96
0
        }
97
0
    }
98
0
99
0
    MOZ_ASSERT((dstBegin+1) - dstBegin == 1);
100
0
    const uint32_t dstCharLen = dstItr - dstBegin;
101
0
    if (!out->Assign(dstBegin, dstCharLen, mozilla::fallible))
102
0
        return false;
103
0
104
0
    return true;
105
0
}
106
107
////////////////////////////////////////////////////////////////////////////////
108
109
static bool
110
IsValidGLSLChar(char16_t c)
111
0
{
112
0
    if (('a' <= c && c <= 'z') ||
113
0
        ('A' <= c && c <= 'Z') ||
114
0
        ('0' <= c && c <= '9'))
115
0
    {
116
0
        return true;
117
0
    }
118
0
119
0
    switch (c) {
120
0
    case ' ':
121
0
    case '\t':
122
0
    case '\v':
123
0
    case '\f':
124
0
    case '\r':
125
0
    case '\n':
126
0
    case '_':
127
0
    case '.':
128
0
    case '+':
129
0
    case '-':
130
0
    case '/':
131
0
    case '*':
132
0
    case '%':
133
0
    case '<':
134
0
    case '>':
135
0
    case '[':
136
0
    case ']':
137
0
    case '(':
138
0
    case ')':
139
0
    case '{':
140
0
    case '}':
141
0
    case '^':
142
0
    case '|':
143
0
    case '&':
144
0
    case '~':
145
0
    case '=':
146
0
    case '!':
147
0
    case ':':
148
0
    case ';':
149
0
    case ',':
150
0
    case '?':
151
0
        return true;
152
0
153
0
    default:
154
0
        return false;
155
0
    }
156
0
}
157
158
static bool
159
IsValidGLSLPreprocChar(char16_t c)
160
0
{
161
0
    if (IsValidGLSLChar(c))
162
0
        return true;
163
0
164
0
    switch (c) {
165
0
    case '\\':
166
0
    case '#':
167
0
        return true;
168
0
169
0
    default:
170
0
        return false;
171
0
    }
172
0
}
173
174
////
175
176
bool
177
ValidateGLSLPreprocString(WebGLContext* webgl, const nsAString& string)
178
0
{
179
0
    for (size_t i = 0; i < string.Length(); ++i) {
180
0
        const auto& cur = string[i];
181
0
182
0
        if (!IsValidGLSLPreprocChar(cur)) {
183
0
            webgl->ErrorInvalidValue("String contains the illegal character 0x%x.", cur);
184
0
            return false;
185
0
        }
186
0
187
0
        if (cur == '\\' && !webgl->IsWebGL2()) {
188
0
            // Todo: Backslash is technically still invalid in WebGLSL 1 under even under
189
0
            // WebGL 2.
190
0
            webgl->ErrorInvalidValue("Backslash is not valid in WebGL 1.");
191
0
            return false;
192
0
        }
193
0
    }
194
0
195
0
    return true;
196
0
}
197
198
bool
199
ValidateGLSLVariableName(const nsAString& name, WebGLContext* webgl)
200
0
{
201
0
    if (name.IsEmpty())
202
0
        return false;
203
0
204
0
    const uint32_t maxSize = webgl->IsWebGL2() ? 1024 : 256;
205
0
    if (name.Length() > maxSize) {
206
0
        webgl->ErrorInvalidValue("Identifier is %u characters long, exceeds the"
207
0
                                 " maximum allowed length of %u characters.",
208
0
                                 name.Length(), maxSize);
209
0
        return false;
210
0
    }
211
0
212
0
    for (size_t i = 0; i < name.Length(); ++i) {
213
0
        const auto& cur = name[i];
214
0
        if (!IsValidGLSLChar(cur)) {
215
0
           webgl->ErrorInvalidValue("String contains the illegal character 0x%x'.", cur);
216
0
           return false;
217
0
        }
218
0
    }
219
0
220
0
    nsString prefix1 = NS_LITERAL_STRING("webgl_");
221
0
    nsString prefix2 = NS_LITERAL_STRING("_webgl_");
222
0
223
0
    if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
224
0
        Substring(name, 0, prefix2.Length()).Equals(prefix2))
225
0
    {
226
0
        webgl->ErrorInvalidOperation("String contains a reserved GLSL prefix.");
227
0
        return false;
228
0
    }
229
0
230
0
    return true;
231
0
}
232
233
} // namespace mozilla