From 8aae1b3096eb4e810231a7c23f6771d1f1a19400 Mon Sep 17 00:00:00 2001 From: yangguo Date: Wed, 11 Feb 2015 02:21:18 -0800 Subject: [PATCH] Throw on range error when creating a string via API. R=jkummerow@chromium.org BUG=v8:3853 LOG=Y Review URL: https://codereview.chromium.org/867373003 Cr-Commit-Position: refs/heads/master@{#26574} --- include/v8.h | 7 ++-- src/api.cc | 12 ++++--- test/cctest/test-api.cc | 33 +++++++++++++++++++ test/cctest/test-thread-termination.cc | 59 ++++++++++++++++++---------------- 4 files changed, 74 insertions(+), 37 deletions(-) diff --git a/include/v8.h b/include/v8.h index 6f4268f..de2e733 100644 --- a/include/v8.h +++ b/include/v8.h @@ -2133,10 +2133,9 @@ class V8_EXPORT String : public Name { enum NewStringType { kNormalString, kInternalizedString }; /** Allocates a new string from UTF-8 data.*/ - static Local NewFromUtf8(Isolate* isolate, - const char* data, - NewStringType type = kNormalString, - int length = -1); + static Local NewFromUtf8(Isolate* isolate, const char* data, + NewStringType type = kNormalString, + int length = -1); /** Allocates a new string from Latin-1 data.*/ static Local NewFromOneByte( diff --git a/src/api.cc b/src/api.cc index 8716b4a..f2fffa2 100644 --- a/src/api.cc +++ b/src/api.cc @@ -5431,17 +5431,19 @@ inline Local NewString(Isolate* v8_isolate, String::NewStringType type, int length) { i::Isolate* isolate = reinterpret_cast(v8_isolate); + ON_BAILOUT(isolate, location, return Local()); LOG_API(isolate, env); if (length == 0) { return String::Empty(v8_isolate); } ENTER_V8(isolate); if (length == -1) length = StringLength(data); - // We do not expect this to fail. Change this if it does. - i::Handle result = NewString( - isolate->factory(), - type, - i::Vector(data, length)).ToHandleChecked(); + EXCEPTION_PREAMBLE(isolate); + i::Handle result; + has_pending_exception = + !NewString(isolate->factory(), type, i::Vector(data, length)) + .ToHandle(&result); + EXCEPTION_BAILOUT_CHECK(isolate, Local()); return Utils::ToLocal(result); } diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 95a64a9..f1593fe 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -21914,3 +21914,36 @@ TEST(StreamingScriptWithSourceMappingURLInTheMiddle) { RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL, "bar2.js"); } + + +TEST(NewStringRangeError) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext env; + const int length = i::String::kMaxLength + 1; + const int buffer_size = length * sizeof(uint16_t); + void* buffer = malloc(buffer_size); + memset(buffer, 'A', buffer_size); + { + v8::TryCatch try_catch; + char* data = reinterpret_cast(buffer); + CHECK(v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString, + length).IsEmpty()); + CHECK(try_catch.HasCaught()); + } + { + v8::TryCatch try_catch; + uint8_t* data = reinterpret_cast(buffer); + CHECK(v8::String::NewFromOneByte(isolate, data, v8::String::kNormalString, + length).IsEmpty()); + CHECK(try_catch.HasCaught()); + } + { + v8::TryCatch try_catch; + uint16_t* data = reinterpret_cast(buffer); + CHECK(v8::String::NewFromTwoByte(isolate, data, v8::String::kNormalString, + length).IsEmpty()); + CHECK(try_catch.HasCaught()); + } + free(buffer); +} diff --git a/test/cctest/test-thread-termination.cc b/test/cctest/test-thread-termination.cc index 21d3b95..d31b413 100644 --- a/test/cctest/test-thread-termination.cc +++ b/test/cctest/test-thread-termination.cc @@ -270,31 +270,23 @@ TEST(TerminateLoadICException) { } +v8::Persistent reenter_script_1; +v8::Persistent reenter_script_2; + void ReenterAfterTermination(const v8::FunctionCallbackInfo& args) { v8::TryCatch try_catch; - CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate())); - v8::Script::Compile(v8::String::NewFromUtf8(args.GetIsolate(), - "function f() {" - " var term = true;" - " try {" - " while(true) {" - " if (term) terminate();" - " term = false;" - " }" - " fail();" - " } catch(e) {" - " fail();" - " }" - "}" - "f()"))->Run(); + v8::Isolate* isolate = args.GetIsolate(); + CHECK(!v8::V8::IsExecutionTerminating(isolate)); + v8::Local script = + v8::Local::New(isolate, reenter_script_1); + v8::Script::Compile(script)->Run(); CHECK(try_catch.HasCaught()); CHECK(try_catch.Exception()->IsNull()); CHECK(try_catch.Message().IsEmpty()); CHECK(!try_catch.CanContinue()); - CHECK(v8::V8::IsExecutionTerminating(args.GetIsolate())); - v8::Script::Compile(v8::String::NewFromUtf8(args.GetIsolate(), - "function f() { fail(); } f()")) - ->Run(); + CHECK(v8::V8::IsExecutionTerminating(isolate)); + script = v8::Local::New(isolate, reenter_script_2); + v8::Script::Compile(script)->Run(); } @@ -309,17 +301,28 @@ TEST(TerminateAndReenterFromThreadItself) { v8::Context::New(isolate, NULL, global); v8::Context::Scope context_scope(context); CHECK(!v8::V8::IsExecutionTerminating()); - v8::Handle source = v8::String::NewFromUtf8( - isolate, "try { loop(); fail(); } catch(e) { fail(); }"); - v8::Script::Compile(source)->Run(); + // Create script strings upfront as it won't work when terminating. + reenter_script_1.Reset(isolate, v8_str( + "function f() {" + " var term = true;" + " try {" + " while(true) {" + " if (term) terminate();" + " term = false;" + " }" + " fail();" + " } catch(e) {" + " fail();" + " }" + "}" + "f()")); + reenter_script_2.Reset(isolate, v8_str("function f() { fail(); } f()")); + CompileRun("try { loop(); fail(); } catch(e) { fail(); }"); CHECK(!v8::V8::IsExecutionTerminating(isolate)); // Check we can run JS again after termination. - CHECK(v8::Script::Compile( - v8::String::NewFromUtf8(isolate, - "function f() { return true; }" - "f()")) - ->Run() - ->IsTrue()); + CHECK(CompileRun("function f() { return true; } f()")->IsTrue()); + reenter_script_1.Reset(); + reenter_script_2.Reset(); } -- 2.7.4