Commit 6e13e8ce authored by lrn@chromium.org's avatar lrn@chromium.org

Parsing a RegExp decimal escape could overflow, making an otherwise too large

decimal escape be accepted as a capture index.
We introduce a limit on the nubmer of allowed captures in a regexp, and break off
parsing of the decimal escape at that point.


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1189 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent dd2051ca
......@@ -537,8 +537,10 @@ class RegExpParser {
int position() { return next_pos_ - 1; }
bool failed() { return failed_; }
static const int kMaxCaptures = 1 << 16;
static const uc32 kEndMarker = (1 << 21);
private:
uc32 current() { return current_; }
bool has_more() { return has_more_; }
bool has_next() { return next_pos_ < in()->length(); }
......@@ -3891,11 +3893,8 @@ void RegExpParser::ScanForCaptures() {
bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
ASSERT_EQ('\\', current());
ASSERT('1' <= Next() && Next() <= '9');
// Try to parse a decimal literal that is no greater than the number
// of previously encountered left capturing parentheses.
// This is a not according the the ECMAScript specification. According to
// that, one must accept values up to the total number of left capturing
// parentheses in the entire input, even if they are meaningless.
// Try to parse a decimal literal that is no greater than the total number
// of left capturing parentheses in the input.
int start = position();
int value = Next() - '0';
Advance(2);
......@@ -3903,6 +3902,10 @@ bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
uc32 c = current();
if (IsDecimalDigit(c)) {
value = 10 * value + (c - '0');
if (value > kMaxCaptures) {
Reset(start);
return false;
}
Advance();
} else {
break;
......@@ -4115,6 +4118,9 @@ RegExpTree* RegExpParser::ParseGroup() {
if (captures_ == NULL) {
captures_ = new ZoneList<RegExpCapture*>(2);
}
if (captures_started() >= kMaxCaptures) {
ReportError(CStrVector("Too many captures") CHECK_FAILED);
}
captures_->Add(NULL);
}
int capture_index = captures_started();
......
......@@ -31,6 +31,7 @@
#include "v8.h"
#include "string-stream.h"
#include "cctest.h"
#include "zone-inl.h"
#include "parser.h"
......@@ -371,6 +372,17 @@ TEST(Errors) {
ExpectError("{1}", kNothingToRepeat);
ExpectError("{1,2}", kNothingToRepeat);
ExpectError("{1,}", kNothingToRepeat);
// Check that we don't allow more than kMaxCapture captures
const int kMaxCaptures = 1 << 16; // Must match RegExpParser::kMaxCaptures.
const char* kTooManyCaptures = "Too many captures";
HeapStringAllocator allocator;
StringStream accumulator(&allocator);
for (int i = 0; i <= kMaxCaptures; i++) {
accumulator.Add("()");
}
SmartPointer<const char> many_captures(accumulator.ToCString());
ExpectError(*many_captures, kTooManyCaptures);
}
......
......@@ -303,6 +303,12 @@ for (var i = 0; i < 128; i++) {
assertFalse(/f(o)$\1/.test('foo'), "backref detects at_end");
// Check decimal escapes doesn't overflow.
assertEquals(/\2147483648/.exec("\x8c7483648"),
["\x8c7483648"],
"Overflow decimal escape");
// Check that we don't read past the end of the string.
assertFalse(/f/.test('b'));
assertFalse(/[abc]f/.test('x'));
......
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