Bug 1838771 - Assert the thread matches between JS::SetNativeStackQuota call and JS::CompileGlobalScriptToStencil for JS::FrontendContext. r=nbp

Differential Revision: https://phabricator.services.mozilla.com/D181201
This commit is contained in:
Tooru Fujisawa 2023-06-28 11:36:42 +00:00
Родитель 446a595eeb
Коммит c1cdda9cde
5 изменённых файлов: 75 добавлений и 0 удалений

Просмотреть файл

@ -125,8 +125,10 @@ oddly_ordered_inclnames = set(
"gc/StatsPhasesGenerated.inc", # Included in the body of gc/Statistics.cpp
"psapi.h", # Must be included after "util/WindowsWrapper.h" on Windows
"machine/endian.h", # Must be included after <sys/types.h> on BSD
"process.h", # Windows-specific
"winbase.h", # Must precede other system headers(?)
"windef.h", # Must precede other system headers(?)
"windows.h", # Must precede other system headers(?)
]
)

Просмотреть файл

@ -34,6 +34,11 @@ JS_PUBLIC_API JS::FrontendContext* NewFrontendContext();
// Destroy a front-end context allocated with NewFrontendContext.
JS_PUBLIC_API void DestroyFrontendContext(JS::FrontendContext* fc);
// Set the size of the native stack that should not be exceed. To disable
// stack size checking pass 0.
//
// WARNING: When the stack size checking is enabled, the JS::FrontendContext
// can be used only in the thread where JS::SetNativeStackQuota is called.
JS_PUBLIC_API void SetNativeStackQuota(JS::FrontendContext* fc,
JS::NativeStackSize stackSize);

Просмотреть файл

@ -154,12 +154,18 @@ already_AddRefed<JS::Stencil> JS::CompileGlobalScriptToStencil(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
JS::SourceText<mozilla::Utf8Unit>& srcBuf,
JS::CompilationStorage& compileStorage) {
#ifdef DEBUG
fc->assertNativeStackLimitThread();
#endif
return CompileGlobalScriptToStencilImpl(fc, options, srcBuf, compileStorage);
}
already_AddRefed<JS::Stencil> JS::CompileGlobalScriptToStencil(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
JS::SourceText<char16_t>& srcBuf, JS::CompilationStorage& compileStorage) {
#ifdef DEBUG
fc->assertNativeStackLimitThread();
#endif
return CompileGlobalScriptToStencilImpl(fc, options, srcBuf, compileStorage);
}
@ -167,6 +173,9 @@ already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& optionsInput,
JS::SourceText<mozilla::Utf8Unit>& srcBuf,
JS::CompilationStorage& compileStorage) {
#ifdef DEBUG
fc->assertNativeStackLimitThread();
#endif
return CompileModuleScriptToStencilImpl(fc, optionsInput, srcBuf,
compileStorage);
}
@ -174,6 +183,9 @@ already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil(
already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& optionsInput,
JS::SourceText<char16_t>& srcBuf, JS::CompilationStorage& compileStorage) {
#ifdef DEBUG
fc->assertNativeStackLimitThread();
#endif
return CompileModuleScriptToStencilImpl(fc, optionsInput, srcBuf,
compileStorage);
}

Просмотреть файл

@ -6,6 +6,13 @@
#include "frontend/FrontendContext.h"
#ifdef _WIN32
# include <windows.h>
# include <process.h> // GetCurrentThreadId
#else
# include <pthread.h> // pthread_self
#endif
#include "gc/GC.h"
#include "js/AllocPolicy.h" // js::ReportOutOfMemory
#include "js/friend/StackLimits.h" // js::ReportOverRecursed
@ -61,6 +68,10 @@ void FrontendContext::setStackQuota(JS::NativeStackSize stackSize) {
stackLimit_ = JS::GetNativeStackLimit(GetNativeStackBase(), stackSize - 1);
}
#endif // !__wasi__
#ifdef DEBUG
setNativeStackLimitThread();
#endif
}
bool FrontendContext::allocateOwnedPool() {
@ -164,6 +175,10 @@ void FrontendContext::setCurrentJSContext(JSContext* cx) {
nameCollectionPool_ = &cx->frontendCollectionPool();
scriptDataTableHolder_ = &cx->runtime()->scriptDataTableHolder();
stackLimit_ = cx->stackLimitForCurrentPrincipal();
#ifdef DEBUG
setNativeStackLimitThread();
#endif
}
void FrontendContext::convertToRuntimeError(
@ -196,6 +211,28 @@ void FrontendContext::linkWithJSContext(JSContext* cx) {
}
}
#ifdef DEBUG
static size_t GetTid() {
# if defined(_WIN32)
return size_t(GetCurrentThreadId());
# else
return size_t(pthread_self());
# endif
}
void FrontendContext::setNativeStackLimitThread() {
stackLimitThreadId_.emplace(GetTid());
}
void FrontendContext::assertNativeStackLimitThread() {
if (!stackLimitThreadId_.isSome()) {
return;
}
MOZ_ASSERT(*stackLimitThreadId_ == GetTid());
}
#endif
#ifdef __wasi__
void FrontendContext::incWasiRecursionDepth() {
if (maybeCx_) {

Просмотреть файл

@ -76,8 +76,22 @@ class FrontendContext {
JS::ImportAssertionVector supportedImportAssertions_;
// Limit pointer for checking native stack consumption.
//
// The pointer is calculated based on the stack base of the current thread
// except for JS::NativeStackLimitMax. Once such value is set, this
// FrontendContext can be used only in the thread.
//
// In order to enforce this thread rule, setNativeStackLimitThread should
// be called when setting the value, and assertNativeStackLimitThread should
// be called at each entry-point that might make use of this field.
JS::NativeStackLimit stackLimit_ = JS::NativeStackLimitMax;
#ifdef DEBUG
// The thread ID where the native stack limit is set.
mozilla::Maybe<size_t> stackLimitThreadId_;
#endif
protected:
// (optional) Current JSContext to support main-thread-specific
// handling for error reporting, GC, and memory allocation.
@ -177,6 +191,11 @@ class FrontendContext {
bool checkWasiRecursionLimit();
#endif // __wasi__
#ifdef DEBUG
void setNativeStackLimitThread();
void assertNativeStackLimitThread();
#endif
private:
void ReportOutOfMemory();
void addPendingOutOfMemory();