Bug 834989 - Use of RegExp in self-hosted code can be observed through RegExp statics. r=jwalden

This commit is contained in:
Norbert Lindenberg 2013-07-11 09:53:56 -04:00
parent 168b162725
commit 7968ef59e4
3 changed files with 80 additions and 16 deletions

View File

@ -528,7 +528,8 @@ js_InitRegExpClass(JSContext *cx, HandleObject obj)
}
RegExpRunStatus
js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string, MatchConduit &matches)
js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string,
MatchConduit &matches, RegExpStaticsUpdate staticsUpdate)
{
/* Step 1 (b) was performed by CallNonGenericMethod. */
Rooted<RegExpObject*> reobj(cx, &regexp->as<RegExpObject>());
@ -537,7 +538,7 @@ js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string, Match
if (!reobj->getShared(cx, &re))
return RegExpRunStatus_Error;
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = (staticsUpdate == UpdateRegExpStatics) ? cx->regExpStatics() : NULL;
/* Step 3. */
Rooted<JSLinearString*> input(cx, string->ensureLinear(cx));
@ -607,27 +608,19 @@ ExecuteRegExp(JSContext *cx, CallArgs args, MatchConduit &matches)
if (!string)
return RegExpRunStatus_Error;
return ExecuteRegExp(cx, regexp, string, matches);
return ExecuteRegExp(cx, regexp, string, matches, UpdateRegExpStatics);
}
/* ES5 15.10.6.2. */
static bool
regexp_exec_impl(JSContext *cx, CallArgs args)
regexp_exec_impl(JSContext *cx, CallArgs args, HandleObject regexp, HandleString string,
RegExpStaticsUpdate staticsUpdate)
{
/* Execute regular expression and gather matches. */
ScopedMatchPairs matches(&cx->tempLifoAlloc());
MatchConduit conduit(&matches);
/*
* Extract arguments to share between ExecuteRegExp()
* and CreateRegExpMatchResult().
*/
RootedObject regexp(cx, &args.thisv().toObject());
RootedString string(cx, ToString<CanGC>(cx, args.handleOrUndefinedAt(0)));
if (!string)
return false;
RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, conduit);
RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, conduit, staticsUpdate);
if (status == RegExpRunStatus_Error)
return false;
@ -640,6 +633,17 @@ regexp_exec_impl(JSContext *cx, CallArgs args)
return CreateRegExpMatchResult(cx, string, matches, args.rval());
}
static bool
regexp_exec_impl(JSContext *cx, CallArgs args)
{
RootedObject regexp(cx, &args.thisv().toObject());
RootedString string(cx, ToString<CanGC>(cx, args.handleOrUndefinedAt(0)));
if (!string)
return false;
return regexp_exec_impl(cx, args, regexp, string, UpdateRegExpStatics);
}
JSBool
js::regexp_exec(JSContext *cx, unsigned argc, Value *vp)
{
@ -647,6 +651,20 @@ js::regexp_exec(JSContext *cx, unsigned argc, Value *vp)
return CallNonGenericMethod(cx, IsRegExp, regexp_exec_impl, args);
}
JSBool
js::regexp_exec_no_statics(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(args.length() == 2);
JS_ASSERT(IsRegExp(args[0]));
JS_ASSERT(args[1].isString());
RootedObject regexp(cx, &args[0].toObject());
RootedString string(cx, args[1].toString());
return regexp_exec_impl(cx, args, regexp, string, DontUpdateRegExpStatics);
}
/* ES5 15.10.6.3. */
static bool
regexp_test_impl(JSContext *cx, CallArgs args)
@ -664,7 +682,7 @@ js::regexp_test_raw(JSContext *cx, HandleObject regexp, HandleString input, JSBo
{
MatchPair match;
MatchConduit conduit(&match);
RegExpRunStatus status = ExecuteRegExp(cx, regexp, input, conduit);
RegExpRunStatus status = ExecuteRegExp(cx, regexp, input, conduit, UpdateRegExpStatics);
*result = (status == RegExpRunStatus_Success);
return (status != RegExpRunStatus_Error);
}
@ -675,3 +693,21 @@ js::regexp_test(JSContext *cx, unsigned argc, Value *vp)
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod(cx, IsRegExp, regexp_test_impl, args);
}
JSBool
js::regexp_test_no_statics(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(args.length() == 2);
JS_ASSERT(IsRegExp(args[0]));
JS_ASSERT(args[1].isString());
RootedObject regexp(cx, &args[0].toObject());
RootedString string(cx, args[1].toString());
MatchPair match;
MatchConduit conduit(&match);
RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, conduit, DontUpdateRegExpStatics);
args.rval().setBoolean(status == RegExpRunStatus_Success);
return (status != RegExpRunStatus_Error);
}

View File

@ -22,9 +22,13 @@ js_InitRegExpClass(JSContext *cx, js::HandleObject obj);
namespace js {
// Whether RegExp statics should be updated with the input and results of a
// regular expression execution.
enum RegExpStaticsUpdate { UpdateRegExpStatics, DontUpdateRegExpStatics };
RegExpRunStatus
ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string,
MatchConduit &matches);
MatchConduit &matches, RegExpStaticsUpdate staticsUpdate);
/*
* Legacy behavior of ExecuteRegExp(), which is baked into the JSAPI.
@ -56,6 +60,26 @@ regexp_test_raw(JSContext *cx, HandleObject regexp, HandleString input, JSBool *
extern JSBool
regexp_test(JSContext *cx, unsigned argc, Value *vp);
/*
* The following functions are for use by self-hosted code.
*/
/*
* Behaves like regexp.exec(string), but doesn't set RegExp statics.
*
* Usage: match = regexp_exec_no_statics(regexp, string)
*/
extern JSBool
regexp_exec_no_statics(JSContext *cx, unsigned argc, Value *vp);
/*
* Behaves like regexp.test(string), but doesn't set RegExp statics.
*
* Usage: does_match = regexp_test_no_statics(regexp, string)
*/
extern JSBool
regexp_test_no_statics(JSContext *cx, unsigned argc, Value *vp);
} /* namespace js */
#endif /* builtin_RegExp_h */

View File

@ -655,6 +655,10 @@ const JSFunctionSpec intrinsic_functions[] = {
JS_FN("intl_numberingSystem", intl_numberingSystem, 1,0),
JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
// See builtin/RegExp.h for descriptions of the regexp_* functions.
JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
JS_FN("regexp_test_no_statics", regexp_test_no_statics, 2,0),
#ifdef DEBUG
JS_FN("Dump", intrinsic_Dump, 1,0),