diff --git a/SOURCES/v8-Apply-REPLACE_INVALID_UTF8-patch.patch b/SOURCES/v8-Apply-REPLACE_INVALID_UTF8-patch.patch new file mode 100644 index 0000000..d6ee436 --- /dev/null +++ b/SOURCES/v8-Apply-REPLACE_INVALID_UTF8-patch.patch @@ -0,0 +1,221 @@ +From 881ac26f27f4ac9585d66c8d8a67d5b246a23d1b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Felix=20Geisendo=CC=88rfer?= +Date: Mon, 20 Jan 2014 09:43:43 +0100 +Subject: [PATCH] deps/v8: Apply REPLACE_INVALID_UTF8 patch + +- https://codereview.chromium.org/121173009/ +- https://code.google.com/p/v8/source/detail?r=18683 + +Note: The v8 test case did not cleanly apply, so it's missing from this +patch. I'm assuming this is not a problem if the v8 test suite is not +part of the node build / test system. If that's the case I'll fix it. +Otherwise the test case will be integrated once v8 is upgraded. +--- + include/v8.h | 6 +++++- + src/api.cc | 35 +++++++++++++++++++++++++---------- + src/unicode-inl.h | 15 +++++++++++---- + src/unicode.h | 16 ++++++++++++++-- + 4 files changed, 55 insertions(+), 17 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 470661e..71a0d01 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -1076,7 +1076,11 @@ class String : public Primitive { + NO_OPTIONS = 0, + HINT_MANY_WRITES_EXPECTED = 1, + NO_NULL_TERMINATION = 2, +- PRESERVE_ASCII_NULL = 4 ++ PRESERVE_ASCII_NULL = 4, ++ // Used by WriteUtf8 to replace orphan surrogate code units with the ++ // unicode replacement character. Needs to be set to guarantee valid UTF-8 ++ // output. ++ REPLACE_INVALID_UTF8 = 8 + }; + + // 16-bit character codes. +diff --git a/src/api.cc b/src/api.cc +index f168398..96d564f 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -3759,7 +3759,8 @@ static int RecursivelySerializeToUtf8(i::String* string, + int end, + int recursion_budget, + int32_t previous_character, +- int32_t* last_character) { ++ int32_t* last_character, ++ bool replace_invalid_utf8) { + int utf8_bytes = 0; + while (true) { + if (string->IsAsciiRepresentation()) { +@@ -3775,7 +3776,10 @@ static int RecursivelySerializeToUtf8(i::String* string, + for (int i = start; i < end; i++) { + uint16_t character = data[i]; + current += +- unibrow::Utf8::Encode(current, character, previous_character); ++ unibrow::Utf8::Encode(current, ++ character, ++ previous_character, ++ replace_invalid_utf8); + previous_character = character; + } + *last_character = previous_character; +@@ -3788,7 +3792,10 @@ static int RecursivelySerializeToUtf8(i::String* string, + for (int i = start; i < end; i++) { + uint16_t character = data[i]; + current += +- unibrow::Utf8::Encode(current, character, previous_character); ++ unibrow::Utf8::Encode(current, ++ character, ++ previous_character, ++ replace_invalid_utf8); + previous_character = character; + } + *last_character = previous_character; +@@ -3824,7 +3831,8 @@ static int RecursivelySerializeToUtf8(i::String* string, + boundary, + recursion_budget - 1, + previous_character, +- &previous_character); ++ &previous_character, ++ replace_invalid_utf8); + if (extra_utf8_bytes < 0) return extra_utf8_bytes; + buffer += extra_utf8_bytes; + utf8_bytes += extra_utf8_bytes; +@@ -3879,7 +3887,10 @@ int String::WriteUtf8(char* buffer, + return len; + } + +- if (capacity == -1 || capacity / 3 >= string_length) { ++ bool replace_invalid_utf8 = (options & REPLACE_INVALID_UTF8); ++ int max16BitCodeUnitSize = unibrow::Utf8::kMax16BitCodeUnitSize; ++ ++ if (capacity == -1 || capacity / max16BitCodeUnitSize >= string_length) { + int32_t previous = unibrow::Utf16::kNoPreviousCharacter; + const int kMaxRecursion = 100; + int utf8_bytes = +@@ -3889,7 +3900,8 @@ int String::WriteUtf8(char* buffer, + string_length, + kMaxRecursion, + previous, +- &previous); ++ &previous, ++ replace_invalid_utf8); + if (utf8_bytes >= 0) { + // Success serializing with recursion. + if ((options & NO_NULL_TERMINATION) == 0 && +@@ -3942,14 +3954,16 @@ int String::WriteUtf8(char* buffer, + char intermediate[unibrow::Utf8::kMaxEncodedSize]; + for (; i < len && pos < capacity; i++) { + i::uc32 c = write_input_buffer.GetNext(); +- if (unibrow::Utf16::IsTrailSurrogate(c) && +- unibrow::Utf16::IsLeadSurrogate(previous)) { ++ if (unibrow::Utf16::IsSurrogatePair(previous, c)) { + // We can't use the intermediate buffer here because the encoding + // of surrogate pairs is done under assumption that you can step + // back and fix the UTF8 stream. Luckily we only need space for one + // more byte, so there is always space. + ASSERT(pos < capacity); +- int written = unibrow::Utf8::Encode(buffer + pos, c, previous); ++ int written = unibrow::Utf8::Encode(buffer + pos, ++ c, ++ previous, ++ replace_invalid_utf8); + ASSERT(written == 1); + pos += written; + nchars++; +@@ -3957,7 +3971,8 @@ int String::WriteUtf8(char* buffer, + int written = + unibrow::Utf8::Encode(intermediate, + c, +- unibrow::Utf16::kNoPreviousCharacter); ++ unibrow::Utf16::kNoPreviousCharacter, ++ replace_invalid_utf8); + if (pos + written <= capacity) { + for (int j = 0; j < written; j++) { + buffer[pos + j] = intermediate[j]; +diff --git a/src/unicode-inl.h b/src/unicode-inl.h +index ec9c69f..3f54a5b 100644 +--- a/src/unicode-inl.h ++++ b/src/unicode-inl.h +@@ -79,7 +79,10 @@ template int Mapping::CalculateValue(uchar c, uchar n, + } + + +-unsigned Utf8::Encode(char* str, uchar c, int previous) { ++unsigned Utf8::Encode(char* str, ++ uchar c, ++ int previous, ++ bool replace_invalid) { + static const int kMask = ~(1 << 6); + if (c <= kMaxOneByteChar) { + str[0] = c; +@@ -89,12 +92,16 @@ unsigned Utf8::Encode(char* str, uchar c, int previous) { + str[1] = 0x80 | (c & kMask); + return 2; + } else if (c <= kMaxThreeByteChar) { +- if (Utf16::IsTrailSurrogate(c) && +- Utf16::IsLeadSurrogate(previous)) { ++ if (Utf16::IsSurrogatePair(previous, c)) { + const int kUnmatchedSize = kSizeOfUnmatchedSurrogate; + return Encode(str - kUnmatchedSize, + Utf16::CombineSurrogatePair(previous, c), +- Utf16::kNoPreviousCharacter) - kUnmatchedSize; ++ Utf16::kNoPreviousCharacter, ++ replace_invalid) - kUnmatchedSize; ++ } else if (replace_invalid && ++ (Utf16::IsLeadSurrogate(c) || ++ Utf16::IsTrailSurrogate(c))) { ++ c = kBadChar; + } + str[0] = 0xE0 | (c >> 12); + str[1] = 0x80 | ((c >> 6) & kMask); +diff --git a/src/unicode.h b/src/unicode.h +index 91b16c9..dc88226 100644 +--- a/src/unicode.h ++++ b/src/unicode.h +@@ -117,6 +117,9 @@ class Buffer { + + class Utf16 { + public: ++ static inline bool IsSurrogatePair(int lead, int trail) { ++ return IsLeadSurrogate(lead) && IsTrailSurrogate(trail); ++ } + static inline bool IsLeadSurrogate(int code) { + if (code == kNoPreviousCharacter) return false; + return (code & 0xfc00) == 0xd800; +@@ -152,13 +155,19 @@ class Utf16 { + class Utf8 { + public: + static inline uchar Length(uchar chr, int previous); +- static inline unsigned Encode( +- char* out, uchar c, int previous); ++ static inline unsigned Encode(char* out, ++ uchar c, ++ int previous, ++ bool replace_invalid = false); + static const byte* ReadBlock(Buffer str, byte* buffer, + unsigned capacity, unsigned* chars_read, unsigned* offset); + static uchar CalculateValue(const byte* str, + unsigned length, + unsigned* cursor); ++ ++ ++ // The unicode replacement character, used to signal invalid unicode ++ // sequences (e.g. an orphan surrogate) when converting to a UTF-8 encoding. + static const uchar kBadChar = 0xFFFD; + static const unsigned kMaxEncodedSize = 4; + static const unsigned kMaxOneByteChar = 0x7f; +@@ -170,6 +179,9 @@ class Utf8 { + // that match are coded as a 4 byte UTF-8 sequence. + static const unsigned kBytesSavedByCombiningSurrogates = 2; + static const unsigned kSizeOfUnmatchedSurrogate = 3; ++ // The maximum size a single UTF-16 code unit may take up when encoded as ++ // UTF-8. ++ static const unsigned kMax16BitCodeUnitSize = 3; + + private: + template friend class Utf8InputBuffer; +-- +1.8.3.1 + diff --git a/SOURCES/v8-add-api-for-aborting-on-uncaught-exception.patch b/SOURCES/v8-add-api-for-aborting-on-uncaught-exception.patch new file mode 100644 index 0000000..812d787 --- /dev/null +++ b/SOURCES/v8-add-api-for-aborting-on-uncaught-exception.patch @@ -0,0 +1,142 @@ +From fbff7054a47551387a99244e2cf0631f30406798 Mon Sep 17 00:00:00 2001 +From: Trevor Norris +Date: Tue, 18 Nov 2014 16:37:54 -0800 +Subject: [PATCH] v8: add api for aborting on uncaught exception + +Add v8::Isolate::SetAbortOnUncaughtException() so the user can be +notified when an uncaught exception has bubbled. + +PR-URL: https://github.com/joyent/node/pull/8666 +Reviewed-by: Trevor Norris +--- + include/v8.h | 11 +++++++++++ + src/api.cc | 5 +++++ + src/isolate.cc | 33 +++++++++++++++++++++++---------- + src/isolate.h | 5 +++++ + 4 files changed, 44 insertions(+), 10 deletions(-) + +diff --git a/include/v8.h binclude/v8.h +index 71a0d01..e229ed9 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -2846,6 +2846,17 @@ class V8EXPORT Isolate { + static Isolate* GetCurrent(); + + /** ++ * Custom callback used by embedders to help V8 determine if it should abort ++ * when it throws and no internal handler can catch the exception. ++ * If FLAG_abort_on_uncaught_exception is true, then V8 will abort if either: ++ * - no custom callback is set. ++ * - the custom callback set returns true. ++ * Otherwise it won't abort. ++ */ ++ typedef bool (*abort_on_uncaught_exception_t)(); ++ void SetAbortOnUncaughtException(abort_on_uncaught_exception_t callback); ++ ++ /** + * Methods below this point require holding a lock (using Locker) in + * a multi-threaded environment. + */ +diff --git a/src/api.cc b/src/api.cc +index 96d564f..4b1aa67 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -5565,6 +5565,11 @@ void Isolate::Enter() { + isolate->Enter(); + } + ++void Isolate::SetAbortOnUncaughtException( ++ abort_on_uncaught_exception_t callback) { ++ i::Isolate* isolate = reinterpret_cast(this); ++ isolate->SetAbortOnUncaughtException(callback); ++} + + void Isolate::Exit() { + i::Isolate* isolate = reinterpret_cast(this); +diff --git a/src/isolate.cc b/src/isolate.cc +index 5a5293e..0b38616 100644 +--- a/src/isolate.cc ++++ b/src/isolate.cc +@@ -1152,18 +1152,26 @@ void Isolate::DoThrow(Object* exception, MessageLocation* location) { + thread_local_top()->pending_message_end_pos_ = location->end_pos(); + } + +- // If the abort-on-uncaught-exception flag is specified, abort on any +- // exception not caught by JavaScript, even when an external handler is +- // present. This flag is intended for use by JavaScript developers, so +- // print a user-friendly stack trace (not an internal one). ++ // If the abort-on-uncaught-exception flag is specified, and if the ++ // exception is not caught by JavaScript (even when an external handler is ++ // present). + if (fatal_exception_depth == 0 && + FLAG_abort_on_uncaught_exception && + (report_exception || can_be_caught_externally)) { +- fatal_exception_depth++; +- fprintf(stderr, "%s\n\nFROM\n", +- *MessageHandler::GetLocalizedMessage(message_obj)); +- PrintCurrentStackTrace(stderr); +- OS::Abort(); ++ // If the embedder didn't specify a custom uncaught exception callback, ++ // or if the custom callback determined that V8 should abort, then ++ // abort ++ bool should_abort = !abort_on_uncaught_exception_callback_ || ++ abort_on_uncaught_exception_callback_(); ++ if (should_abort) { ++ fatal_exception_depth++; ++ // This flag is intended for use by JavaScript developers, so ++ // print a user-friendly stack trace (not an internal one). ++ fprintf(stderr, "%s\n\nFROM\n", ++ *MessageHandler::GetLocalizedMessage(message_obj)); ++ PrintCurrentStackTrace(stderr); ++ OS::Abort(); ++ } + } + } else if (location != NULL && !location->script().is_null()) { + // We are bootstrapping and caught an error where the location is set +@@ -1339,6 +1347,10 @@ void Isolate::SetCaptureStackTraceForUncaughtExceptions( + stack_trace_for_uncaught_exceptions_options_ = options; + } + ++void Isolate::SetAbortOnUncaughtException( ++ v8::Isolate::abort_on_uncaught_exception_t callback) { ++ abort_on_uncaught_exception_callback_ = callback; ++} + + bool Isolate::is_out_of_memory() { + if (has_pending_exception()) { +@@ -1534,7 +1546,8 @@ Isolate::Isolate() + date_cache_(NULL), + context_exit_happened_(false), + deferred_handles_head_(NULL), +- optimizing_compiler_thread_(this) { ++ optimizing_compiler_thread_(this), ++ abort_on_uncaught_exception_callback_(NULL) { + TRACE_ISOLATE(constructor); + + memset(isolate_addresses_, 0, +diff --git a/src/isolate.h b/src/isolate.h +index 2769ca7..8719aa1 100644 +--- a/src/isolate.h ++++ b/src/isolate.h +@@ -692,6 +692,9 @@ class Isolate { + int frame_limit, + StackTrace::StackTraceOptions options); + ++ typedef bool (*abort_on_uncaught_exception_t)(); ++ void SetAbortOnUncaughtException(abort_on_uncaught_exception_t callback); ++ + // Tells whether the current context has experienced an out of memory + // exception. + bool is_out_of_memory(); +@@ -1292,6 +1295,8 @@ class Isolate { + DeferredHandles* deferred_handles_head_; + OptimizingCompilerThread optimizing_compiler_thread_; + ++ abort_on_uncaught_exception_t abort_on_uncaught_exception_callback_; ++ + friend class ExecutionAccess; + friend class HandleScopeImplementer; + friend class IsolateInitializer; +-- +1.8.3.1 + diff --git a/SPECS/v8.spec b/SPECS/v8.spec index fa31a1b..a8c18ce 100644 --- a/SPECS/v8.spec +++ b/SPECS/v8.spec @@ -35,7 +35,7 @@ Name: %{?scl_prefix}v8 Version: %{somajor}.%{sominor}.%{sobuild}.%{sotiny} -Release: 6%{?dist} +Release: 8%{?dist} Epoch: 1 Summary: JavaScript Engine Group: System Environment/Libraries @@ -97,6 +97,9 @@ Patch12: v8-3.14.5.10-unused-local-typedefs.patch Patch13: v8-3.14.5.10-CVE-2013-6668.patch Patch14: v8-3.14.5.10-CVE-2013-6668-segfault.patch Patch15: v8-3.14.5.10-use-upstream-test-values-regress-test-1122.patch +#This is nodejs specific patch it has not been pushed upstream by joyent +Patch16: v8-add-api-for-aborting-on-uncaught-exception.patch +Patch17: v8-Apply-REPLACE_INVALID_UTF8-patch.patch Obsoletes: nodejs010-v8, ruby193-v8, mongodb24-v8 @@ -133,7 +136,8 @@ Development headers and libraries for v8. %patch13 -p1 %patch14 -p1 %patch15 -p1 - +%patch16 -p1 +%patch17 -p1 %build mkdir -p build/gyp @@ -228,6 +232,14 @@ rm -rf %{buildroot} %{?_scl_root}%{python_sitelib}/j*.py* %changelog +* Wed Jan 07 2015 Tomas Hrcka - 1:3.14.5.10-8 +- Backport Apply REPLACE_INVALID_UTF8 patch +- https://github.com/joyent/node/commit/881ac26f27f4ac9585d66c8d8a67d5b246a23d1b + +* Wed Jan 07 2015 Tomas Hrcka - 1:3.14.5.10-7 +- Backport api for aborting on uncaught exception +- https://github.com/joyent/node/commit/fbff7054a47551387a99244e2cf0631f30406798 + * Tue Sep 30 2014 Tomas Hrcka - 1:3.14.5.10-6 - Update regress test 1122