Commit 6c12d57e authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[crankshaft] Fix Smi overflow in {HMaybeGrowElements}.

This fixes the case where the index passed to {HMaybeGrowElements} used
to derive the new capacity for the elements backing store does not fit
into Smi range. Such an overflow would fail the capacity check and cause
growing to be skipped. Subsequent keyed stores would potentially go out
of bounds.

R=mvstanton@chromium.org
TEST=mjsunit/regress/regress-crbug-686427
BUG=chromium:686427

Review-Url: https://codereview.chromium.org/2686263002
Cr-Commit-Position: refs/heads/master@{#43101}
parent 6d1c114c
......@@ -83,9 +83,6 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
Representation representation,
bool transition_to_field);
HValue* BuildPushElement(HValue* object, HValue* argc,
HValue* argument_elements, ElementsKind kind);
HValue* BuildToString(HValue* input, bool convert);
HValue* BuildToPrimitive(HValue* input, HValue* input_map);
......@@ -330,52 +327,6 @@ static Handle<Code> DoGenerateCode(Stub* stub) {
}
HValue* CodeStubGraphBuilderBase::BuildPushElement(HValue* object, HValue* argc,
HValue* argument_elements,
ElementsKind kind) {
// Precheck whether all elements fit into the array.
if (!IsFastObjectElementsKind(kind)) {
LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
HValue* start = graph()->GetConstant0();
HValue* key = builder.BeginBody(start, argc, Token::LT);
{
HInstruction* argument =
Add<HAccessArgumentsAt>(argument_elements, argc, key);
IfBuilder can_store(this);
can_store.IfNot<HIsSmiAndBranch>(argument);
if (IsFastDoubleElementsKind(kind)) {
can_store.And();
can_store.IfNot<HCompareMap>(argument,
isolate()->factory()->heap_number_map());
}
can_store.ThenDeopt(DeoptimizeReason::kFastPathFailed);
can_store.End();
}
builder.EndBody();
}
HValue* length = Add<HLoadNamedField>(object, nullptr,
HObjectAccess::ForArrayLength(kind));
HValue* new_length = AddUncasted<HAdd>(length, argc);
HValue* max_key = AddUncasted<HSub>(new_length, graph()->GetConstant1());
HValue* elements = Add<HLoadNamedField>(object, nullptr,
HObjectAccess::ForElementsPointer());
elements = BuildCheckForCapacityGrow(object, elements, kind, length, max_key,
true, STORE);
LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
HValue* start = graph()->GetConstant0();
HValue* key = builder.BeginBody(start, argc, Token::LT);
{
HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key);
HValue* index = AddUncasted<HAdd>(key, length);
AddElementAccess(elements, index, argument, object, nullptr, kind, STORE);
}
builder.EndBody();
return new_length;
}
HLoadNamedField* CodeStubGraphBuilderBase::BuildLoadNamedField(
HValue* object, FieldIndex index) {
Representation representation = index.is_double()
......
......@@ -4045,13 +4045,17 @@ void LCodeGen::DoDeferredMaybeGrowElements(LMaybeGrowElements* instr) {
if (Smi::IsValid(int_key)) {
__ mov(r3, Operand(Smi::FromInt(int_key)));
} else {
// We should never get here at runtime because there is a smi check on
// the key before this point.
__ stop("expected smi");
Abort(kArrayIndexConstantValueTooBig);
}
} else {
__ Move(r3, ToRegister(key));
__ SmiTag(r3);
Label is_smi;
__ SmiTag(r3, ToRegister(key), SetCC);
// Deopt if the key is outside Smi range. The stub expects Smi and would
// bump the elements into dictionary mode (and trigger a deopt) anyways.
__ b(vc, &is_smi);
__ PopSafepointRegisters();
DeoptimizeIf(al, instr, DeoptimizeReason::kOverflow);
__ bind(&is_smi);
}
GrowArrayElementsStub stub(isolate(), instr->hydrogen()->kind());
......
......@@ -3859,13 +3859,18 @@ void LCodeGen::DoDeferredMaybeGrowElements(LMaybeGrowElements* instr) {
if (Smi::IsValid(int_key)) {
__ mov(ebx, Immediate(Smi::FromInt(int_key)));
} else {
// We should never get here at runtime because there is a smi check on
// the key before this point.
__ int3();
Abort(kArrayIndexConstantValueTooBig);
}
} else {
Label is_smi;
__ Move(ebx, ToRegister(key));
__ SmiTag(ebx);
// Deopt if the key is outside Smi range. The stub expects Smi and would
// bump the elements into dictionary mode (and trigger a deopt) anyways.
__ j(no_overflow, &is_smi);
__ PopSafepointRegisters();
DeoptimizeIf(no_condition, instr, DeoptimizeReason::kOverflow);
__ bind(&is_smi);
}
GrowArrayElementsStub stub(isolate(), instr->hydrogen()->kind());
......
......@@ -4020,13 +4020,19 @@ void LCodeGen::DoDeferredMaybeGrowElements(LMaybeGrowElements* instr) {
if (Smi::IsValid(int_key)) {
__ li(a3, Operand(Smi::FromInt(int_key)));
} else {
// We should never get here at runtime because there is a smi check on
// the key before this point.
__ stop("expected smi");
Abort(kArrayIndexConstantValueTooBig);
}
} else {
__ mov(a3, ToRegister(key));
__ SmiTag(a3);
Label is_smi;
__ SmiTagCheckOverflow(a3, ToRegister(key), at);
// Deopt if the key is outside Smi range. The stub expects Smi and would
// bump the elements into dictionary mode (and trigger a deopt) anyways.
__ BranchOnNoOverflow(&is_smi, at);
RestoreRegistersStateStub stub(isolate());
__ push(ra);
__ CallStub(&stub);
DeoptimizeIf(al, instr, DeoptimizeReason::kOverflow);
__ bind(&is_smi);
}
GrowArrayElementsStub stub(isolate(), instr->hydrogen()->kind());
......
......@@ -4249,15 +4249,7 @@ void LCodeGen::DoDeferredMaybeGrowElements(LMaybeGrowElements* instr) {
LOperand* key = instr->key();
if (key->IsConstantOperand()) {
LConstantOperand* constant_key = LConstantOperand::cast(key);
int32_t int_key = ToInteger32(constant_key);
if (Smi::IsValid(int_key)) {
__ li(a3, Operand(Smi::FromInt(int_key)));
} else {
// We should never get here at runtime because there is a smi check on
// the key before this point.
__ stop("expected smi");
}
__ li(a3, Operand(ToSmi(LConstantOperand::cast(key))));
} else {
__ mov(a3, ToRegister(key));
__ SmiTag(a3);
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function f(a, base) {
a[base + 4] = 23;
return a;
}
var i = 1073741824;
assertEquals(23, f({}, 1)[1 + 4]);
assertEquals(23, f([], 2)[2 + 4]);
%OptimizeFunctionOnNextCall(f);
assertEquals(23, f({}, i)[i + 4]);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment