}
-// If an object given is an external string, check that the underlying
-// resource is accessible. For other kinds of objects, always return true.
-static bool IsExternalStringValid(Object* str) {
- if (!str->IsString() || !StringShape(String::cast(str)).IsExternal()) {
- return true;
- }
- if (String::cast(str)->IsAsciiRepresentation()) {
- return ExternalAsciiString::cast(str)->resource() != NULL;
- } else if (String::cast(str)->IsTwoByteRepresentation()) {
- return ExternalTwoByteString::cast(str)->resource() != NULL;
- } else {
- return true;
- }
-}
-
-
void Debug::CreateScriptCache() {
HandleScope scope;
while (iterator.has_next()) {
HeapObject* obj = iterator.next();
ASSERT(obj != NULL);
- if (obj->IsScript() && IsExternalStringValid(Script::cast(obj)->source())) {
+ if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
script_cache_->Add(Handle<Script>(Script::cast(obj)));
count++;
}
}
-void Logger::LogCompiledFunctions() {
- HandleScope scope;
- Handle<SharedFunctionInfo>* sfis = NULL;
+static int EnumerateCompiledFunctions(Handle<SharedFunctionInfo>* sfis) {
+ AssertNoAllocation no_alloc;
int compiled_funcs_count = 0;
-
- {
- AssertNoAllocation no_alloc;
-
- HeapIterator iterator;
- while (iterator.has_next()) {
- HeapObject* obj = iterator.next();
- ASSERT(obj != NULL);
- if (obj->IsSharedFunctionInfo()
- && SharedFunctionInfo::cast(obj)->is_compiled()) {
- ++compiled_funcs_count;
- }
+ HeapIterator iterator;
+ while (iterator.has_next()) {
+ HeapObject* obj = iterator.next();
+ ASSERT(obj != NULL);
+ if (!obj->IsSharedFunctionInfo()) continue;
+ SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
+ if (sfi->is_compiled()
+ && (!sfi->script()->IsScript()
+ || Script::cast(sfi->script())->HasValidSource())) {
+ if (sfis != NULL)
+ sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi);
+ ++compiled_funcs_count;
}
+ }
+ return compiled_funcs_count;
+}
- sfis = NewArray< Handle<SharedFunctionInfo> >(compiled_funcs_count);
- iterator.reset();
- int i = 0;
- while (iterator.has_next()) {
- HeapObject* obj = iterator.next();
- ASSERT(obj != NULL);
- if (obj->IsSharedFunctionInfo()
- && SharedFunctionInfo::cast(obj)->is_compiled()) {
- sfis[i++] = Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(obj));
- }
- }
- }
+void Logger::LogCompiledFunctions() {
+ HandleScope scope;
+ const int compiled_funcs_count = EnumerateCompiledFunctions(NULL);
+ Handle<SharedFunctionInfo>* sfis =
+ NewArray< Handle<SharedFunctionInfo> >(compiled_funcs_count);
+ EnumerateCompiledFunctions(sfis);
// During iteration, there can be heap allocation due to
// GetScriptLineNumber call.
kThisPropertyAssignmentsCountOffset)
+bool Script::HasValidSource() {
+ Object* src = this->source();
+ if (!src->IsString()) return true;
+ String* src_str = String::cast(src);
+ if (!StringShape(src_str).IsExternal()) return true;
+ if (src_str->IsAsciiRepresentation()) {
+ return ExternalAsciiString::cast(src)->resource() != NULL;
+ } else if (src_str->IsTwoByteRepresentation()) {
+ return ExternalTwoByteString::cast(src)->resource() != NULL;
+ }
+ return true;
+}
+
+
void SharedFunctionInfo::DontAdaptArguments() {
ASSERT(code()->kind() == Code::BUILTIN);
set_formal_parameter_count(kDontAdaptArgumentsSentinel);
static inline Script* cast(Object* obj);
+ // If script source is an external string, check that the underlying
+ // resource is accessible. Otherwise, always return true.
+ inline bool HasValidSource();
+
#ifdef DEBUG
void ScriptPrint();
void ScriptVerify();
#endif // __linux__
+// Test for issue http://crbug.com/23768 in Chromium.
+// Heap can contain scripts with already disposed external sources.
+// We need to verify that LogCompiledFunctions doesn't crash on them.
+namespace {
+
+class SimpleExternalString : public v8::String::ExternalStringResource {
+ public:
+ explicit SimpleExternalString(const char* source)
+ : utf_source_(strlen(source)) {
+ for (int i = 0; i < utf_source_.length(); ++i)
+ utf_source_[i] = source[i];
+ }
+ virtual ~SimpleExternalString() {}
+ virtual size_t length() const { return utf_source_.length(); }
+ virtual const uint16_t* data() const { return utf_source_.start(); }
+ private:
+ i::ScopedVector<uint16_t> utf_source_;
+};
+
+} // namespace
+
+TEST(Issue23768) {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ SimpleExternalString source_ext_str("(function ext() {})();");
+ v8::Local<v8::String> source = v8::String::NewExternal(&source_ext_str);
+ // Script needs to have a name in order to trigger InitLineEnds execution.
+ v8::Handle<v8::String> origin = v8::String::New("issue-23768-test");
+ v8::Handle<v8::Script> evil_script = v8::Script::Compile(source, origin);
+ CHECK(!evil_script.IsEmpty());
+ CHECK(!evil_script->Run().IsEmpty());
+ i::Handle<i::ExternalTwoByteString> i_source(
+ i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
+ // This situation can happen if source was an external string disposed
+ // by its owner.
+ i_source->set_resource(NULL);
+
+ // Must not crash.
+ i::Logger::LogCompiledFunctions();
+}
+
+
static inline bool IsStringEqualTo(const char* r, const char* s) {
return strncmp(r, s, strlen(r)) == 0;
}