mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:09:48 +00:00
[vm] Make OOM during interpreted regex non-fatal.
TEST=manually adjusting ulimit Change-Id: I1c1a9ba583275017cfbd92cd850a8bc33920aac9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/211461 Reviewed-by: Alexander Aprelev <aam@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
eab69f12f8
commit
714e7e6f9e
|
@ -494,8 +494,7 @@ static ObjectPtr ExecRaw(const RegExp& regexp,
|
||||||
TypedData::Handle(zone, regexp.bytecode(is_one_byte, sticky));
|
TypedData::Handle(zone, regexp.bytecode(is_one_byte, sticky));
|
||||||
ASSERT(!bytecode.IsNull());
|
ASSERT(!bytecode.IsNull());
|
||||||
const Object& result = Object::Handle(
|
const Object& result = Object::Handle(
|
||||||
zone,
|
zone, IrregexpInterpreter::Match(bytecode, subject, raw_output, index));
|
||||||
IrregexpInterpreter::Match(bytecode, subject, raw_output, index, zone));
|
|
||||||
|
|
||||||
if (result.ptr() == Bool::True().ptr()) {
|
if (result.ptr() == Bool::True().ptr()) {
|
||||||
// Copy capture results to the start of the registers array.
|
// Copy capture results to the start of the registers array.
|
||||||
|
@ -503,11 +502,7 @@ static ObjectPtr ExecRaw(const RegExp& regexp,
|
||||||
}
|
}
|
||||||
if (result.ptr() == Object::null()) {
|
if (result.ptr() == Object::null()) {
|
||||||
// Exception during regexp processing
|
// Exception during regexp processing
|
||||||
Thread* thread = Thread::Current();
|
Exceptions::ThrowStackOverflow();
|
||||||
auto isolate_group = thread->isolate_group();
|
|
||||||
const Instance& exception =
|
|
||||||
Instance::Handle(isolate_group->object_store()->stack_overflow());
|
|
||||||
Exceptions::Throw(thread, exception);
|
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
return result.ptr();
|
return result.ptr();
|
||||||
|
|
|
@ -135,7 +135,7 @@ static int32_t Load16Aligned(const uint8_t* pc) {
|
||||||
// matching terminates.
|
// matching terminates.
|
||||||
class BacktrackStack {
|
class BacktrackStack {
|
||||||
public:
|
public:
|
||||||
explicit BacktrackStack(Zone* zone) {
|
BacktrackStack() {
|
||||||
memory_ = Isolate::Current()->TakeRegexpBacktrackStack();
|
memory_ = Isolate::Current()->TakeRegexpBacktrackStack();
|
||||||
// Note: using malloc here has a potential of triggering jemalloc/tcmalloc
|
// Note: using malloc here has a potential of triggering jemalloc/tcmalloc
|
||||||
// bugs which cause application to leak memory and eventually OOM.
|
// bugs which cause application to leak memory and eventually OOM.
|
||||||
|
@ -147,15 +147,16 @@ class BacktrackStack {
|
||||||
sizeof(intptr_t) * kBacktrackStackSize, /*is_executable=*/false,
|
sizeof(intptr_t) * kBacktrackStackSize, /*is_executable=*/false,
|
||||||
"regexp-backtrack-stack"));
|
"regexp-backtrack-stack"));
|
||||||
}
|
}
|
||||||
if (memory_ == nullptr) {
|
|
||||||
OUT_OF_MEMORY();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~BacktrackStack() {
|
~BacktrackStack() {
|
||||||
Isolate::Current()->CacheRegexpBacktrackStack(std::move(memory_));
|
if (memory_ != nullptr) {
|
||||||
|
Isolate::Current()->CacheRegexpBacktrackStack(std::move(memory_));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool out_of_memory() const { return memory_ == nullptr; }
|
||||||
|
|
||||||
intptr_t* data() const {
|
intptr_t* data() const {
|
||||||
return reinterpret_cast<intptr_t*>(memory_->address());
|
return reinterpret_cast<intptr_t*>(memory_->address());
|
||||||
}
|
}
|
||||||
|
@ -177,13 +178,15 @@ static ObjectPtr RawMatch(const TypedData& bytecode,
|
||||||
const String& subject,
|
const String& subject,
|
||||||
int32_t* registers,
|
int32_t* registers,
|
||||||
intptr_t current,
|
intptr_t current,
|
||||||
uint32_t current_char,
|
uint32_t current_char) {
|
||||||
Zone* zone) {
|
|
||||||
const auto thread = Thread::Current();
|
|
||||||
// BacktrackStack ensures that the memory allocated for the backtracking stack
|
// BacktrackStack ensures that the memory allocated for the backtracking stack
|
||||||
// is returned to the system or cached if there is no stack being cached at
|
// is returned to the system or cached if there is no stack being cached at
|
||||||
// the moment.
|
// the moment.
|
||||||
BacktrackStack backtrack_stack(zone);
|
BacktrackStack backtrack_stack;
|
||||||
|
if (backtrack_stack.out_of_memory()) {
|
||||||
|
Exceptions::ThrowOOM();
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
intptr_t* backtrack_stack_base = backtrack_stack.data();
|
intptr_t* backtrack_stack_base = backtrack_stack.data();
|
||||||
intptr_t* backtrack_sp = backtrack_stack_base;
|
intptr_t* backtrack_sp = backtrack_stack_base;
|
||||||
intptr_t backtrack_stack_space = backtrack_stack.max_size();
|
intptr_t backtrack_stack_space = backtrack_stack.max_size();
|
||||||
|
@ -199,6 +202,7 @@ static ObjectPtr RawMatch(const TypedData& bytecode,
|
||||||
OS::PrintErr("Start irregexp bytecode interpreter\n");
|
OS::PrintErr("Start irregexp bytecode interpreter\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
const auto thread = Thread::Current();
|
||||||
const uint8_t* code_base;
|
const uint8_t* code_base;
|
||||||
const uint8_t* pc;
|
const uint8_t* pc;
|
||||||
{
|
{
|
||||||
|
@ -683,8 +687,7 @@ static ObjectPtr RawMatch(const TypedData& bytecode,
|
||||||
ObjectPtr IrregexpInterpreter::Match(const TypedData& bytecode,
|
ObjectPtr IrregexpInterpreter::Match(const TypedData& bytecode,
|
||||||
const String& subject,
|
const String& subject,
|
||||||
int32_t* registers,
|
int32_t* registers,
|
||||||
intptr_t start_position,
|
intptr_t start_position) {
|
||||||
Zone* zone) {
|
|
||||||
uint16_t previous_char = '\n';
|
uint16_t previous_char = '\n';
|
||||||
if (start_position != 0) {
|
if (start_position != 0) {
|
||||||
previous_char = subject.CharAt(start_position - 1);
|
previous_char = subject.CharAt(start_position - 1);
|
||||||
|
@ -692,10 +695,10 @@ ObjectPtr IrregexpInterpreter::Match(const TypedData& bytecode,
|
||||||
|
|
||||||
if (subject.IsOneByteString() || subject.IsExternalOneByteString()) {
|
if (subject.IsOneByteString() || subject.IsExternalOneByteString()) {
|
||||||
return RawMatch<uint8_t>(bytecode, subject, registers, start_position,
|
return RawMatch<uint8_t>(bytecode, subject, registers, start_position,
|
||||||
previous_char, zone);
|
previous_char);
|
||||||
} else if (subject.IsTwoByteString() || subject.IsExternalTwoByteString()) {
|
} else if (subject.IsTwoByteString() || subject.IsExternalTwoByteString()) {
|
||||||
return RawMatch<uint16_t>(bytecode, subject, registers, start_position,
|
return RawMatch<uint16_t>(bytecode, subject, registers, start_position,
|
||||||
previous_char, zone);
|
previous_char);
|
||||||
} else {
|
} else {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return Bool::False().ptr();
|
return Bool::False().ptr();
|
||||||
|
|
|
@ -21,8 +21,7 @@ class IrregexpInterpreter : public AllStatic {
|
||||||
static ObjectPtr Match(const TypedData& bytecode,
|
static ObjectPtr Match(const TypedData& bytecode,
|
||||||
const String& subject,
|
const String& subject,
|
||||||
int32_t* captures,
|
int32_t* captures,
|
||||||
intptr_t start_position,
|
intptr_t start_position);
|
||||||
Zone* zone);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dart
|
} // namespace dart
|
||||||
|
|
Loading…
Reference in a new issue