Bug 1236476: Report out of memory in ExpandErrorArgumentsVA; r=jandem

This commit is contained in:
Benjamin Bouvier 2016-01-05 10:24:05 +01:00
parent bf99b703b6
commit e1351b414b
6 changed files with 56 additions and 14 deletions

View File

@ -617,7 +617,10 @@ TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigne
// On the main thread, report the error immediately. When compiling off
// thread, save the error so that the main thread can report it later.
CompileError tempErr;
CompileError& err = cx->isJSContext() ? tempErr : cx->addPendingCompileError();
CompileError* tempErrPtr = &tempErr;
if (!cx->isJSContext() && !cx->addPendingCompileError(&tempErrPtr))
return false;
CompileError& err = *tempErrPtr;
err.report.flags = flags;
err.report.errorNumber = errorNumber;

View File

@ -0,0 +1,16 @@
// |jit-test| allow-oom; allow-unhandlable-oom
// 1236476
if (typeof oomTest !== 'function' ||
typeof offThreadCompileScript !== 'function' ||
typeof runOffThreadScript !== 'function')
quit();
oomTest(() => {
offThreadCompileScript(`
"use asm";
return assertEq;
`);
runOffThreadScript();
});

View File

@ -291,7 +291,7 @@ js::ReportOutOfMemory(ExclusiveContext* cxArg)
#endif
if (!cxArg->isJSContext())
return;
return cxArg->addPendingOutOfMemory();
JSContext* cx = cxArg->asJSContext();
cx->runtime()->hadOutOfMemory = true;
@ -645,7 +645,6 @@ js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback,
*/
reportp->ucmessage = out = cx->pod_malloc<char16_t>(expandedLength + 1);
if (!out) {
ReportOutOfMemory(cx);
js_free(buffer);
goto error;
}
@ -937,13 +936,16 @@ ExclusiveContext::ExclusiveContext(JSRuntime* rt, PerThreadData* pt, ContextKind
void
ExclusiveContext::recoverFromOutOfMemory()
{
// If this is not a JSContext, there's nothing to do.
if (JSContext* maybecx = maybeJSContext()) {
if (maybecx->isExceptionPending()) {
MOZ_ASSERT(maybecx->isThrowingOutOfMemory());
maybecx->clearPendingException();
}
return;
}
// Keep in sync with addPendingOutOfMemory.
if (ParseTask* task = helperThread()->parseTask())
task->outOfMemory = false;
}
JSContext::JSContext(JSRuntime* rt)

View File

@ -165,8 +165,10 @@ class ExclusiveContext : public ContextFriendFields,
}
void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes, void* reallocPtr = nullptr) {
if (!isJSContext())
if (!isJSContext()) {
addPendingOutOfMemory();
return nullptr;
}
return runtime_->onOutOfMemory(allocFunc, nbytes, reallocPtr, asJSContext());
}
@ -280,8 +282,9 @@ class ExclusiveContext : public ContextFriendFields,
}
// Methods specific to any HelperThread for the context.
frontend::CompileError& addPendingCompileError();
bool addPendingCompileError(frontend::CompileError** err);
void addPendingOverRecursed();
void addPendingOutOfMemory();
};
} /* namespace js */

View File

@ -28,6 +28,7 @@ using namespace js;
using mozilla::ArrayLength;
using mozilla::DebugOnly;
using mozilla::UniquePtr;
namespace js {
@ -203,7 +204,7 @@ ParseTask::ParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal, JSC
exclusiveContextGlobal(initCx->runtime(), exclusiveContextGlobal),
callback(callback), callbackData(callbackData),
script(initCx->runtime()), sourceObject(initCx->runtime()),
errors(cx), overRecursed(false)
errors(cx), overRecursed(false), outOfMemory(false)
{
}
@ -1058,6 +1059,12 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void
RootedScript script(rt, parseTask->script);
assertSameCompartment(cx, script);
// Report out of memory errors eagerly, or errors could be malformed.
if (parseTask->outOfMemory) {
ReportOutOfMemory(cx);
return nullptr;
}
// Report any error or warnings generated during the parse, and inform the
// debugger about the compiled scripts.
for (size_t i = 0; i < parseTask->errors.length(); i++)
@ -1341,14 +1348,16 @@ ExclusiveContext::setHelperThread(HelperThread* thread)
perThreadData = thread->threadData.ptr();
}
frontend::CompileError&
ExclusiveContext::addPendingCompileError()
bool
ExclusiveContext::addPendingCompileError(frontend::CompileError** error)
{
AutoEnterOOMUnsafeRegion oomUnsafe;
frontend::CompileError* error = js_new<frontend::CompileError>();
if (!error || !helperThread()->parseTask()->errors.append(error))
oomUnsafe.crash("ExclusiveContext::addPendingCompileError");
return *error;
UniquePtr<frontend::CompileError> errorPtr(new_<frontend::CompileError>());
if (!errorPtr)
return false;
if (!helperThread()->parseTask()->errors.append(errorPtr.get()))
return false;
*error = errorPtr.release();
return true;
}
void
@ -1358,6 +1367,14 @@ ExclusiveContext::addPendingOverRecursed()
helperThread()->parseTask()->overRecursed = true;
}
void
ExclusiveContext::addPendingOutOfMemory()
{
// Keep in sync with recoverFromOutOfMemory.
if (helperThread()->parseTask())
helperThread()->parseTask()->outOfMemory = true;
}
void
HelperThread::handleParseWorkload()
{

View File

@ -488,6 +488,7 @@ struct ParseTask
// when finishing the script.
Vector<frontend::CompileError*> errors;
bool overRecursed;
bool outOfMemory;
ParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
JSContext* initCx, const char16_t* chars, size_t length,