Bug 826581 - Root RegExp source for the lifetime of RegExpShared. r=dvander

This commit is contained in:
Sean Stangl 2013-01-07 14:32:52 -08:00
parent 152a9285ce
commit c570fc3be6
8 changed files with 66 additions and 20 deletions

View File

@ -143,7 +143,7 @@ js::ExecuteRegExpLegacy(JSContext *cx, RegExpStatics *res, RegExpObject &reobj,
Handle<JSStableString*> input, StableCharPtr chars, size_t length,
size_t *lastIndex, JSBool test, jsval *rval)
{
RegExpGuard shared;
RegExpGuard shared(cx);
if (!reobj.getShared(cx, &shared))
return false;
@ -252,7 +252,7 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
*/
RegExpFlag flags;
{
RegExpGuard g;
RegExpGuard g(cx);
if (!RegExpToShared(cx, *sourceObj, &g))
return false;
@ -556,7 +556,7 @@ js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string, Match
/* Step 1 (b) was performed by CallNonGenericMethod. */
Rooted<RegExpObject*> reobj(cx, &regexp->asRegExp());
RegExpGuard re;
RegExpGuard re(cx);
if (!reobj->getShared(cx, &re))
return RegExpRunStatus_Error;

View File

@ -0,0 +1,12 @@
// Don't crash.
try {
x = " () ";
for (var y = 0; y < 19; y++) {
x += x;
}
} catch (e) {}
try {
"".replace(x, "", "gy");
} catch (e) { }

View File

@ -1548,7 +1548,9 @@ class StringRegExpGuard
}
public:
StringRegExpGuard(JSContext *cx) : fm(cx) {}
StringRegExpGuard(JSContext *cx)
: re_(cx), fm(cx)
{ }
/* init must succeed in order to call tryFlatMatch or normalizeRegExp. */
bool init(JSContext *cx, CallArgs args, bool convertVoid = false)
@ -1632,7 +1634,7 @@ class StringRegExpGuard
opt = NULL;
}
JSAtom *patstr;
Rooted<JSAtom *> patstr(cx);
if (flat) {
patstr = flattenPattern(cx, fm.patstr);
if (!patstr)
@ -2784,7 +2786,7 @@ js::str_split(JSContext *cx, unsigned argc, Value *vp)
}
/* Step 8. */
RegExpGuard re;
RegExpGuard re(cx);
JSLinearString *sepstr = NULL;
bool sepDefined = args.hasDefined(0);
if (sepDefined) {

View File

@ -7014,7 +7014,7 @@ mjit::Compiler::jsop_regexp()
* between now and construction of that jitcode could purge the shared
* info, but such activity will also abort compilation.
*/
RegExpGuard g;
RegExpGuard g(cx);
if (!reobj->getShared(cx, &g))
return false;

View File

@ -1659,6 +1659,11 @@ JITChunk::trace(JSTracer *trc)
/* We use a manual write barrier in destroyChunk. */
MarkObjectUnbarriered(trc, &rootedTemplates_[i], "jitchunk_template");
}
/* RegExpShared objects require the RegExp source string. */
RegExpShared **rootedRegExps_ = rootedRegExps();
for (size_t i = 0; i < nRootedRegExps; i++)
rootedRegExps_[i]->trace(trc);
}
void

View File

@ -101,7 +101,7 @@ RegExpObjectBuilder::clone(Handle<RegExpObject *> other, Handle<RegExpObject *>
return build(source, newFlags);
}
RegExpGuard g;
RegExpGuard g(cx);
if (!other->getShared(cx, &g))
return NULL;
@ -405,6 +405,12 @@ RegExpShared::~RegExpShared()
js_delete<BytecodePattern>(bytecode);
}
void
RegExpShared::trace(JSTracer *trc)
{
MarkString(trc, &source, "regexpshared source");
}
void
RegExpShared::reportYarrError(JSContext *cx, TokenStream *ts, ErrorCode error)
{

View File

@ -120,11 +120,11 @@ class RegExpShared
#endif
/*
* Source to the RegExp. Safe to hold: if the RegExpShared is active,
* then at least one RegExpObject must be referencing the RegExpShared,
* and the RegExpObject keeps alive the source JSAtom.
* Source to the RegExp. The RegExpShared must either be protected by a
* RegExpGuard, which handles rooting for stacky RegExpShareds,
* or trace() must be explicitly called during marking.
*/
JSAtom * source;
HeapPtrAtom source;
RegExpFlag flags;
unsigned parenCount;
@ -149,6 +149,8 @@ class RegExpShared
RegExpShared(JSRuntime *rt, JSAtom *source, RegExpFlag flags);
~RegExpShared();
void trace(JSTracer *trc);
/* Static functions to expose some Yarr logic. */
static inline bool isJITRuntimeEnabled(JSContext *cx);
static void reportYarrError(JSContext *cx, TokenStream *ts, ErrorCode error);
@ -198,22 +200,41 @@ class RegExpShared
class RegExpGuard
{
RegExpShared *re_;
/*
* Prevent the RegExp source from being collected:
* because RegExpShared objects compile at execution time, the source
* must remain rooted for the active lifetime of the RegExpShared.
*/
RootedAtom source_;
RegExpGuard(const RegExpGuard &) MOZ_DELETE;
void operator=(const RegExpGuard &) MOZ_DELETE;
public:
RegExpGuard() : re_(NULL) {}
RegExpGuard(RegExpShared &re) : re_(&re) {
re_->incRef();
}
void init(RegExpShared &re) {
JS_ASSERT(!re_);
re_ = &re;
RegExpGuard(JSContext *cx)
: re_(NULL), source_(cx)
{ }
RegExpGuard(JSContext *cx, RegExpShared &re)
: re_(&re), source_(cx, re.source)
{
re_->incRef();
}
~RegExpGuard() {
if (re_)
re_->decRef();
}
public:
void init(RegExpShared &re) {
JS_ASSERT(!re_);
re_ = &re;
re_->incRef();
source_ = re.source;
}
bool initialized() const { return !!re_; }
RegExpShared *re() const { JS_ASSERT(initialized()); return re_; }
RegExpShared *operator->() { return re(); }

View File

@ -87,7 +87,7 @@ RegExpStatics::executeLazy(JSContext *cx)
StableCharPtr chars(matchesInput->chars(), length);
/* Execute the full regular expression. */
RegExpGuard shared;
RegExpGuard shared(cx);
if (!regexp->getShared(cx, &shared))
return false;