Fix identifier handling in strings

Give identifiers a full 32bit range, so we don't accidentally
get into overflows. Make sure UINT_MAX can be used as an identifier.

Change-Id: I7d031f9eff0ea2edd7d3e182670fbd37aaf04040
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
This commit is contained in:
Lars Knoll 2013-02-12 11:05:18 +01:00 committed by Simon Hausmann
parent b5333bdcf1
commit 8c10aeb9fa
5 changed files with 32 additions and 40 deletions

View File

@ -70,9 +70,8 @@ public:
if (str->subtype == String::StringType_ArrayIndex) if (str->subtype == String::StringType_ArrayIndex)
return str; return str;
str->stringIdentifier = currentIndex; str->identifier = currentIndex;
if (currentIndex <= USHRT_MAX) { if (currentIndex <= USHRT_MAX) {
str->subtype = String::StringType_Identifier;
identifiers.insert(s, str); identifiers.insert(s, str);
++currentIndex; ++currentIndex;
} }
@ -80,21 +79,19 @@ public:
} }
void toIdentifier(String *s) { void toIdentifier(String *s) {
if (s->subtype >= String::StringType_Identifier) if (s->identifier != UINT_MAX)
return; return;
if (s->subtype == String::StringType_Unknown) if (s->subtype == String::StringType_Unknown)
s->createHashValue(); s->createHashValue();
if (s->subtype >= String::StringType_Identifier) if (s->subtype == String::StringType_ArrayIndex)
return; return;
QHash<QString, String*>::const_iterator it = identifiers.find(s->toQString()); QHash<QString, String*>::const_iterator it = identifiers.find(s->toQString());
if (it != identifiers.constEnd()) { if (it != identifiers.constEnd()) {
s->subtype = String::StringType_Identifier; s->identifier = (*it)->identifier;
s->stringIdentifier = (*it)->stringIdentifier;
return; return;
} }
s->stringIdentifier = currentIndex; s->identifier = currentIndex;
if (currentIndex <= USHRT_MAX) { if (currentIndex <= USHRT_MAX) {
s->subtype = String::StringType_Identifier;
identifiers.insert(s->toQString(), s); identifiers.insert(s->toQString(), s);
++currentIndex; ++currentIndex;
} }

View File

@ -60,7 +60,7 @@ InternalClass::InternalClass(const QQmlJS::VM::InternalClass &other)
uint InternalClass::getOrAddMember(Object *object, String *string) uint InternalClass::getOrAddMember(Object *object, String *string)
{ {
engine->identifierCache->toIdentifier(string); engine->identifierCache->toIdentifier(string);
uint id = string->stringIdentifier; uint id = string->identifier;
QHash<uint, uint>::const_iterator it = propertyTable.constFind(id); QHash<uint, uint>::const_iterator it = propertyTable.constFind(id);
if (it != propertyTable.constEnd()) if (it != propertyTable.constEnd())
@ -115,7 +115,7 @@ void InternalClass::removeMember(Object *object, uint id)
uint InternalClass::find(String *string) uint InternalClass::find(String *string)
{ {
engine->identifierCache->toIdentifier(string); engine->identifierCache->toIdentifier(string);
uint id = string->stringIdentifier; uint id = string->identifier;
QHash<uint, uint>::const_iterator it = propertyTable.constFind(id); QHash<uint, uint>::const_iterator it = propertyTable.constFind(id);
if (it != propertyTable.constEnd()) if (it != propertyTable.constEnd())

View File

@ -69,7 +69,7 @@ Object::Object(ExecutionEngine *engine)
: prototype(0) : prototype(0)
, internalClass(engine->emptyClass) , internalClass(engine->emptyClass)
, memberDataAlloc(0), memberData(0) , memberDataAlloc(0), memberData(0)
, arrayOffset(0), arrayDataLen(0), arrayAlloc(0), sparseArray(0) , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayData(0), sparseArray(0)
{ {
type = Type_Object; type = Type_Object;
} }
@ -221,7 +221,7 @@ PropertyDescriptor *Object::insertMember(String *s)
PropertyDescriptor *Object::__getOwnProperty__(ExecutionContext *ctx, String *name) PropertyDescriptor *Object::__getOwnProperty__(ExecutionContext *ctx, String *name)
{ {
uint idx = name->asArrayIndex(); uint idx = name->asArrayIndex();
if (idx != String::InvalidArrayIndex) if (idx != UINT_MAX)
return __getOwnProperty__(ctx, idx); return __getOwnProperty__(ctx, idx);
uint member = internalClass->find(name); uint member = internalClass->find(name);
@ -246,7 +246,7 @@ PropertyDescriptor *Object::__getOwnProperty__(ExecutionContext *ctx, uint index
PropertyDescriptor *Object::__getPropertyDescriptor__(ExecutionContext *ctx, String *name) PropertyDescriptor *Object::__getPropertyDescriptor__(ExecutionContext *ctx, String *name)
{ {
uint idx = name->asArrayIndex(); uint idx = name->asArrayIndex();
if (idx != String::InvalidArrayIndex) if (idx != UINT_MAX)
return __getPropertyDescriptor__(ctx, idx); return __getPropertyDescriptor__(ctx, idx);
@ -282,7 +282,7 @@ PropertyDescriptor *Object::__getPropertyDescriptor__(ExecutionContext *ctx, uin
Value Object::__get__(ExecutionContext *ctx, String *name, bool *hasProperty) Value Object::__get__(ExecutionContext *ctx, String *name, bool *hasProperty)
{ {
uint idx = name->asArrayIndex(); uint idx = name->asArrayIndex();
if (idx != String::InvalidArrayIndex) if (idx != UINT_MAX)
return __get__(ctx, idx, hasProperty); return __get__(ctx, idx, hasProperty);
name->makeIdentifier(ctx); name->makeIdentifier(ctx);
@ -346,7 +346,7 @@ Value Object::__get__(ExecutionContext *ctx, uint index, bool *hasProperty)
void Object::__put__(ExecutionContext *ctx, String *name, Value value) void Object::__put__(ExecutionContext *ctx, String *name, Value value)
{ {
uint idx = name->asArrayIndex(); uint idx = name->asArrayIndex();
if (idx != String::InvalidArrayIndex) if (idx != UINT_MAX)
return __put__(ctx, idx, value); return __put__(ctx, idx, value);
name->makeIdentifier(ctx); name->makeIdentifier(ctx);
@ -486,7 +486,7 @@ void Object::__put__(ExecutionContext *ctx, uint index, Value value)
bool Object::__hasProperty__(const ExecutionContext *ctx, String *name) const bool Object::__hasProperty__(const ExecutionContext *ctx, String *name) const
{ {
uint idx = name->asArrayIndex(); uint idx = name->asArrayIndex();
if (idx != String::InvalidArrayIndex) if (idx != UINT_MAX)
return __hasProperty__(ctx, idx); return __hasProperty__(ctx, idx);
name->makeIdentifier(ctx); name->makeIdentifier(ctx);
@ -510,7 +510,7 @@ bool Object::__hasProperty__(const ExecutionContext *ctx, uint index) const
bool Object::__delete__(ExecutionContext *ctx, String *name) bool Object::__delete__(ExecutionContext *ctx, String *name)
{ {
uint idx = name->asArrayIndex(); uint idx = name->asArrayIndex();
if (idx != String::InvalidArrayIndex) if (idx != UINT_MAX)
return __delete__(ctx, idx); return __delete__(ctx, idx);
name->makeIdentifier(ctx); name->makeIdentifier(ctx);
@ -519,7 +519,7 @@ bool Object::__delete__(ExecutionContext *ctx, String *name)
if (memberIdx != UINT_MAX) { if (memberIdx != UINT_MAX) {
PropertyDescriptor &pd = memberData[memberIdx]; PropertyDescriptor &pd = memberData[memberIdx];
if (pd.isConfigurable()) { if (pd.isConfigurable()) {
internalClass->removeMember(this, name->stringIdentifier); internalClass->removeMember(this, name->identifier);
memmove(memberData + memberIdx, memberData + memberIdx + 1, (internalClass->size - memberIdx)*sizeof(PropertyDescriptor)); memmove(memberData + memberIdx, memberData + memberIdx + 1, (internalClass->size - memberIdx)*sizeof(PropertyDescriptor));
return true; return true;
} }
@ -565,7 +565,7 @@ bool Object::__delete__(ExecutionContext *ctx, uint index)
bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const PropertyDescriptor *desc) bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const PropertyDescriptor *desc)
{ {
uint idx = name->asArrayIndex(); uint idx = name->asArrayIndex();
if (idx != String::InvalidArrayIndex) if (idx != UINT_MAX)
return __defineOwnProperty__(ctx, idx, desc); return __defineOwnProperty__(ctx, idx, desc);
name->makeIdentifier(ctx); name->makeIdentifier(ctx);

View File

@ -52,20 +52,20 @@ static uint toArrayIndex(const QChar *ch, const QChar *end, bool *ok)
*ok = false; *ok = false;
uint i = ch->unicode() - '0'; uint i = ch->unicode() - '0';
if (i > 9) if (i > 9)
return String::InvalidArrayIndex; return UINT_MAX;
++ch; ++ch;
// reject "01", "001", ... // reject "01", "001", ...
if (i == 0 && ch != end) if (i == 0 && ch != end)
return String::InvalidArrayIndex; return UINT_MAX;
while (ch < end) { while (ch < end) {
uint x = ch->unicode() - '0'; uint x = ch->unicode() - '0';
if (x > 9) if (x > 9)
return String::InvalidArrayIndex; return UINT_MAX;
uint n = i*10 + x; uint n = i*10 + x;
if (n < i) if (n < i)
// overflow // overflow
return String::InvalidArrayIndex; return UINT_MAX;
i = n; i = n;
++ch; ++ch;
} }
@ -79,9 +79,10 @@ uint String::toUInt(bool *ok) const
if (subtype == StringType_Unknown) if (subtype == StringType_Unknown)
createHashValue(); createHashValue();
if (subtype == StringType_ArrayIndex) if (subtype >= StringType_UInt)
return stringHash; return stringHash;
// ### this conversion shouldn't be required
double d = __qmljs_string_to_number(this); double d = __qmljs_string_to_number(this);
uint l = (uint)d; uint l = (uint)d;
if (d == l) if (d == l)
@ -104,7 +105,7 @@ void String::createHashValue() const
bool ok; bool ok;
stringHash = toArrayIndex(ch, end, &ok); stringHash = toArrayIndex(ch, end, &ok);
if (ok) { if (ok) {
subtype = StringType_ArrayIndex; subtype = (stringHash == UINT_MAX) ? StringType_UInt : StringType_ArrayIndex;
return; return;
} }

View File

@ -55,12 +55,12 @@ struct String : public Managed {
enum StringType { enum StringType {
StringType_Unknown, StringType_Unknown,
StringType_Regular, StringType_Regular,
StringType_Identifier, StringType_UInt,
StringType_ArrayIndex StringType_ArrayIndex
}; };
String(const QString &text) String(const QString &text)
: _text(text), stringHash(InvalidHashValue) : _text(text), stringHash(UINT_MAX), identifier(UINT_MAX)
{ type = Type_String; subtype = StringType_Unknown; } { type = Type_String; subtype = StringType_Unknown; }
inline bool isEqualTo(const String *other) const { inline bool isEqualTo(const String *other) const {
@ -68,12 +68,11 @@ struct String : public Managed {
return true; return true;
if (hashValue() != other->hashValue()) if (hashValue() != other->hashValue())
return false; return false;
if (subtype == other->subtype) { if (identifier != UINT_MAX && identifier == other->identifier)
if (subtype == StringType_ArrayIndex) return true;
return true; if (subtype >= StringType_UInt && subtype == other->subtype)
if (subtype == StringType_Identifier) return true;
return stringIdentifier == other->stringIdentifier;
}
return toQString() == other->toQString(); return toQString() == other->toQString();
} }
@ -87,10 +86,6 @@ struct String : public Managed {
return stringHash; return stringHash;
} }
enum {
InvalidArrayIndex = 0xffffffff,
InvalidHashValue = 0xffffffff
};
uint asArrayIndex() const { uint asArrayIndex() const {
if (subtype == StringType_Unknown) if (subtype == StringType_Unknown)
createHashValue(); createHashValue();
@ -101,19 +96,18 @@ struct String : public Managed {
uint toUInt(bool *ok) const; uint toUInt(bool *ok) const;
void makeIdentifier(const ExecutionContext *ctx) { void makeIdentifier(const ExecutionContext *ctx) {
if (subtype == StringType_Identifier) if (identifier != UINT_MAX)
return; return;
makeIdentifierImpl(ctx); makeIdentifierImpl(ctx);
} }
void makeIdentifierImpl(const ExecutionContext *ctx); void makeIdentifierImpl(const ExecutionContext *ctx);
private:
friend struct Identifiers;
void createHashValue() const; void createHashValue() const;
QString _text; QString _text;
mutable uint stringHash; mutable uint stringHash;
mutable uint identifier;
}; };
} // namespace VM } // namespace VM