Bug Summary

File:platform/mac/avmshell/../../../eval/eval-parse-config.cpp
Location:line 154, column 47
Description:Access to field 'pos' results in a dereference of a null pointer (loaded from variable 'expr')

Annotated Source Code

1/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3/* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * The Original Code is [Open Source Virtual Machine.].
17 *
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2010
21 * the Initial Developer. All Rights Reserved.
22 *
23 * Contributor(s):
24 * Adobe AS3 Team
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39
40#include "avmplus.h"
41
42#ifdef VMCFG_EVAL
43
44#include "eval.h"
45
46namespace avmplus
47{
48 namespace RTC
49 {
50 Parser::ConfigBinding::ConfigBinding(Str* ns, Str* name, Expr* value)
51 : ns(ns)
52 , name(name)
53 , value(value)
54 {
55 }
56
57 void Parser::addConfigNamespace(Str* ns)
58 {
59 configNamespaces = ALLOC(Seq<Str*>, (ns, configNamespaces))::new (allocator->alloc(sizeof(Seq<Str*>))) Seq<Str
*> (ns, configNamespaces)
;
60 }
61
62 void Parser::checkNoShadowingOfConfigNamespaces(uint32_t pos, Str* s)
63 {
64 Seq<Str*>* nss = configNamespaces;
65 while (nss != NULL__null) {
66 if (s == nss->hd)
67 compiler->syntaxError(pos, SYNTAXERR_CONFIG_NAMESPACE_SHADOWING);
68 nss = nss->tl;
69 }
70 }
71
72 void Parser::addConfigBinding(Str* ns, Str* name, Expr* value)
73 {
74 configBindings = ALLOC(Seq<ConfigBinding*>, (ALLOC(ConfigBinding, (ns, name, value)), configBindings))::new (allocator->alloc(sizeof(Seq<ConfigBinding*>))
) Seq<ConfigBinding*> (::new (allocator->alloc(sizeof
(ConfigBinding))) ConfigBinding (ns, name, value), configBindings
)
;
75 }
76
77 boolbool Parser::findConfigNamespace(Str* ns)
78 {
79 Seq<Str*>* nss = configNamespaces;
80 while (nss != NULL__null) {
81 if (nss->hd == ns)
82 return truetrue;
83 nss = nss->tl;
84 }
85 return falsefalse;
86 }
87
88 Expr* Parser::findConfigBinding(Str* ns, Str* name)
89 {
90 Seq<ConfigBinding*>* bs = configBindings;
91 while (bs != NULL__null) {
92 if (bs->hd->ns == ns && bs->hd->name == name)
93 return bs->hd->value;
94 bs = bs->tl;
95 }
96 return NULL__null;
97 }
98
99 boolbool Parser::isConfigReference(Expr* e)
100 {
101 if (e->tag() != TAG_qualifiedName)
102 return falsefalse;
103 QualifiedName* qn = (QualifiedName*)e;
104 if (qn->qualifier == NULL__null || qn->qualifier->tag() != TAG_simpleName || qn->name->tag() != TAG_simpleName)
105 return falsefalse;
106 SimpleName* sn = (SimpleName*)(qn->qualifier);
107 return findConfigNamespace(sn->name);
108 }
109
110 boolbool Parser::evaluateConfigReference(QualifiedName* qname)
111 {
112 if (qname == NULL__null)
113 return truetrue;
114
115 AvmAssert(isConfigReference(qname))do { } while (0);
116
117 Str* ns = ((SimpleName*)qname->qualifier)->name;
118 Str* name = ((SimpleName*)qname->name)->name;
119 Expr* value = findConfigBinding(ns, name);
120 if (value != NULL__null)
121 return evaluateToBoolean(value);
122
123 compiler->syntaxError(qname->pos, SYNTAXERR_UNBOUND_CONST_NAME);
124 /*NOTREACHED*/
125 return falsefalse;
126 }
127
128 // POSSIBLE EXTENSION: structured data and field access
129 //
130 // It would be possible to support array, object, xml, and vector initializers
131 // whose initializing subexpressions are either literal values or references
132 // to config variables, as well as field selections on those initializers.
133 // It's possible to imagine some use cases. We need some clean semantics for
134 // when those initializers escape into non-config code - do we want a single
135 // copy or multiple copies?
136
137 Expr* Parser::evaluateConfigDefinition(Str* ns, Expr* e)
138 {
139 // e is evaluated in an environment containing only config bindings.
140 // ns is the default namespace: it will be used to qualify any unqualified name.
141
142 switch (e->tag()) {
1
Control jumps to 'case TAG_simpleName:' at line 151
143 case TAG_literalUndefined:
144 case TAG_literalString:
145 case TAG_literalNull:
146 case TAG_literalUInt:
147 case TAG_literalInt:
148 case TAG_literalDouble:
149 case TAG_literalBoolean:
150 return e;
151 case TAG_simpleName: {
152 Expr* expr = findConfigBinding(ns, ((SimpleName*)e)->name);
153 if (expr == NULL__null)
2
Taking true branch
154 compiler->syntaxError(expr->pos, SYNTAXERR_UNBOUND_CONST_NAME);
3
Access to field 'pos' results in a dereference of a null pointer (loaded from variable 'expr')
155 return expr;
156 }
157 case TAG_qualifiedName: {
158 QualifiedName* qname = (QualifiedName*)e;
159 if (qname->qualifier->tag() != TAG_simpleName || qname->name->tag() != TAG_simpleName)
160 compiler->syntaxError(e->pos, SYNTAXERR_UNBOUND_CONST_NAME); // Specifically an illegal const name
161 Str* ns = ((SimpleName*)qname->qualifier)->name;
162 Str* name = ((SimpleName*)qname->name)->name;
163 Expr* value = findConfigBinding(ns, name);
164 if (value == NULL__null)
165 compiler->syntaxError(e->pos, SYNTAXERR_UNBOUND_CONST_NAME);
166 return value;
167 }
168 case TAG_binaryExpr: {
169 // CLARIFICATION: no short-circuiting
170 //
171 // We evaluate both sides of && and || in order to uncover
172 // any undefined variables lurking in non-taken branches.
173 BinaryExpr* binary = (BinaryExpr*)e;
174 Expr* lhs = evaluateConfigDefinition(ns, binary->lhs);
175 Expr* rhs = evaluateConfigDefinition(ns, binary->rhs);
176 switch (binary->op) {
177 case OPR_plus:
178 if (lhs->tag() == TAG_literalString || rhs->tag() == TAG_literalString) {
179 StringBuilder b(compiler);
180 b.append(((LiteralString*)lhs)->value);
181 b.append(((LiteralString*)rhs)->value);
182 return boxString(b.str());
183 }
184 return boxDouble(evaluateToNumber(lhs) + evaluateToNumber(rhs));
185 case OPR_minus:
186 return boxDouble(evaluateToNumber(lhs) - evaluateToNumber(rhs));
187 case OPR_multiply:
188 return boxDouble(evaluateToNumber(lhs) * evaluateToNumber(rhs));
189 case OPR_divide:
190 return boxDouble(evaluateToNumber(lhs) / evaluateToNumber(rhs));
191 case OPR_remainder:
192 return boxDouble(fmod(evaluateToNumber(lhs), evaluateToNumber(rhs)));
193 case OPR_leftShift:
194 return boxInt(evaluateToInt32(lhs) << (evaluateToUInt32(rhs) & 0x1F));
195 case OPR_rightShift:
196 return boxInt(evaluateToInt32(lhs) >> (evaluateToUInt32(rhs) & 0x1F));
197 case OPR_rightShiftUnsigned:
198 return boxUInt(evaluateToUInt32(lhs) >> (evaluateToUInt32(rhs) & 0x1F));
199 case OPR_bitwiseAnd:
200 return boxInt(evaluateToInt32(lhs) & evaluateToInt32(rhs));
201 case OPR_bitwiseOr:
202 return boxInt(evaluateToInt32(lhs) | evaluateToInt32(rhs));
203 case OPR_bitwiseXor:
204 return boxInt(evaluateToInt32(lhs) ^ evaluateToInt32(rhs));
205 case OPR_logicalAnd:
206 return boxBoolean(int(evaluateToBoolean(lhs)) + int(evaluateToBoolean(rhs)) == 2);
207 case OPR_logicalOr:
208 return boxBoolean(int(evaluateToBoolean(lhs)) + int(evaluateToBoolean(rhs)) != 0);
209 case OPR_less: {
210 int r = evaluateRelational(lhs, rhs);
211 return boxBoolean(r == -1 || r == 0 ? falsefalse : truetrue);
212 }
213 case OPR_greater: {
214 int r = evaluateRelational(rhs, lhs);
215 return boxBoolean(r == -1 || r == 0 ? falsefalse : truetrue);
216 }
217 case OPR_lessOrEqual: {
218 int r = evaluateRelational(rhs, lhs);
219 return boxBoolean(r == -1 || r == 1 ? falsefalse : truetrue);
220 }
221 case OPR_greaterOrEqual: {
222 int r = evaluateRelational(lhs, rhs);
223 return boxBoolean(r == -1 || r == 1 ? falsefalse : truetrue);
224 }
225 case OPR_equal:
226 case OPR_notEqual:
227 case OPR_strictEqual:
228 case OPR_strictNotEqual: {
229 if (lhs->tag() == TAG_literalInt || lhs->tag() == TAG_literalUInt)
230 lhs = boxDouble(evaluateToNumber(lhs));
231 if (rhs->tag() == TAG_literalInt || rhs->tag() == TAG_literalUInt)
232 rhs = boxDouble(evaluateToNumber(rhs));
233
234 boolbool equality;
235 if (binary->op == OPR_equal || binary->op == OPR_notEqual)
236 equality = binary->op == OPR_equal;
237 else
238 equality = binary->op == OPR_strictEqual;
239
240 if (lhs->tag() != rhs->tag()) {
241 if (binary->op == OPR_equal || binary->op == OPR_notEqual) {
242 if ((lhs->tag() == TAG_literalUndefined && rhs->tag() == TAG_literalNull) ||
243 (lhs->tag() == TAG_literalNull && rhs->tag() == TAG_literalUndefined))
244 return boxBoolean(truetrue == equality);
245 if ((lhs->tag() == TAG_literalString && rhs->tag() == TAG_literalDouble) ||
246 (lhs->tag() == TAG_literalDouble && rhs->tag() == TAG_literalString))
247 return boxBoolean((evaluateToNumber(lhs) == evaluateToNumber(rhs)) == equality);
248 if (lhs->tag() == TAG_literalBoolean || rhs->tag() == TAG_literalBoolean)
249 return boxBoolean((evaluateToBoolean(lhs) == evaluateToBoolean(rhs)) == equality);
250 }
251 return boxBoolean(falsefalse == equality);
252 }
253 if (lhs->tag() == TAG_literalUndefined || lhs->tag() == TAG_literalNull)
254 return boxBoolean(truetrue == equality);
255 if (lhs->tag() == TAG_literalDouble)
256 return boxBoolean((evaluateToNumber(lhs) == evaluateToNumber(rhs)) == equality);
257 if (lhs->tag() == TAG_literalBoolean)
258 return boxBoolean((evaluateToBoolean(lhs) == evaluateToBoolean(rhs)) == equality);
259 if (lhs->tag() == TAG_literalString)
260 return boxBoolean((evaluateToString(lhs) == evaluateToString(rhs)) == equality);
261 failNonConstant(lhs);
262 /*NOTREACHED*/
263 break;
264 }
265 default:
266 // "as", "is", "in", ",", "="
267 compiler->syntaxError(position(), SYNTAXERR_ILLEGAL_OP_IN_CONSTEXPR);
268 /*NOTREACHED*/
269 break;
270 }
271 /*NOTREACHED*/
272 break;
273 }
274 case TAG_unaryExpr: {
275 // EXTENSION: typeof
276 //
277 // Supporting "typeof" makes some sort of sense (for example, the
278 // operand of typeof can be a config constant that can take on
279 // various values, and computing the name of the type into the
280 // program can be useful).
281 //
282 // EXTENSION: void
283 //
284 // Supporting "void" probably does not make a lot of sense, but it
285 // seems benign.
286 UnaryExpr* unary = (UnaryExpr*)e;
287 Expr* opd = evaluateConfigDefinition(ns, unary->expr);
288 switch (unary->op) {
289 case OPR_typeof:
290 switch (opd->tag()) {
291 case TAG_literalUndefined: return boxString("undefined");
292 case TAG_literalString: return boxString("string");
293 case TAG_literalNull: return boxString("object");
294 case TAG_literalUInt:
295 case TAG_literalInt:
296 case TAG_literalDouble: return boxString("number");
297 case TAG_literalBoolean: return boxString("boolean");
298 default:
299 failNonConstant(opd);
300 return NULL__null;
301 }
302 case OPR_bitwiseNot: return boxUInt(~evaluateToUInt32(opd));
303 case OPR_unminus: return boxDouble(-evaluateToNumber(opd));
304 case OPR_unplus: return boxDouble(evaluateToNumber(opd));
305 case OPR_not: return boxBoolean(!evaluateToBoolean(opd));
306 case OPR_void: return boxUndefined();
307 default:
308 // "delete", "++", "--"
309 compiler->syntaxError(position(), SYNTAXERR_ILLEGAL_OP_IN_CONSTEXPR);
310 /*NOTREACHED*/
311 break;
312 }
313 /*NOTREACHED*/
314 break;
315 }
316 case TAG_conditionalExpr: {
317 // EXTENSION: conditional operator
318 //
319 // It seems totally sensible to support "... ? ... : ...", though
320 // it's not mentioned in the conditional compilation spec.
321 //
322 // We evaluate both arms in order to uncover references to undefined
323 // configuration variables, same as for && and ||.
324 ConditionalExpr* cond = (ConditionalExpr*)e;
325 Expr* e1 = evaluateConfigDefinition(ns, cond->e1);
326 Expr* e2 = evaluateConfigDefinition(ns, cond->e2);
327 Expr* e3 = evaluateConfigDefinition(ns, cond->e3);
328 return evaluateToBoolean(e1) ? e2 : e3;
329 }
330 default:
331 // Property references, 'new', 'call' - lots of things
332 compiler->syntaxError(position(), SYNTAXERR_ILLEGAL_OP_IN_CONSTEXPR);
333 /*NOTREACHED*/
334 break;
335 }
336 /*NOTREACHED*/
337 return NULL__null;
338 }
339
340 Expr* Parser::boxDouble(double n) { return ALLOC(LiteralDouble, (n, 0))::new (allocator->alloc(sizeof(LiteralDouble))) LiteralDouble
(n, 0)
; }
341 Expr* Parser::boxUInt(uint32_t n) { return ALLOC(LiteralUInt, (n, 0))::new (allocator->alloc(sizeof(LiteralUInt))) LiteralUInt (
n, 0)
; }
342 Expr* Parser::boxInt(int32_t n) { return ALLOC(LiteralInt, (n, 0))::new (allocator->alloc(sizeof(LiteralInt))) LiteralInt (n
, 0)
; }
343 Expr* Parser::boxBoolean(boolbool b) { return ALLOC(LiteralBoolean, (b, 0))::new (allocator->alloc(sizeof(LiteralBoolean))) LiteralBoolean
(b, 0)
; }
344 Expr* Parser::boxString(const char* s) { return ALLOC(LiteralString, (compiler->intern(s), 0))::new (allocator->alloc(sizeof(LiteralString))) LiteralString
(compiler->intern(s), 0)
; }
345 Expr* Parser::boxString(Str* s) { return ALLOC(LiteralString, (s, 0))::new (allocator->alloc(sizeof(LiteralString))) LiteralString
(s, 0)
; }
346 Expr* Parser::boxUndefined() { return ALLOC(LiteralUndefined, (0))::new (allocator->alloc(sizeof(LiteralUndefined))) LiteralUndefined
(0)
; }
347
348 uint32_t Parser::evaluateToUInt32(Expr* e)
349 {
350 if (e->tag() == TAG_literalUInt)
351 return ((LiteralUInt*)e)->value;
352 double d = evaluateToNumber(e);
353 if (d == 0 || MathUtils::isNaN(d) || MathUtils::isInfinite(d))
354 return 0;
355 d = (d < 0 ? -1 : 1) * floor(fabs(d));
356 d = fmod(d, 4294967296.0);
357 return uint32_t(d);
358 }
359
360 int32_t Parser::evaluateToInt32(Expr* e)
361 {
362 if (e->tag() == TAG_literalInt)
363 return ((LiteralInt*)e)->value;
364 double d = evaluateToNumber(e);
365 if (d == 0 || MathUtils::isNaN(d) || MathUtils::isInfinite(d))
366 return 0;
367 d = (d < 0 ? -1 : 1) * floor(fabs(d));
368 d = fmod(d, 4294967296.0);
369 if (d >= 2147483648.0)
370 return int32_t(d - 4294967296.0);
371 else
372 return int32_t(d);
373 }
374
375 double Parser::evaluateToNumber(Expr* e)
376 {
377 switch (e->tag()) {
378 case TAG_literalUndefined: return MathUtils::kNaN;
379 case TAG_literalNull: return 0.0;
380 case TAG_literalBoolean: return ((LiteralBoolean*)e)->value ? 1.0 : 0.0;
381 case TAG_literalDouble: return ((LiteralDouble*)e)->value;
382 case TAG_literalInt: return (double)(((LiteralInt*)e)->value);
383 case TAG_literalUInt: return (double)(((LiteralUInt*)e)->value);
384 case TAG_literalString: return strToDouble(((LiteralString*)e)->value);
385 default:
386 failNonConstant(e);
387 return 0;
388 }
389 }
390
391 boolbool Parser::evaluateToBoolean(Expr* e)
392 {
393 switch (e->tag()) {
394 case TAG_literalUndefined: return falsefalse;
395 case TAG_literalNull: return falsefalse;
396 case TAG_literalBoolean: return ((LiteralBoolean*)e)->value;
397 case TAG_literalDouble: { double v = ((LiteralDouble*)e)->value; return !MathUtils::isNaN(v) && v != 0.0; }
398 case TAG_literalInt: return ((LiteralInt*)e)->value != 0;
399 case TAG_literalUInt: return ((LiteralUInt*)e)->value != 0;
400 case TAG_literalString: return ((LiteralString*)e)->value->length > 0;
401 default:
402 failNonConstant(e);
403 return 0;
404 }
405 }
406
407 Str* Parser::evaluateToString(Expr* e)
408 {
409 switch (e->tag()) {
410 case TAG_literalUndefined: return compiler->intern("undefined");
411 case TAG_literalNull: return compiler->intern("null");
412 case TAG_literalBoolean: return ((LiteralBoolean*)e)->value ? compiler->intern("true") : compiler->intern("false");
413 case TAG_literalDouble: return doubleToStr(((LiteralDouble*)e)->value);
414 case TAG_literalInt: return doubleToStr(((LiteralInt*)e)->value);
415 case TAG_literalUInt: return doubleToStr(((LiteralUInt*)e)->value);
416 case TAG_literalString: return ((LiteralString*)e)->value;
417 default:
418 failNonConstant(e);
419 return 0;
420 }
421 }
422
423 // Returns -1 for undefined, 0 for false, 1 for true. Generally true means "x < y",
424 // false means "!(x < y)" and undefined means x and y are not comparable.
425
426 int Parser::evaluateRelational(Expr* lhs, Expr* rhs)
427 {
428 if (lhs->tag() == TAG_literalString && rhs->tag() == TAG_literalString)
429 return (((LiteralString*)lhs)->value)->compareTo(((LiteralString*)rhs)->value) < 0 ? 1 : 0;
430
431 double l = evaluateToNumber(lhs);
432 double r = evaluateToNumber(rhs);
433 if (MathUtils::isNaN(l) || MathUtils::isNaN(r))
434 return -1;
435 return l < r ? 1 : 0;
436 }
437
438 void Parser::failNonConstant(Expr* e)
439 {
440 compiler->internalError(position(), "Non-constant value in expression evaluation, tag=%d", int(e->tag()));
441 }
442 }
443}
444
445#endif // VMCFG_EVAL