[constant-tracking] Fix RegExp.p.exec tampering check.

Bug: v8:5495, v8:8361
Change-Id: I8bf37c75113cff212d9899c39cffbca47c448924
Reviewed-on: https://chromium-review.googlesource.com/c/1297310
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56927}
This commit is contained in:
Jaroslav Sevcik 2018-10-24 07:38:57 +02:00 committed by Commit Bot
parent 68bd0a6b5d
commit f289f1cafb
3 changed files with 38 additions and 3 deletions

View File

@ -2534,6 +2534,10 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Handle<JSFunction> fun = SimpleInstallFunction(
isolate_, prototype, factory->exec_string(),
Builtins::kRegExpPrototypeExec, 1, true, DONT_ENUM);
// Check that index of "exec" function in JSRegExp is correct.
DCHECK_EQ(JSRegExp::kExecFunctionDescriptorIndex,
prototype->map()->LastAdded());
native_context()->set_regexp_exec_function(*fun);
}

View File

@ -916,9 +916,6 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context,
GotoIfForceSlowPath(if_ismodified);
// TODO(ishell): Update this check once map changes for constant field
// tracking are landing.
Node* const native_context = LoadNativeContext(context);
Node* const regexp_fun =
LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
@ -931,11 +928,42 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context,
Node* const initial_proto_initial_map =
LoadContextElement(native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX);
Node* const proto_map = LoadMap(LoadMapPrototype(map));
Node* const proto_has_initialmap =
WordEqual(proto_map, initial_proto_initial_map);
GotoIfNot(proto_has_initialmap, if_ismodified);
if (FLAG_track_constant_fields) {
// With constant field tracking, we need to make sure that the exec
// function in the prototype has not been tampered with. We do this by
// checking that the slot in the prototype's descriptor array is still
// marked as const.
TNode<DescriptorArray> descriptors = LoadMapDescriptors(proto_map);
const int index = JSRegExp::kExecFunctionDescriptorIndex;
// Assert the index is in-bounds.
CSA_ASSERT(this, SmiLessThan(SmiConstant(index),
LoadWeakFixedArrayLength(descriptors)));
// Assert that the name is correct. This essentially checks that
// the index corresponds to the insertion order in the bootstrapper.
CSA_ASSERT(this,
WordEqual(LoadWeakFixedArrayElement(
descriptors, DescriptorArray::ToKeyIndex(index)),
LoadRoot(RootIndex::kexec_string)));
TNode<Uint32T> details =
DescriptorArrayGetDetails(descriptors, Uint32Constant(index));
TNode<Uint32T> constness =
DecodeWord32<PropertyDetails::ConstnessField>(details);
GotoIfNot(
Word32Equal(constness,
Int32Constant(static_cast<int>(PropertyConstness::kConst))),
if_ismodified);
}
// The smi check is required to omit ToLength(lastIndex) calls with possible
// user-code execution on the fast path.
Node* const last_index = FastLoadLastIndex(CAST(object));

View File

@ -131,6 +131,9 @@ class JSRegExp : public JSObject {
static const int kLastIndexFieldIndex = 0;
static const int kInObjectFieldCount = 1;
// Descriptor array index to the exec method in the prototype.
static const int kExecFunctionDescriptorIndex = 1;
// The uninitialized value for a regexp code object.
static const int kUninitializedValue = -1;
};