Bug 56041 - RexExp constructor should only accept flags "gim"
We also should be passing the flags around as a bitfield rather than a string,
and should not have redundant, incompatible code for converting the string to a bitfield!
Reviewed by Darin Adler.
Source/JavaScriptCore:
* JavaScriptCore.exp:
* bytecompiler/NodesCodegen.cpp:
(JSC::RegExpNode::emitBytecode):
- Need to parse flags string to enum.
* runtime/RegExp.cpp:
(JSC::regExpFlags):
(JSC::RegExp::RegExp):
(JSC::RegExp::create):
- Add method to parse flags string to enum, change constructor/create args to take enum.
* runtime/RegExp.h:
(JSC::RegExp::global):
(JSC::RegExp::ignoreCase):
(JSC::RegExp::multiline):
- Change to use new enum values.
* runtime/RegExpCache.cpp:
(JSC::RegExpCache::lookupOrCreate):
(JSC::RegExpCache::create):
* runtime/RegExpCache.h:
- Changed to use regExpFlags enum instead of int/const UString&.
* runtime/RegExpConstructor.cpp:
(JSC::constructRegExp):
- Add use new enum parsing, check for error.
* runtime/RegExpKey.h:
(JSC::RegExpKey::RegExpKey):
* runtime/RegExpPrototype.cpp:
(JSC::RegExpPrototype::RegExpPrototype):
- Pass NoFlags value instead of empty string.
(JSC::regExpProtoFuncCompile):
- Add use new enum parsing, check for error.
* runtime/StringPrototype.cpp:
(JSC::stringProtoFuncMatch):
(JSC::stringProtoFuncSearch):
- Pass NoFlags value instead of empty string.
Source/WebCore:
* bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneDeserializer::readTerminal):
- Need to parse flags string back to enum.
LayoutTests:
* sputnik/Conformance/15_Native_Objects/15.10_RegExp/15.10.4/S15.10.4.1_A5_T1-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.10_RegExp/15.10.4/S15.10.4.1_A5_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.10_RegExp/15.10.4/S15.10.4.1_A5_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.10_RegExp/15.10.4/S15.10.4.1_A5_T4-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.10_RegExp/15.10.4/S15.10.4.1_A5_T5-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.10_RegExp/15.10.4/S15.10.4.1_A5_T6-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.10_RegExp/15.10.4/S15.10.4.1_A5_T7-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.10_RegExp/15.10.4/S15.10.4.1_A5_T8-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.10_RegExp/15.10.4/S15.10.4.1_A5_T9-expected.txt:
- Check in passing results!
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@80667 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index f46a1c5..3b92e14 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,45 @@
+2011-03-09 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 56041 - RexExp constructor should only accept flags "gim"
+ We also should be passing the flags around as a bitfield rather than a string,
+ and should not have redundant, incompatible code for converting the string to a bitfield!
+
+ * JavaScriptCore.exp:
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::RegExpNode::emitBytecode):
+ - Need to parse flags string to enum.
+ * runtime/RegExp.cpp:
+ (JSC::regExpFlags):
+ (JSC::RegExp::RegExp):
+ (JSC::RegExp::create):
+ - Add method to parse flags string to enum, change constructor/create args to take enum.
+ * runtime/RegExp.h:
+ (JSC::RegExp::global):
+ (JSC::RegExp::ignoreCase):
+ (JSC::RegExp::multiline):
+ - Change to use new enum values.
+ * runtime/RegExpCache.cpp:
+ (JSC::RegExpCache::lookupOrCreate):
+ (JSC::RegExpCache::create):
+ * runtime/RegExpCache.h:
+ - Changed to use regExpFlags enum instead of int/const UString&.
+ * runtime/RegExpConstructor.cpp:
+ (JSC::constructRegExp):
+ - Add use new enum parsing, check for error.
+ * runtime/RegExpKey.h:
+ (JSC::RegExpKey::RegExpKey):
+ * runtime/RegExpPrototype.cpp:
+ (JSC::RegExpPrototype::RegExpPrototype):
+ - Pass NoFlags value instead of empty string.
+ (JSC::regExpProtoFuncCompile):
+ - Add use new enum parsing, check for error.
+ * runtime/StringPrototype.cpp:
+ (JSC::stringProtoFuncMatch):
+ (JSC::stringProtoFuncSearch):
+ - Pass NoFlags value instead of empty string.
+
2011-03-08 Gavin Barraclough <barraclough@apple.com>
Reviewed by Sam Weinig
diff --git a/Source/JavaScriptCore/JavaScriptCore.exp b/Source/JavaScriptCore/JavaScriptCore.exp
index 914c2ac..060f6612 100644
--- a/Source/JavaScriptCore/JavaScriptCore.exp
+++ b/Source/JavaScriptCore/JavaScriptCore.exp
@@ -1,4 +1,3 @@
-__ZN3JSC22objectConstructorTableE
_JSCheckScriptSyntax
_JSClassCreate
_JSClassRelease
@@ -120,6 +119,7 @@
__ZN3JSC11ParserArena5resetEv
__ZN3JSC11checkSyntaxEPNS_9ExecStateERKNS_10SourceCodeE
__ZN3JSC11createErrorEPNS_9ExecStateERKNS_7UStringE
+__ZN3JSC11regExpFlagsERKNS_7UStringE
__ZN3JSC12DateInstance6s_infoE
__ZN3JSC12DateInstanceC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEd
__ZN3JSC12DateInstanceC1EPNS_9ExecStateEd
@@ -201,6 +201,7 @@
__ZN3JSC20MarkedArgumentBuffer10slowAppendENS_7JSValueE
__ZN3JSC20createReferenceErrorEPNS_9ExecStateERKNS_7UStringE
__ZN3JSC22globalMemoryStatisticsEv
+__ZN3JSC22objectConstructorTableE
__ZN3JSC23AbstractSamplingCounter4dumpEv
__ZN3JSC23objectProtoFuncToStringEPNS_9ExecStateE
__ZN3JSC23setUpStaticFunctionSlotEPNS_9ExecStateEPKNS_9HashEntryEPNS_8JSObjectERKNS_10IdentifierERNS_12PropertySlotE
@@ -248,7 +249,7 @@
__ZN3JSC6JSLock6unlockENS_14JSLockBehaviorE
__ZN3JSC6JSLock9lockCountEv
__ZN3JSC6JSLockC1EPNS_9ExecStateE
-__ZN3JSC6RegExp6createEPNS_12JSGlobalDataERKNS_7UStringES5_
+__ZN3JSC6RegExp6createEPNS_12JSGlobalDataERKNS_7UStringENS_11RegExpFlagsE
__ZN3JSC6RegExpD1Ev
__ZN3JSC7JSArray12markChildrenERNS_9MarkStackE
__ZN3JSC7JSArray15setSubclassDataEPv
@@ -446,10 +447,10 @@
__ZN3WTF3MD58addBytesEPKhm
__ZN3WTF3MD58checksumERNS_6VectorIhLm16EEE
__ZN3WTF3MD5C1Ev
-__ZN3WTF4dtoaEPcdRbRiRj
__ZN3WTF4SHA111computeHashERNS_6VectorIhLm20EEE
__ZN3WTF4SHA18addBytesEPKhm
__ZN3WTF4SHA1C1Ev
+__ZN3WTF4dtoaEPcdRbRiRj
__ZN3WTF5Mutex4lockEv
__ZN3WTF5Mutex6unlockEv
__ZN3WTF5Mutex7tryLockEv
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 2875434..4b6bb3e 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -125,7 +125,9 @@
{
if (dst == generator.ignoredResult())
return 0;
- RefPtr<RegExp> regExp = generator.globalData()->regExpCache()->lookupOrCreate(m_pattern.ustring(), m_flags.ustring());
+ RegExpFlags flags = regExpFlags(m_flags.ustring());
+ ASSERT(flags != InvalidFlags);
+ RefPtr<RegExp> regExp = generator.globalData()->regExpCache()->lookupOrCreate(m_pattern.ustring(), flags);
ASSERT(regExp->isValid());
return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get());
}
diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp
index 95ce5e9..25cb2d5 100644
--- a/Source/JavaScriptCore/runtime/RegExp.cpp
+++ b/Source/JavaScriptCore/runtime/RegExp.cpp
@@ -34,6 +34,38 @@
namespace JSC {
+RegExpFlags regExpFlags(const UString& string)
+{
+ RegExpFlags flags = NoFlags;
+
+ for (unsigned i = 0; i < string.length(); ++i) {
+ switch (string.characters()[i]) {
+ case 'g':
+ if (flags & FlagGlobal)
+ return InvalidFlags;
+ flags = static_cast<RegExpFlags>(flags | FlagGlobal);
+ break;
+
+ case 'i':
+ if (flags & FlagIgnoreCase)
+ return InvalidFlags;
+ flags = static_cast<RegExpFlags>(flags | FlagIgnoreCase);
+ break;
+
+ case 'm':
+ if (flags & FlagMultiline)
+ return InvalidFlags;
+ flags = static_cast<RegExpFlags>(flags | FlagMultiline);
+ break;
+
+ default:
+ return InvalidFlags;
+ }
+ }
+
+ return flags;
+}
+
struct RegExpRepresentation {
#if ENABLE(YARR_JIT)
Yarr::YarrCodeBlock m_regExpJITCode;
@@ -41,9 +73,9 @@
OwnPtr<Yarr::BytecodePattern> m_regExpBytecode;
};
-inline RegExp::RegExp(JSGlobalData* globalData, const UString& patternString, const UString& flags)
+inline RegExp::RegExp(JSGlobalData* globalData, const UString& patternString, RegExpFlags flags)
: m_patternString(patternString)
- , m_flagBits(0)
+ , m_flags(flags)
, m_constructionError(0)
, m_numSubpatterns(0)
#if ENABLE(REGEXP_TRACING)
@@ -52,17 +84,6 @@
#endif
, m_representation(adoptPtr(new RegExpRepresentation))
{
- // NOTE: The global flag is handled on a case-by-case basis by functions like
- // String::match and RegExpObject::match.
- if (!flags.isNull()) {
- if (flags.find('g') != notFound)
- m_flagBits |= Global;
- if (flags.find('i') != notFound)
- m_flagBits |= IgnoreCase;
- if (flags.find('m') != notFound)
- m_flagBits |= Multiline;
- }
-
m_state = compile(globalData);
}
@@ -70,7 +91,7 @@
{
}
-PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& patternString, const UString& flags)
+PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& patternString, RegExpFlags flags)
{
RefPtr<RegExp> res = adoptRef(new RegExp(globalData, patternString, flags));
#if ENABLE(REGEXP_TRACING)
diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h
index d99befb..f7fc4bf 100644
--- a/Source/JavaScriptCore/runtime/RegExp.h
+++ b/Source/JavaScriptCore/runtime/RegExp.h
@@ -24,6 +24,7 @@
#include "UString.h"
#include "ExecutableAllocator.h"
+#include "RegExpKey.h"
#include <wtf/Forward.h>
#include <wtf/RefCounted.h>
@@ -32,14 +33,16 @@
struct RegExpRepresentation;
class JSGlobalData;
+ RegExpFlags regExpFlags(const UString&);
+
class RegExp : public RefCounted<RegExp> {
public:
- static PassRefPtr<RegExp> create(JSGlobalData* globalData, const UString& pattern, const UString& flags);
+ static PassRefPtr<RegExp> create(JSGlobalData* globalData, const UString& pattern, RegExpFlags);
~RegExp();
- bool global() const { return m_flagBits & Global; }
- bool ignoreCase() const { return m_flagBits & IgnoreCase; }
- bool multiline() const { return m_flagBits & Multiline; }
+ bool global() const { return m_flags & FlagGlobal; }
+ bool ignoreCase() const { return m_flags & FlagIgnoreCase; }
+ bool multiline() const { return m_flags & FlagMultiline; }
const UString& pattern() const { return m_patternString; }
@@ -54,7 +57,7 @@
#endif
private:
- RegExp(JSGlobalData* globalData, const UString& pattern, const UString& flags);
+ RegExp(JSGlobalData* globalData, const UString& pattern, RegExpFlags);
enum RegExpState {
ParseError,
@@ -68,9 +71,8 @@
void matchCompareWithInterpreter(const UString&, int startOffset, int* offsetVector, int jitResult);
#endif
- enum FlagBits { Global = 1, IgnoreCase = 2, Multiline = 4 };
UString m_patternString;
- int m_flagBits;
+ RegExpFlags m_flags;
const char* m_constructionError;
unsigned m_numSubpatterns;
#if ENABLE(REGEXP_TRACING)
diff --git a/Source/JavaScriptCore/runtime/RegExpCache.cpp b/Source/JavaScriptCore/runtime/RegExpCache.cpp
index d101758..c96b047 100644
--- a/Source/JavaScriptCore/runtime/RegExpCache.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpCache.cpp
@@ -31,7 +31,7 @@
namespace JSC {
-PassRefPtr<RegExp> RegExpCache::lookupOrCreate(const UString& patternString, const UString& flags)
+PassRefPtr<RegExp> RegExpCache::lookupOrCreate(const UString& patternString, RegExpFlags flags)
{
if (patternString.length() < maxCacheablePatternLength) {
pair<RegExpCacheMap::iterator, bool> result = m_cacheMap.add(RegExpKey(flags, patternString), 0);
@@ -43,7 +43,7 @@
return create(patternString, flags, m_cacheMap.end());
}
-PassRefPtr<RegExp> RegExpCache::create(const UString& patternString, const UString& flags, RegExpCacheMap::iterator iterator)
+PassRefPtr<RegExp> RegExpCache::create(const UString& patternString, RegExpFlags flags, RegExpCacheMap::iterator iterator)
{
RefPtr<RegExp> regExp = RegExp::create(m_globalData, patternString, flags);
diff --git a/Source/JavaScriptCore/runtime/RegExpCache.h b/Source/JavaScriptCore/runtime/RegExpCache.h
index b5b637f..b4a6ae5 100644
--- a/Source/JavaScriptCore/runtime/RegExpCache.h
+++ b/Source/JavaScriptCore/runtime/RegExpCache.h
@@ -41,8 +41,8 @@
typedef HashMap<RegExpKey, RefPtr<RegExp> > RegExpCacheMap;
public:
- PassRefPtr<RegExp> lookupOrCreate(const UString& patternString, const UString& flags);
- PassRefPtr<RegExp> create(const UString& patternString, const UString& flags, RegExpCacheMap::iterator iterator);
+ PassRefPtr<RegExp> lookupOrCreate(const UString& patternString, RegExpFlags);
+ PassRefPtr<RegExp> create(const UString& patternString, RegExpFlags, RegExpCacheMap::iterator);
RegExpCache(JSGlobalData* globalData);
private:
diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
index c06fdc4..348f38a 100644
--- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
@@ -291,7 +291,7 @@
{
asRegExpConstructor(baseObject)->setMultiline(value.toBoolean(exec));
}
-
+
// ECMA 15.10.4
JSObject* constructRegExp(ExecState* exec, const ArgList& args)
{
@@ -305,7 +305,17 @@
}
UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec);
- UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec);
+ if (exec->hadException())
+ return 0;
+
+ RegExpFlags flags = NoFlags;
+ if (!arg1.isUndefined()) {
+ flags = regExpFlags(arg1.toString(exec));
+ if (exec->hadException())
+ return 0;
+ if (flags == InvalidFlags)
+ return throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
+ }
RefPtr<RegExp> regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags);
if (!regExp->isValid())
diff --git a/Source/JavaScriptCore/runtime/RegExpKey.h b/Source/JavaScriptCore/runtime/RegExpKey.h
index cd1368d..756fabc 100644
--- a/Source/JavaScriptCore/runtime/RegExpKey.h
+++ b/Source/JavaScriptCore/runtime/RegExpKey.h
@@ -25,63 +25,53 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "UString.h"
-#include <wtf/text/StringHash.h>
-
#ifndef RegExpKey_h
#define RegExpKey_h
+#include "UString.h"
+#include <wtf/text/StringHash.h>
+
namespace JSC {
+enum RegExpFlags {
+ NoFlags = 0,
+ FlagGlobal = 1,
+ FlagIgnoreCase = 2,
+ FlagMultiline = 4,
+ InvalidFlags = 8
+};
+
struct RegExpKey {
- int flagsValue;
+ RegExpFlags flagsValue;
RefPtr<StringImpl> pattern;
RegExpKey()
- : flagsValue(0)
+ : flagsValue(NoFlags)
{
}
- RegExpKey(int flags)
+ RegExpKey(RegExpFlags flags)
: flagsValue(flags)
{
}
- RegExpKey(int flags, const UString& pattern)
+ RegExpKey(RegExpFlags flags, const UString& pattern)
: flagsValue(flags)
, pattern(pattern.impl())
{
}
- RegExpKey(int flags, const PassRefPtr<StringImpl> pattern)
+ RegExpKey(RegExpFlags flags, const PassRefPtr<StringImpl> pattern)
: flagsValue(flags)
, pattern(pattern)
{
}
- RegExpKey(int flags, const RefPtr<StringImpl>& pattern)
+ RegExpKey(RegExpFlags flags, const RefPtr<StringImpl>& pattern)
: flagsValue(flags)
, pattern(pattern)
{
}
-
- RegExpKey(const UString& flags, const UString& pattern)
- : pattern(pattern.impl())
- {
- flagsValue = getFlagsValue(flags);
- }
-
- int getFlagsValue(const UString flags)
- {
- flagsValue = 0;
- if (flags.find('g') != notFound)
- flagsValue += 4;
- if (flags.find('i') != notFound)
- flagsValue += 2;
- if (flags.find('m') != notFound)
- flagsValue += 1;
- return flagsValue;
- }
};
inline bool operator==(const RegExpKey& a, const RegExpKey& b)
@@ -112,8 +102,8 @@
};
template<> struct HashTraits<JSC::RegExpKey> : GenericHashTraits<JSC::RegExpKey> {
- static void constructDeletedValue(JSC::RegExpKey& slot) { slot.flagsValue = -1; }
- static bool isDeletedValue(const JSC::RegExpKey& value) { return value.flagsValue == -1; }
+ static void constructDeletedValue(JSC::RegExpKey& slot) { slot.flagsValue = JSC::InvalidFlags; }
+ static bool isDeletedValue(const JSC::RegExpKey& value) { return value.flagsValue == JSC::InvalidFlags; }
};
} // namespace WTF
diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
index 106006c..35c3389 100644
--- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
@@ -48,7 +48,7 @@
// ECMA 15.10.5
RegExpPrototype::RegExpPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, Structure* functionStructure)
- : RegExpObject(globalObject, structure, RegExp::create(&exec->globalData(), "", ""))
+ : RegExpObject(globalObject, structure, RegExp::create(&exec->globalData(), "", NoFlags))
{
putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum);
putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().exec, regExpProtoFuncExec), DontEnum);
@@ -90,7 +90,17 @@
regExp = asRegExpObject(arg0)->regExp();
} else {
UString pattern = !exec->argumentCount() ? UString("") : arg0.toString(exec);
- UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ RegExpFlags flags = NoFlags;
+ if (!arg1.isUndefined()) {
+ flags = regExpFlags(arg1.toString(exec));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (flags == InvalidFlags)
+ return throwVMError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
+ }
regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags);
}
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp
index aa37122..41707b8 100644
--- a/Source/JavaScriptCore/runtime/StringPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp
@@ -615,7 +615,7 @@
* If regexp is not an object whose [[Class]] property is "RegExp", it is
* replaced with the result of the expression new RegExp(regexp).
*/
- reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), UString());
+ reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), NoFlags);
}
RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
int pos;
@@ -668,7 +668,7 @@
* If regexp is not an object whose [[Class]] property is "RegExp", it is
* replaced with the result of the expression new RegExp(regexp).
*/
- reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), UString());
+ reg = exec->globalData().regExpCache()->lookupOrCreate(a0.toString(exec), NoFlags);
}
RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
int pos;