From 82ee97156b7d3f4f17fa8ee88dcc2bbadfbf4db3 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 5 Jul 2016 11:31:28 +0100 Subject: [PATCH] Bug 1283448 - Freeze module objects before they are passed back to the caller r=shu --- js/src/builtin/ModuleObject.cpp | 46 ++++++++++++-------- js/src/builtin/ModuleObject.h | 6 ++- js/src/frontend/BytecodeCompiler.cpp | 2 +- js/src/jit-test/tests/modules/bug-1283448.js | 10 +++++ js/src/vm/HelperThreads.cpp | 2 +- 5 files changed, 44 insertions(+), 22 deletions(-) create mode 100644 js/src/jit-test/tests/modules/bug-1283448.js diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index b741edf60470..505659631c04 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -722,36 +722,46 @@ FreezeObjectProperty(JSContext* cx, HandleNativeObject obj, uint32_t slot) } /* static */ bool -ModuleObject::FreezeArrayProperties(JSContext* cx, HandleModuleObject self) +ModuleObject::Freeze(JSContext* cx, HandleModuleObject self) { return FreezeObjectProperty(cx, self, RequestedModulesSlot) && FreezeObjectProperty(cx, self, ImportEntriesSlot) && FreezeObjectProperty(cx, self, LocalExportEntriesSlot) && FreezeObjectProperty(cx, self, IndirectExportEntriesSlot) && - FreezeObjectProperty(cx, self, StarExportEntriesSlot); + FreezeObjectProperty(cx, self, StarExportEntriesSlot) && + FreezeObject(cx, self); } -static inline void -AssertObjectPropertyFrozen(JSContext* cx, HandleNativeObject obj, uint32_t slot) -{ #ifdef DEBUG + +static inline bool +IsObjectFrozen(JSContext* cx, HandleObject obj) +{ bool frozen = false; - RootedObject property(cx, &obj->getSlot(slot).toObject()); - MOZ_ALWAYS_TRUE(TestIntegrityLevel(cx, property, IntegrityLevel::Frozen, &frozen)); - MOZ_ASSERT(frozen); -#endif + MOZ_ALWAYS_TRUE(TestIntegrityLevel(cx, obj, IntegrityLevel::Frozen, &frozen)); + return frozen; } -/* static */ inline void -ModuleObject::AssertArrayPropertiesFrozen(JSContext* cx, HandleModuleObject self) +static inline bool +IsObjectPropertyFrozen(JSContext* cx, HandleNativeObject obj, uint32_t slot) { - AssertObjectPropertyFrozen(cx, self, RequestedModulesSlot); - AssertObjectPropertyFrozen(cx, self, ImportEntriesSlot); - AssertObjectPropertyFrozen(cx, self, LocalExportEntriesSlot); - AssertObjectPropertyFrozen(cx, self, IndirectExportEntriesSlot); - AssertObjectPropertyFrozen(cx, self, StarExportEntriesSlot); + RootedObject property(cx, &obj->getSlot(slot).toObject()); + return IsObjectFrozen(cx, property); } +/* static */ inline bool +ModuleObject::IsFrozen(JSContext* cx, HandleModuleObject self) +{ + return IsObjectPropertyFrozen(cx, self, RequestedModulesSlot) && + IsObjectPropertyFrozen(cx, self, ImportEntriesSlot) && + IsObjectPropertyFrozen(cx, self, LocalExportEntriesSlot) && + IsObjectPropertyFrozen(cx, self, IndirectExportEntriesSlot) && + IsObjectPropertyFrozen(cx, self, StarExportEntriesSlot) && + IsObjectFrozen(cx, self); +} + +#endif + inline static void AssertModuleScopesMatch(ModuleObject* module) { @@ -858,7 +868,7 @@ ModuleObject::noteFunctionDeclaration(ExclusiveContext* cx, HandleAtom name, Han /* static */ bool ModuleObject::instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject self) { - AssertArrayPropertiesFrozen(cx, self); + MOZ_ASSERT(IsFrozen(cx, self)); FunctionDeclarationVector* funDecls = self->functionDeclarations(); if (!funDecls) { @@ -896,7 +906,7 @@ ModuleObject::setEvaluated() /* static */ bool ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValue rval) { - AssertArrayPropertiesFrozen(cx, self); + MOZ_ASSERT(IsFrozen(cx, self)); RootedScript script(cx, self->script()); RootedModuleEnvironmentObject scope(cx, self->environment()); diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index 8e321e38c4d6..642657fe0d91 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -236,8 +236,10 @@ class ModuleObject : public NativeObject HandleArrayObject localExportEntries, HandleArrayObject indiretExportEntries, HandleArrayObject starExportEntries); - static bool FreezeArrayProperties(JSContext* cx, HandleModuleObject self); - static void AssertArrayPropertiesFrozen(JSContext* cx, HandleModuleObject self); + static bool Freeze(JSContext* cx, HandleModuleObject self); +#ifdef DEBUG + static bool IsFrozen(JSContext* cx, HandleModuleObject self); +#endif void fixScopesAfterCompartmentMerge(JSContext* cx); JSScript* script() const; diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 46c5585db9c5..8a4bcbfe5128 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -801,7 +801,7 @@ frontend::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options, // This happens in GlobalHelperThreadState::finishModuleParseTask() when a // module is compiled off main thread. - if (!ModuleObject::FreezeArrayProperties(cx->asJSContext(), module)) + if (!ModuleObject::Freeze(cx->asJSContext(), module)) return nullptr; return module; diff --git a/js/src/jit-test/tests/modules/bug-1283448.js b/js/src/jit-test/tests/modules/bug-1283448.js new file mode 100644 index 000000000000..9ee6217abf79 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1283448.js @@ -0,0 +1,10 @@ +// |jit-test| error: TypeError + +let moduleRepo = {}; +setModuleResolveHook(function(module, specifier) { + return moduleRepo[specifier]; +}); +let a = moduleRepo['a'] = parseModule("var x = 1; export { x };"); +let b = moduleRepo['b'] = parseModule("import { x as y } from 'a';"); +a.__proto__ = {15: 1337}; +b.declarationInstantiation(); diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index 9e624c87c27a..7e12faa449f9 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -1215,7 +1215,7 @@ GlobalHelperThreadState::finishModuleParseTask(JSContext* maybecx, JSRuntime* rt JSContext* cx = maybecx; RootedModuleObject module(cx, script->module()); module->fixScopesAfterCompartmentMerge(cx); - if (!ModuleObject::FreezeArrayProperties(cx, module)) + if (!ModuleObject::Freeze(cx, module)) return nullptr; return module;