[heap] Handle partially initialized objects in NativeContextInferrer

Since GC can now happen during deserialization, object fields may
contain the Smi sentinel value instead of pointers. This adds the
required guards to methods of NativeContextInferrer

Bug: chromium:1136801
Change-Id: I7338f31bf6ee34b8dee8431b8250d2cc2978e0c2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2461241
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70425}
This commit is contained in:
Ulan Degenbaev 2020-10-09 13:26:06 +02:00 committed by Commit Bot
parent ceeee0c78d
commit 32d7ec1af4
4 changed files with 92 additions and 10 deletions

View File

@ -20,13 +20,13 @@ bool NativeContextInferrer::Infer(Isolate* isolate, Map map, HeapObject object,
Address* native_context) {
switch (map.visitor_id()) {
case kVisitContext:
*native_context = Context::cast(object).native_context().ptr();
return true;
return InferForContext(isolate, Context::cast(object), native_context);
case kVisitNativeContext:
*native_context = object.ptr();
return true;
case kVisitJSFunction:
return InferForJSFunction(JSFunction::cast(object), native_context);
return InferForJSFunction(isolate, JSFunction::cast(object),
native_context);
case kVisitJSApiObject:
case kVisitJSArrayBuffer:
case kVisitJSObject:

View File

@ -337,15 +337,37 @@ std::unique_ptr<v8::MeasureMemoryDelegate> MemoryMeasurement::DefaultDelegate(
mode);
}
bool NativeContextInferrer::InferForJSFunction(JSFunction function,
Address* native_context) {
if (function.has_context()) {
*native_context = function.context().native_context().ptr();
bool NativeContextInferrer::InferForContext(Isolate* isolate, Context context,
Address* native_context) {
Map context_map = context.synchronized_map();
Object maybe_native_context =
TaggedField<Object, Map::kConstructorOrBackPointerOrNativeContextOffset>::
Acquire_Load(isolate, context_map);
if (maybe_native_context.IsNativeContext()) {
*native_context = maybe_native_context.ptr();
return true;
}
return false;
}
bool NativeContextInferrer::InferForJSFunction(Isolate* isolate,
JSFunction function,
Address* native_context) {
Object maybe_context =
TaggedField<Object, JSFunction::kContextOffset>::Acquire_Load(isolate,
function);
// The context may be a smi during deserialization.
if (maybe_context.IsSmi()) {
DCHECK_EQ(maybe_context, Deserializer::uninitialized_field_value());
return false;
}
if (!maybe_context.IsContext()) {
// The function does not have a context.
return false;
}
return InferForContext(isolate, Context::cast(maybe_context), native_context);
}
bool NativeContextInferrer::InferForJSObject(Isolate* isolate, Map map,
JSObject object,
Address* native_context) {
@ -361,7 +383,7 @@ bool NativeContextInferrer::InferForJSObject(Isolate* isolate, Map map,
const int kMaxSteps = 3;
Object maybe_constructor = map.TryGetConstructor(isolate, kMaxSteps);
if (maybe_constructor.IsJSFunction()) {
return InferForJSFunction(JSFunction::cast(maybe_constructor),
return InferForJSFunction(isolate, JSFunction::cast(maybe_constructor),
native_context);
}
return false;

View File

@ -73,7 +73,10 @@ class V8_EXPORT_PRIVATE NativeContextInferrer {
Address* native_context);
private:
bool InferForJSFunction(JSFunction function, Address* native_context);
bool InferForContext(Isolate* isolate, Context context,
Address* native_context);
bool InferForJSFunction(Isolate* isolate, JSFunction function,
Address* native_context);
bool InferForJSObject(Isolate* isolate, Map map, JSObject object,
Address* native_context);
};

View File

@ -91,7 +91,6 @@ TEST(NativeContextStatsArrayBuffers) {
*i_array_buffer, 10);
CHECK_EQ(1010, stats.Get(native_context->ptr()));
}
namespace {
class TestResource : public v8::String::ExternalStringResource {
@ -229,6 +228,64 @@ TEST(LazyMemoryMeasurement) {
CHECK(!platform.TaskPosted());
}
TEST(PartiallyInitializedJSFunction) {
LocalContext env;
Isolate* isolate = CcTest::i_isolate();
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<JSFunction> js_function =
factory->NewFunctionForTest(factory->NewStringFromAsciiChecked("test"));
Handle<Context> context = handle(js_function->context(), isolate);
// 1. Start simulating deserializaiton.
isolate->RegisterDeserializerStarted();
// 2. Set the context field to the uninitialized sentintel.
TaggedField<Object, JSFunction::kContextOffset>::store(
*js_function, Deserializer::uninitialized_field_value());
// 3. Request memory meaurement and run all tasks. GC that runs as part
// of the measurement should not crash.
CcTest::isolate()->MeasureMemory(
std::make_unique<MockMeasureMemoryDelegate>(),
v8::MeasureMemoryExecution::kEager);
while (v8::platform::PumpMessageLoop(v8::internal::V8::GetCurrentPlatform(),
CcTest::isolate())) {
}
// 4. Restore the value and complete deserialization.
TaggedField<Object, JSFunction::kContextOffset>::store(*js_function,
*context);
isolate->RegisterDeserializerFinished();
}
TEST(PartiallyInitializedContext) {
LocalContext env;
Isolate* isolate = CcTest::i_isolate();
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<ScopeInfo> scope_info =
ReadOnlyRoots(isolate).global_this_binding_scope_info_handle();
Handle<Context> context = factory->NewScriptContext(
GetNativeContext(isolate, env.local()), scope_info);
Handle<Map> map = handle(context->map(), isolate);
Handle<NativeContext> native_context = handle(map->native_context(), isolate);
// 1. Start simulating deserializaiton.
isolate->RegisterDeserializerStarted();
// 2. Set the native context field to the uninitialized sentintel.
TaggedField<Object, Map::kConstructorOrBackPointerOrNativeContextOffset>::
store(*map, Deserializer::uninitialized_field_value());
// 3. Request memory meaurement and run all tasks. GC that runs as part
// of the measurement should not crash.
CcTest::isolate()->MeasureMemory(
std::make_unique<MockMeasureMemoryDelegate>(),
v8::MeasureMemoryExecution::kEager);
while (v8::platform::PumpMessageLoop(v8::internal::V8::GetCurrentPlatform(),
CcTest::isolate())) {
}
// 4. Restore the value and complete deserialization.
TaggedField<Object, Map::kConstructorOrBackPointerOrNativeContextOffset>::
store(*map, *native_context);
isolate->RegisterDeserializerFinished();
}
} // namespace heap
} // namespace internal
} // namespace v8