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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright 2007-2008 the V8 project authors. All rights reserved. 1 // Copyright 2007-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 5667 matching lines...) Expand 10 before | Expand all | Expand 10 after
5678 context1->Exit(); 5678 context1->Exit();
5679 5679
5680 // Dispose the contexts to allow them to be garbage collected. 5680 // Dispose the contexts to allow them to be garbage collected.
5681 context0.Dispose(); 5681 context0.Dispose();
5682 context1.Dispose(); 5682 context1.Dispose();
5683 } 5683 }
5684 5684
5685 5685
5686 class RegExpInterruptTest { 5686 class RegExpInterruptTest {
5687 public: 5687 public:
5688 RegExpInterruptTest() : block_(NULL) {}
5689 ~RegExpInterruptTest() { delete block_; }
5688 void RunTest() { 5690 void RunTest() {
5689 block_ = i::OS::CreateSemaphore(0); 5691 block_ = i::OS::CreateSemaphore(0);
5690 gc_count_ = 0; 5692 gc_count_ = 0;
5691 gc_during_regexp_ = 0; 5693 gc_during_regexp_ = 0;
5692 regexp_success_ = false; 5694 regexp_success_ = false;
5693 gc_success_ = false; 5695 gc_success_ = false;
5694 GCThread gc_thread(this); 5696 GCThread gc_thread(this);
5695 gc_thread.Start(); 5697 gc_thread.Start();
5696 v8::Locker::StartPreemption(1); 5698 v8::Locker::StartPreemption(1);
5697 5699
5698 LongRunningRegExp(); 5700 LongRunningRegExp();
5699 { 5701 {
5700 v8::Unlocker unlock; 5702 v8::Unlocker unlock;
5701 gc_thread.Join(); 5703 gc_thread.Join();
5702 } 5704 }
5703 v8::Locker::StopPreemption(); 5705 v8::Locker::StopPreemption();
5704 CHECK(regexp_success_); 5706 CHECK(regexp_success_);
5705 CHECK(gc_success_); 5707 CHECK(gc_success_);
5706 } 5708 }
5707 RegExpInterruptTest() : block_(NULL) {}
5708 ~RegExpInterruptTest() { delete block_; }
5709 private: 5709 private:
5710 // Number of garbage collections required. 5710 // Number of garbage collections required.
5711 static const int kRequiredGCs = 5; 5711 static const int kRequiredGCs = 5;
5712 5712
5713 class GCThread : public i::Thread { 5713 class GCThread : public i::Thread {
5714 public: 5714 public:
5715 explicit GCThread(RegExpInterruptTest* test) 5715 explicit GCThread(RegExpInterruptTest* test)
5716 : test_(test) {} 5716 : test_(test) {}
5717 virtual void Run() { 5717 virtual void Run() {
5718 test_->CollectGarbage(); 5718 test_->CollectGarbage();
(...skipping 15 matching lines...) Expand all
5734 } 5734 }
5735 gc_success_ = true; 5735 gc_success_ = true;
5736 } 5736 }
5737 5737
5738 void LongRunningRegExp() { 5738 void LongRunningRegExp() {
5739 block_->Signal(); // Enable garbage collection thread on next preemption. 5739 block_->Signal(); // Enable garbage collection thread on next preemption.
5740 int rounds = 0; 5740 int rounds = 0;
5741 while (gc_during_regexp_ < kRequiredGCs) { 5741 while (gc_during_regexp_ < kRequiredGCs) {
5742 int gc_before = gc_count_; 5742 int gc_before = gc_count_;
5743 { 5743 {
5744 // match 15-30 "a"'s against 14 and a "b". 5744 // Match 15-30 "a"'s against 14 and a "b".
5745 const char* c_source = 5745 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
5746 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" 5746 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
5747 ".exec('aaaaaaaaaaaaaaab') === null"; 5747 ".exec('aaaaaaaaaaaaaaab') === null";
5748 Local<String> source = String::New(c_source); 5748 Local<String> source = String::New(c_source);
5749 Local<Script> script = Script::Compile(source); 5749 Local<Script> script = Script::Compile(source);
5750 Local<Value> result = script->Run(); 5750 Local<Value> result = script->Run();
5751 if (!result->BooleanValue()) { 5751 if (!result->BooleanValue()) {
5752 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit. 5752 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
5753 return; 5753 return;
5754 } 5754 }
5755 } 5755 }
5756 { 5756 {
5757 // match 15-30 "a"'s against 15 and a "b". 5757 // Match 15-30 "a"'s against 15 and a "b".
5758 const char* c_source = 5758 const char* c_source =
5759 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" 5759 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
5760 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'"; 5760 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
5761 Local<String> source = String::New(c_source); 5761 Local<String> source = String::New(c_source);
5762 Local<Script> script = Script::Compile(source); 5762 Local<Script> script = Script::Compile(source);
5763 Local<Value> result = script->Run(); 5763 Local<Value> result = script->Run();
5764 if (!result->BooleanValue()) { 5764 if (!result->BooleanValue()) {
5765 gc_during_regexp_ = kRequiredGCs; 5765 gc_during_regexp_ = kRequiredGCs;
5766 return; 5766 return;
5767 } 5767 }
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
5830 Local<v8::Object> clone = obj->Clone(); 5830 Local<v8::Object> clone = obj->Clone();
5831 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha"))); 5831 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
5832 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta"))); 5832 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
5833 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma"))); 5833 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
5834 5834
5835 // Set a property on the clone, verify each object. 5835 // Set a property on the clone, verify each object.
5836 clone->Set(v8_str("beta"), v8::Integer::New(456)); 5836 clone->Set(v8_str("beta"), v8::Integer::New(456));
5837 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta"))); 5837 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
5838 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta"))); 5838 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
5839 } 5839 }
5840
5841
5842 class RegExpStringModificationTest {
5843 public:
5844 RegExpStringModificationTest()
5845 : two_byte_content_(),
5846 block_(i::OS::CreateSemaphore(0)),
5847 morphs_(0),
5848 morphs_during_regexp_(0),
5849 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
5850 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
5851 ~RegExpStringModificationTest() { delete block_; }
5852 void RunTest() {
5853 regexp_success_ = false;
5854 morph_success_ = false;
5855
5856 for (int i = 0; i < 14; i++) {
5857 two_byte_content_[i] = 'a';
5858 }
5859 two_byte_content_[14] = 'b';
5860
5861 // Create the input string for the regexp - the one we are going to change
5862 // properties of.
5863 input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
5864
5865 // Inject the input as a global variable.
5866 i::Handle<i::String> input_name =
5867 i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
5868 i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
5869
5870
5871 MorphThread morph_thread(this);
5872 morph_thread.Start();
5873 v8::Locker::StartPreemption(1);
5874 LongRunningRegExp();
5875 {
5876 v8::Unlocker unlock;
5877 morph_thread.Join();
5878 }
5879 v8::Locker::StopPreemption();
5880 CHECK(regexp_success_);
5881 CHECK(morph_success_);
5882 }
5883 private:
5884
5885 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
5886 public:
5887 explicit AsciiVectorResource(i::Vector<const char> vector)
5888 : data_(vector) {}
5889 virtual ~AsciiVectorResource() {}
5890 virtual size_t length() const { return data_.length(); }
5891 virtual const char* data() const { return data_.start(); }
5892 private:
5893 i::Vector<const char> data_;
5894 };
5895 class UC16VectorResource : public v8::String::ExternalStringResource {
5896 public:
5897 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
5898 : data_(vector) {}
5899 virtual ~UC16VectorResource() {}
5900 virtual size_t length() const { return data_.length(); }
5901 virtual const i::uc16* data() const { return data_.start(); }
5902 private:
5903 i::Vector<const i::uc16> data_;
5904 };
5905 // Number of string modifications required.
5906 static const int kRequiredModifications = 5;
5907 static const int kMaxModifications = 100;
5908
5909 class MorphThread : public i::Thread {
5910 public:
5911 explicit MorphThread(RegExpStringModificationTest* test)
5912 : test_(test) {}
5913 virtual void Run() {
5914 test_->MorphString();
5915 }
5916 private:
5917 RegExpStringModificationTest* test_;
5918 };
5919
5920 void MorphString() {
5921 block_->Wait();
5922 while (morphs_during_regexp_ < kRequiredModifications &&
5923 morphs_ < kMaxModifications) {
5924 {
5925 v8::Locker lock;
5926 // Swap string between ascii and two-byte representation.
5927 i::String* string = *input_;
5928 CHECK(i::StringShape(string).IsExternal());
5929 if (i::StringShape(string).IsAsciiRepresentation()) {
5930 // Morph external string to be TwoByte string.
5931 i::ExternalAsciiString* ext_string =
5932 i::ExternalAsciiString::cast(string);
5933 i::ExternalTwoByteString* morphed =
5934 reinterpret_cast<i::ExternalTwoByteString*>(ext_string);
5935 morphed->map()->set_instance_type(i::SHORT_EXTERNAL_STRING_TYPE);
5936 morphed->set_resource(&uc16_resource_);
5937 } else {
5938 // Morph external string to be ASCII string.
5939 i::ExternalTwoByteString* ext_string =
5940 i::ExternalTwoByteString::cast(string);
5941 i::ExternalAsciiString* morphed =
5942 reinterpret_cast<i::ExternalAsciiString*>(ext_string);
5943 morphed->map()->set_instance_type(
5944 i::SHORT_EXTERNAL_ASCII_STRING_TYPE);
5945 morphed->set_resource(&ascii_resource_);
5946 }
5947 morphs_++;
5948 }
5949 i::OS::Sleep(1);
5950 }
5951 morph_success_ = true;
5952 }
5953
5954 void LongRunningRegExp() {
5955 block_->Signal(); // Enable morphing thread on next preemption.
5956 while (morphs_during_regexp_ < kRequiredModifications &&
5957 morphs_ < kMaxModifications) {
5958 int morphs_before = morphs_;
5959 {
5960 // Match 15-30 "a"'s against 14 and a "b".
Erik Corry 2009/03/20 12:45:42 14 "a"s
5961 const char* c_source =
5962 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
5963 ".exec(input) === null";
5964 Local<String> source = String::New(c_source);
5965 Local<Script> script = Script::Compile(source);
5966 Local<Value> result = script->Run();
5967 CHECK(result->IsTrue());
5968 }
5969 int morphs_after = morphs_;
5970 morphs_during_regexp_ += morphs_after - morphs_before;
5971 }
5972 regexp_success_ = true;
5973 }
5974
5975 i::uc16 two_byte_content_[15];
5976 i::Semaphore* block_;
5977 int morphs_;
5978 int morphs_during_regexp_;
5979 bool regexp_success_;
5980 bool morph_success_;
5981 i::Handle<i::String> input_;
5982 AsciiVectorResource ascii_resource_;
5983 UC16VectorResource uc16_resource_;
5984 };
5985
5986
5987 // Test that a regular expression execution can be interrupted and
5988 // the string changed without failing.
5989 TEST(RegExpStringModification) {
5990 v8::Locker lock;
5991 v8::V8::Initialize();
5992 v8::HandleScope scope;
5993 Local<Context> local_env;
5994 {
5995 LocalContext env;
5996 local_env = env.local();
5997 }
5998
5999 // Local context should still be live.
6000 CHECK(!local_env.IsEmpty());
6001 local_env->Enter();
6002
6003 // Should complete without problems.
6004 RegExpStringModificationTest().RunTest();
6005
6006 local_env->Exit();
6007 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698