Commit 79de22a5 authored by plind44@gmail.com's avatar plind44@gmail.com

MIPS: Fixed crashes exposed though fuzzing.

Port r17886 (e2fb3ed)

Original commit message:
The %_OneByteSeqStringSetChar intrinsic expects its arguments to be checked before being called for efficiency reasons, but the fuzzer provided no such checks. Now the intrinsic is robust to bad input if FLAG_debug_code is set.

R=plind44@gmail.com, yangguo@chromium.org
TEST=test/mjsunit/regress/regress-320948.js
BUG=chromium:320948
LOG=Y

Review URL: https://codereview.chromium.org/68793008

Patch from Balazs Kilvady <kilvadyb@homejinni.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17891 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a5f910eb
......@@ -3516,29 +3516,6 @@ void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
}
void FullCodeGenerator::EmitSeqStringSetCharCheck(Register string,
Register index,
Register value,
uint32_t encoding_mask) {
__ And(at, index, Operand(kSmiTagMask));
__ Check(eq, kNonSmiIndex, at, Operand(zero_reg));
__ And(at, value, Operand(kSmiTagMask));
__ Check(eq, kNonSmiValue, at, Operand(zero_reg));
__ lw(at, FieldMemOperand(string, String::kLengthOffset));
__ Check(lt, kIndexIsTooLarge, index, Operand(at));
__ Check(ge, kIndexIsNegative, index, Operand(zero_reg));
__ lw(at, FieldMemOperand(string, HeapObject::kMapOffset));
__ lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset));
__ And(at, at, Operand(kStringRepresentationMask | kStringEncodingMask));
__ Subu(at, at, Operand(encoding_mask));
__ Check(eq, kUnexpectedStringType, at, Operand(zero_reg));
}
void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT_EQ(3, args->length());
......@@ -3553,8 +3530,16 @@ void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
__ Pop(index, value);
if (FLAG_debug_code) {
__ And(at, value, Operand(kSmiTagMask));
__ ThrowIf(ne, kNonSmiValue, at, Operand(zero_reg));
__ And(at, index, Operand(kSmiTagMask));
__ ThrowIf(ne, kNonSmiIndex, at, Operand(zero_reg));
__ SmiUntag(index, index);
static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
Register scratch = t5;
__ EmitSeqStringSetCharCheck(
string, index, value, scratch, one_byte_seq_type);
__ SmiTag(index, index);
}
__ SmiUntag(value, value);
......@@ -3582,8 +3567,16 @@ void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
__ Pop(index, value);
if (FLAG_debug_code) {
__ And(at, value, Operand(kSmiTagMask));
__ ThrowIf(ne, kNonSmiValue, at, Operand(zero_reg));
__ And(at, index, Operand(kSmiTagMask));
__ ThrowIf(ne, kNonSmiIndex, at, Operand(zero_reg));
__ SmiUntag(index, index);
static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
Register scratch = t5;
__ EmitSeqStringSetCharCheck(
string, index, value, scratch, two_byte_seq_type);
__ SmiTag(index, index);
}
__ SmiUntag(value, value);
......
......@@ -1820,16 +1820,13 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
if (FLAG_debug_code) {
Register scratch = scratch0();
__ lw(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
__ lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
__ And(scratch, scratch,
Operand(kStringRepresentationMask | kStringEncodingMask));
Register index = ToRegister(instr->index());
static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
__ Subu(at, scratch, Operand(encoding == String::ONE_BYTE_ENCODING
? one_byte_seq_type : two_byte_seq_type));
__ Check(eq, kUnexpectedStringType, at, Operand(zero_reg));
int encoding_mask =
instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
? one_byte_seq_type : two_byte_seq_type;
__ EmitSeqStringSetCharCheck(string, index, value, scratch, encoding_mask);
}
MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
......
......@@ -1826,10 +1826,13 @@ LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
LOperand* string = UseRegister(instr->string());
LOperand* index = UseRegisterOrConstant(instr->index());
LOperand* value = UseRegister(instr->value());
return new(zone()) LSeqStringSetChar(string, index, value);
LOperand* string = UseRegisterAtStart(instr->string());
LOperand* index = FLAG_debug_code
? UseRegisterAtStart(instr->index())
: UseRegisterOrConstantAtStart(instr->index());
LOperand* value = UseRegisterAtStart(instr->value());
LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
return new(zone()) LSeqStringSetChar(context, string, index, value);
}
......
......@@ -1381,19 +1381,21 @@ class LSeqStringGetChar V8_FINAL : public LTemplateInstruction<1, 2, 0> {
};
class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> {
class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 4, 0> {
public:
LSeqStringSetChar(LOperand* string,
LSeqStringSetChar(LOperand* context,
LOperand* string,
LOperand* index,
LOperand* value) {
inputs_[0] = string;
inputs_[1] = index;
inputs_[2] = value;
inputs_[0] = context;
inputs_[1] = string;
inputs_[2] = index;
inputs_[3] = value;
}
LOperand* string() { return inputs_[0]; }
LOperand* index() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
LOperand* string() { return inputs_[1]; }
LOperand* index() { return inputs_[2]; }
LOperand* value() { return inputs_[3]; }
DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
......
......@@ -5051,6 +5051,44 @@ int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments,
}
void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
Register index,
Register value,
Register scratch,
uint32_t encoding_mask) {
Label is_object;
And(at, string, Operand(kSmiTagMask));
ThrowIf(eq, kNonObject, at, Operand(zero_reg));
lw(at, FieldMemOperand(string, HeapObject::kMapOffset));
lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset));
andi(at, at, kStringRepresentationMask | kStringEncodingMask);
li(scratch, Operand(encoding_mask));
ThrowIf(ne, kUnexpectedStringType, at, Operand(scratch));
// The index is assumed to be untagged coming in, tag it to compare with the
// string length without using a temp register, it is restored at the end of
// this function.
Label index_tag_ok, index_tag_bad;
// On ARM TrySmiTag is used here.
AdduAndCheckForOverflow(index, index, index, scratch);
BranchOnOverflow(&index_tag_bad, scratch);
Branch(&index_tag_ok);
bind(&index_tag_bad);
Throw(kIndexIsTooLarge);
bind(&index_tag_ok);
lw(at, FieldMemOperand(string, String::kLengthOffset));
ThrowIf(ge, kIndexIsTooLarge, index, Operand(at));
li(at, Operand(Smi::FromInt(0)));
ThrowIf(lt, kIndexIsNegative, index, Operand(at));
SmiUntag(index, index);
}
void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
int num_double_arguments,
Register scratch) {
......@@ -5431,6 +5469,57 @@ void MacroAssembler::EnsureNotWhite(
}
void MacroAssembler::Throw(BailoutReason reason) {
Label throw_start;
bind(&throw_start);
#ifdef DEBUG
const char* msg = GetBailoutReason(reason);
if (msg != NULL) {
RecordComment("Throw message: ");
RecordComment(msg);
}
#endif
li(a0, Operand(Smi::FromInt(reason)));
push(a0);
// Disable stub call restrictions to always allow calls to throw.
if (!has_frame_) {
// We don't actually want to generate a pile of code for this, so just
// claim there is a stack frame, without generating one.
FrameScope scope(this, StackFrame::NONE);
CallRuntime(Runtime::kThrowMessage, 1);
} else {
CallRuntime(Runtime::kThrowMessage, 1);
}
// will not return here
if (is_trampoline_pool_blocked()) {
// If the calling code cares throw the exact number of
// instructions generated, we insert padding here to keep the size
// of the ThrowMessage macro constant.
// Currently in debug mode with debug_code enabled the number of
// generated instructions is 14, so we use this as a maximum value.
static const int kExpectedThrowMessageInstructions = 14;
int throw_instructions = InstructionsGeneratedSince(&throw_start);
ASSERT(throw_instructions <= kExpectedThrowMessageInstructions);
while (throw_instructions++ < kExpectedThrowMessageInstructions) {
nop();
}
}
}
void MacroAssembler::ThrowIf(Condition cc,
BailoutReason reason,
Register rs,
Operand rt) {
Label L;
Branch(&L, NegateCondition(cc), rs, rt);
Throw(reason);
// will not return here
bind(&L);
}
void MacroAssembler::LoadInstanceDescriptors(Register map,
Register descriptors) {
lw(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
......
......@@ -967,6 +967,12 @@ class MacroAssembler: public Assembler {
// handler chain.
void ThrowUncatchable(Register value);
// Throw a message string as an exception.
void Throw(BailoutReason reason);
// Throw a message string as an exception if a condition is not true.
void ThrowIf(Condition cc, BailoutReason reason, Register rs, Operand rt);
// Copies a fixed number of fields of heap objects from src to dst.
void CopyFields(Register dst, Register src, RegList temps, int field_count);
......@@ -1452,6 +1458,12 @@ class MacroAssembler: public Assembler {
void JumpIfNotUniqueName(Register reg, Label* not_unique_name);
void EmitSeqStringSetCharCheck(Register string,
Register index,
Register value,
Register scratch,
uint32_t encoding_mask);
// Test that both first and second are sequential ASCII strings.
// Assume that they are non-smis.
void JumpIfNonSmisNotBothSequentialAsciiStrings(Register first,
......
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