Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(953)

Unified Diff: test/cctest/test-api.cc

Issue 42441: Made regexp robust against changes to a string's implementation. (Closed)
Patch Set: Removed unused addition to memory.h Created 11 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: test/cctest/test-api.cc
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 428b6365b95783fe70a20d2253a9aa12e162a766..f4ed084ca627b7aaed9d470b53513ec45ad985c0 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -5685,6 +5685,8 @@ THREADED_TEST(CrossContextNew) {
class RegExpInterruptTest {
public:
+ RegExpInterruptTest() : block_(NULL) {}
+ ~RegExpInterruptTest() { delete block_; }
void RunTest() {
block_ = i::OS::CreateSemaphore(0);
gc_count_ = 0;
@@ -5704,8 +5706,6 @@ class RegExpInterruptTest {
CHECK(regexp_success_);
CHECK(gc_success_);
}
- RegExpInterruptTest() : block_(NULL) {}
- ~RegExpInterruptTest() { delete block_; }
private:
// Number of garbage collections required.
static const int kRequiredGCs = 5;
@@ -5741,7 +5741,7 @@ class RegExpInterruptTest {
while (gc_during_regexp_ < kRequiredGCs) {
int gc_before = gc_count_;
{
- // match 15-30 "a"'s against 14 and a "b".
+ // Match 15-30 "a"'s against 14 and a "b".
const char* c_source =
Erik Corry 2009/03/20 12:45:42 It would be nice to test GC during execution of a
Lasse Reichstein 2009/03/20 13:26:11 Are they more likely to fail? In any case, that wo
"/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
".exec('aaaaaaaaaaaaaaab') === null";
@@ -5754,7 +5754,7 @@ class RegExpInterruptTest {
}
}
{
- // match 15-30 "a"'s against 15 and a "b".
+ // Match 15-30 "a"'s against 15 and a "b".
const char* c_source =
"/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
@@ -5837,3 +5837,171 @@ TEST(ObjectClone) {
CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
}
+
+
+class RegExpStringModificationTest {
+ public:
+ RegExpStringModificationTest()
+ : two_byte_content_(),
+ block_(i::OS::CreateSemaphore(0)),
+ morphs_(0),
+ morphs_during_regexp_(0),
+ ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
+ uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
+ ~RegExpStringModificationTest() { delete block_; }
+ void RunTest() {
+ regexp_success_ = false;
+ morph_success_ = false;
+
+ for (int i = 0; i < 14; i++) {
+ two_byte_content_[i] = 'a';
+ }
+ two_byte_content_[14] = 'b';
+
+ // Create the input string for the regexp - the one we are going to change
+ // properties of.
+ input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
+
+ // Inject the input as a global variable.
+ i::Handle<i::String> input_name =
+ i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
+ i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
+
+
+ MorphThread morph_thread(this);
+ morph_thread.Start();
+ v8::Locker::StartPreemption(1);
+ LongRunningRegExp();
+ {
+ v8::Unlocker unlock;
+ morph_thread.Join();
+ }
+ v8::Locker::StopPreemption();
+ CHECK(regexp_success_);
+ CHECK(morph_success_);
+ }
+ private:
+
+ class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
+ public:
+ explicit AsciiVectorResource(i::Vector<const char> vector)
+ : data_(vector) {}
+ virtual ~AsciiVectorResource() {}
+ virtual size_t length() const { return data_.length(); }
+ virtual const char* data() const { return data_.start(); }
+ private:
+ i::Vector<const char> data_;
+ };
+ class UC16VectorResource : public v8::String::ExternalStringResource {
+ public:
+ explicit UC16VectorResource(i::Vector<const i::uc16> vector)
+ : data_(vector) {}
+ virtual ~UC16VectorResource() {}
+ virtual size_t length() const { return data_.length(); }
+ virtual const i::uc16* data() const { return data_.start(); }
+ private:
+ i::Vector<const i::uc16> data_;
+ };
+ // Number of string modifications required.
+ static const int kRequiredModifications = 5;
+ static const int kMaxModifications = 100;
+
+ class MorphThread : public i::Thread {
+ public:
+ explicit MorphThread(RegExpStringModificationTest* test)
+ : test_(test) {}
+ virtual void Run() {
+ test_->MorphString();
+ }
+ private:
+ RegExpStringModificationTest* test_;
+ };
+
+ void MorphString() {
+ block_->Wait();
+ while (morphs_during_regexp_ < kRequiredModifications &&
+ morphs_ < kMaxModifications) {
+ {
+ v8::Locker lock;
+ // Swap string between ascii and two-byte representation.
+ i::String* string = *input_;
+ CHECK(i::StringShape(string).IsExternal());
+ if (i::StringShape(string).IsAsciiRepresentation()) {
+ // Morph external string to be TwoByte string.
+ i::ExternalAsciiString* ext_string =
+ i::ExternalAsciiString::cast(string);
+ i::ExternalTwoByteString* morphed =
+ reinterpret_cast<i::ExternalTwoByteString*>(ext_string);
+ morphed->map()->set_instance_type(i::SHORT_EXTERNAL_STRING_TYPE);
+ morphed->set_resource(&uc16_resource_);
+ } else {
+ // Morph external string to be ASCII string.
+ i::ExternalTwoByteString* ext_string =
+ i::ExternalTwoByteString::cast(string);
+ i::ExternalAsciiString* morphed =
+ reinterpret_cast<i::ExternalAsciiString*>(ext_string);
+ morphed->map()->set_instance_type(
+ i::SHORT_EXTERNAL_ASCII_STRING_TYPE);
+ morphed->set_resource(&ascii_resource_);
+ }
+ morphs_++;
+ }
+ i::OS::Sleep(1);
+ }
+ morph_success_ = true;
+ }
+
+ void LongRunningRegExp() {
+ block_->Signal(); // Enable morphing thread on next preemption.
+ while (morphs_during_regexp_ < kRequiredModifications &&
+ morphs_ < kMaxModifications) {
+ int morphs_before = morphs_;
+ {
+ // Match 15-30 "a"'s against 14 and a "b".
Erik Corry 2009/03/20 12:45:42 14 "a"s
+ const char* c_source =
+ "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
+ ".exec(input) === null";
+ Local<String> source = String::New(c_source);
+ Local<Script> script = Script::Compile(source);
+ Local<Value> result = script->Run();
+ CHECK(result->IsTrue());
+ }
+ int morphs_after = morphs_;
+ morphs_during_regexp_ += morphs_after - morphs_before;
+ }
+ regexp_success_ = true;
+ }
+
+ i::uc16 two_byte_content_[15];
+ i::Semaphore* block_;
+ int morphs_;
+ int morphs_during_regexp_;
+ bool regexp_success_;
+ bool morph_success_;
+ i::Handle<i::String> input_;
+ AsciiVectorResource ascii_resource_;
+ UC16VectorResource uc16_resource_;
+};
+
+
+// Test that a regular expression execution can be interrupted and
+// the string changed without failing.
+TEST(RegExpStringModification) {
+ v8::Locker lock;
+ v8::V8::Initialize();
+ v8::HandleScope scope;
+ Local<Context> local_env;
+ {
+ LocalContext env;
+ local_env = env.local();
+ }
+
+ // Local context should still be live.
+ CHECK(!local_env.IsEmpty());
+ local_env->Enter();
+
+ // Should complete without problems.
+ RegExpStringModificationTest().RunTest();
+
+ local_env->Exit();
+}

Powered by Google App Engine
This is Rietveld 408576698