diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 13d4cdd963..14eb13a949 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -911,6 +911,7 @@ GK_ATOM(onstatechange, "onstatechange") GK_ATOM(onstatuschanged, "onstatuschanged") GK_ATOM(onstkcommand, "onstkcommand") GK_ATOM(onstksessionend, "onstksessionend") +GK_ATOM(onstorage, "onstorage") GK_ATOM(onstorageareachanged, "onstorageareachanged") GK_ATOM(onsubmit, "onsubmit") GK_ATOM(onsuccess, "onsuccess") diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index b873a84a12..5f1e5d059d 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -531,8 +531,10 @@ WINDOW_EVENT(popstate, eBasicEventClass) // Not supported yet // WINDOW_EVENT(redo) -// Not supported yet -// WINDOW_EVENT(storage) +WINDOW_EVENT(storage, + eStorage, + EventNameType_HTMLBodyOrFramesetOnly, + eBasicEventClass) // Not supported yet // WINDOW_EVENT(undo) WINDOW_EVENT(unload, diff --git a/dom/imptests/failures/html/html/browsers/the-window-object/test_window-properties.html.json b/dom/imptests/failures/html/html/browsers/the-window-object/test_window-properties.html.json index 3a3aa7ffe9..b34f6573fa 100644 --- a/dom/imptests/failures/html/html/browsers/the-window-object/test_window-properties.html.json +++ b/dom/imptests/failures/html/html/browsers/the-window-object/test_window-properties.html.json @@ -25,7 +25,6 @@ "Window attribute: onclose": true, "Window attribute: oncuechange": true, "Window attribute: onmousewheel": true, - "Window attribute: onstorage": true, "Window unforgeable attribute: window": true, "Window unforgeable attribute: document": true, "Window unforgeable attribute: top": true diff --git a/dom/ipc/PreallocatedProcessManager.cpp b/dom/ipc/PreallocatedProcessManager.cpp index df91760a93..8bce3dc1a3 100644 --- a/dom/ipc/PreallocatedProcessManager.cpp +++ b/dom/ipc/PreallocatedProcessManager.cpp @@ -18,6 +18,10 @@ #include "ipc/Nuwa.h" #endif +#ifdef MOZ_B2G_LOADER +#include "ProcessUtils.h" +#endif + // This number is fairly arbitrary ... the intention is to put off // launching another app process until the last one has finished // loading its content, to reduce CPU/memory/IO contention. @@ -133,7 +137,14 @@ PreallocatedProcessManagerImpl::Init() os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, /* weakRef = */ false); } - RereadPrefs(); +#ifdef MOZ_B2G_LOADER + if (!mozilla::ipc::ProcLoaderIsInitialized()) { + Disable(); + } else +#endif + { + RereadPrefs(); + } } NS_IMETHODIMP diff --git a/dom/webidl/EventHandler.webidl b/dom/webidl/EventHandler.webidl index 437449498f..742862297d 100644 --- a/dom/webidl/EventHandler.webidl +++ b/dom/webidl/EventHandler.webidl @@ -136,7 +136,7 @@ interface WindowEventHandlers { attribute EventHandler onpagehide; attribute EventHandler onpageshow; attribute EventHandler onpopstate; - //(Not implemented)attribute EventHandler onstorage; + attribute EventHandler onstorage; attribute EventHandler onunload; }; diff --git a/ipc/app/moz.build b/ipc/app/moz.build index fa9d101b27..3305b97878 100644 --- a/ipc/app/moz.build +++ b/ipc/app/moz.build @@ -73,7 +73,7 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] in ('Linux', 'Android'): # from the function using it which breaks the build. Work around that by # forcing there to be only one partition. if '-flto' in CONFIG['OS_CXXFLAGS'] and not CONFIG['CLANG_CXX']: - LDFLAGS += ['--param lto-partitions=1'] + LDFLAGS += ['--param lto-partitions=1'] if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] == 'Darwin': # For sandbox includes and the include dependencies those have diff --git a/ipc/app/pie/moz.build b/ipc/app/pie/moz.build index d631af46e2..d1d312a1f8 100644 --- a/ipc/app/pie/moz.build +++ b/ipc/app/pie/moz.build @@ -29,4 +29,5 @@ if CONFIG['MOZ_SANDBOX']: LDFLAGS += ['-pie'] -FAIL_ON_WARNINGS = True +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wshadow'] diff --git a/ipc/chromium/Makefile.in b/ipc/chromium/Makefile.in deleted file mode 100644 index d79cb4f9ce..0000000000 --- a/ipc/chromium/Makefile.in +++ /dev/null @@ -1,40 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -OS_CXXFLAGS := $(filter-out -fshort-wchar,$(OS_CXXFLAGS)) - -ACDEFINES = - -ifndef MOZ_NATIVE_LIBEVENT # { -vpath %.c \ - $(srcdir)/src/third_party/libevent \ - $(NULL) -endif # } - -vpath %.cc \ - $(srcdir)/src/base \ - $(srcdir)/src/chrome/common \ - $(NULL) - -vpath %.mm \ - $(srcdir)/src/base \ - $(srcdir)/src/chrome/common \ - $(NULL) - -OS_CXXFLAGS += $(TK_CFLAGS) - -include $(topsrcdir)/config/rules.mk - -ifdef MOZ_NATIVE_LIBEVENT # { - -export-preqs = \ - $(call mkdir_deps,$(CURDIR)/third_party/libevent) \ - $(NULL) - -export:: $(DIST)/third_party/libevent/event.h - -$(DIST)/third_party/libevent/event.h:: $(export-preqs) - echo '#include ' > $(CURDIR)/third_party/libevent/event.h - -endif # } diff --git a/ipc/chromium/src/base/message_pump_libevent.cc b/ipc/chromium/src/base/message_pump_libevent.cc index c3486752c3..9ce230c4a5 100644 --- a/ipc/chromium/src/base/message_pump_libevent.cc +++ b/ipc/chromium/src/base/message_pump_libevent.cc @@ -15,7 +15,7 @@ #include "base/scoped_nsautorelease_pool.h" #include "base/time.h" #include "nsDependentSubstring.h" -#include "third_party/libevent/event.h" +#include "event.h" #include "mozilla/UniquePtr.h" // This macro checks that the _EVENT_SIZEOF_* constants defined in diff --git a/ipc/chromium/src/third_party/libevent/README.mozilla b/ipc/chromium/src/third_party/libevent/README.mozilla index edc8374116..5534c97c7b 100644 --- a/ipc/chromium/src/third_party/libevent/README.mozilla +++ b/ipc/chromium/src/third_party/libevent/README.mozilla @@ -14,9 +14,10 @@ environment indicated by the first path component. You have to run then be found in "include/event2/". You then need to modify the _EVENT_SIZEOF_* constants in the generated linux, -mac and bsd headers to be appropriate for both 32-bit and 64-bit platforms. Use -__LP64__ to distinguish the two cases. If you get something wrong the -CHECK_EVENT_SIZEOF static assertions in message_pump_libevent.cc will fail. +android, mac and bsd headers to be appropriate for both 32-bit and 64-bit +platforms. Use __LP64__ to distinguish the two cases. If you get something +wrong the CHECK_EVENT_SIZEOF static assertions in message_pump_libevent.cc will +fail. 2. This is ugly, prepare yourself. OS X has a weird problem with how the "TAILQ_END(head)" is used, causing a linking error. Just replace all use of the @@ -39,5 +40,6 @@ ipc/chromium/src/third_party/libevent/patches/: - "avoid-empty-sighandler.patch". This fixes some OS X crashes. +- "android64_support.patch". This fixes Android 64-bit support. 7. Apply "libevent-backport-upstream-fixes.patch", which incorporates some upstream fixes from 2.1.* diff --git a/ipc/chromium/src/third_party/libevent/android/event2/event-config.h b/ipc/chromium/src/third_party/libevent/android/event2/event-config.h index 2f782be2b4..7efea69237 100644 --- a/ipc/chromium/src/third_party/libevent/android/event2/event-config.h +++ b/ipc/chromium/src/third_party/libevent/android/event2/event-config.h @@ -398,26 +398,47 @@ your system. */ /* #undef _EVENT_PTHREAD_CREATE_JOINABLE */ +/* ------------------------------------------------------------------------ */ +/* MOZILLA NOTE: the following constants are hand-modified to be suitable */ +/* for both 32-bit and 64-bit platforms. See README.mozilla for details. */ +/* ------------------------------------------------------------------------ */ + /* The size of `int', as computed by sizeof. */ #define _EVENT_SIZEOF_INT 4 /* The size of `long', as computed by sizeof. */ +#ifdef __LP64__ +#define _EVENT_SIZEOF_LONG 8 +#else #define _EVENT_SIZEOF_LONG 4 +#endif /* The size of `long long', as computed by sizeof. */ #define _EVENT_SIZEOF_LONG_LONG 8 /* The size of `pthread_t', as computed by sizeof. */ +#ifdef __LP64__ +#define _EVENT_SIZEOF_PTHREAD_T 8 +#else #define _EVENT_SIZEOF_PTHREAD_T 4 +#endif /* The size of `short', as computed by sizeof. */ #define _EVENT_SIZEOF_SHORT 2 /* The size of `size_t', as computed by sizeof. */ +#ifdef __LP64__ +#define _EVENT_SIZEOF_SIZE_T 8 +#else #define _EVENT_SIZEOF_SIZE_T 4 +#endif /* The size of `void *', as computed by sizeof. */ +#ifdef __LP64__ +#define _EVENT_SIZEOF_VOID_P 8 +#else #define _EVENT_SIZEOF_VOID_P 4 +#endif /* Define to 1 if you have the ANSI C header files. */ #define _EVENT_STDC_HEADERS 1 diff --git a/ipc/chromium/src/third_party/libevent/patches/android64_support.patch b/ipc/chromium/src/third_party/libevent/patches/android64_support.patch new file mode 100644 index 0000000000..1f039d0d54 --- /dev/null +++ b/ipc/chromium/src/third_party/libevent/patches/android64_support.patch @@ -0,0 +1,52 @@ +diff --git a/ipc/chromium/src/third_party/libevent/android/event2/event-config.h b/ipc/chromium/src/third_party/libevent/android/event2/event-config.h +--- a/ipc/chromium/src/third_party/libevent/android/event2/event-config.h ++++ b/ipc/chromium/src/third_party/libevent/android/event2/event-config.h +@@ -397,32 +397,48 @@ + /* Define to necessary symbol if this constant uses a non-standard name on + your system. */ + /* #undef _EVENT_PTHREAD_CREATE_JOINABLE */ + + /* The size of `int', as computed by sizeof. */ + #define _EVENT_SIZEOF_INT 4 + + /* The size of `long', as computed by sizeof. */ ++#ifdef __LP64__ ++#define _EVENT_SIZEOF_LONG 8 ++#else + #define _EVENT_SIZEOF_LONG 4 ++#endif + + /* The size of `long long', as computed by sizeof. */ + #define _EVENT_SIZEOF_LONG_LONG 8 + + /* The size of `pthread_t', as computed by sizeof. */ ++#ifdef __LP64__ ++#define _EVENT_SIZEOF_PTHREAD_T 8 ++#else + #define _EVENT_SIZEOF_PTHREAD_T 4 ++#endif + + /* The size of `short', as computed by sizeof. */ + #define _EVENT_SIZEOF_SHORT 2 + + /* The size of `size_t', as computed by sizeof. */ ++#ifdef __LP64__ ++#define _EVENT_SIZEOF_SIZE_T 8 ++#else + #define _EVENT_SIZEOF_SIZE_T 4 ++#endif + + /* The size of `void *', as computed by sizeof. */ ++#ifdef __LP64__ ++#define _EVENT_SIZEOF_VOID_P 8 ++#else + #define _EVENT_SIZEOF_VOID_P 4 ++#endif + + /* Define to 1 if you have the ANSI C header files. */ + #define _EVENT_STDC_HEADERS 1 + + /* Define to 1 if you can safely include both and . */ + #define _EVENT_TIME_WITH_SYS_TIME 1 + + /* Version number of package */ diff --git a/ipc/chromium/src/third_party/moz.build b/ipc/chromium/src/third_party/moz.build index 89061ecded..4740c9b639 100644 --- a/ipc/chromium/src/third_party/moz.build +++ b/ipc/chromium/src/third_party/moz.build @@ -54,6 +54,7 @@ if os_linux: 'libevent/epoll_sub.c', ] +# We allow warnings for third-party code that can be updated from upstream. ALLOW_COMPILER_WARNINGS = True FINAL_LIBRARY = 'xul' diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 2e0858cb0e..8456b2d316 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -14,6 +14,7 @@ #include "mozilla/DebugOnly.h" #include "mozilla/Move.h" #include "mozilla/SizePrintfMacros.h" +#include "mozilla/Telemetry.h" #include "nsDebug.h" #include "nsISupportsImpl.h" #include "nsContentUtils.h" @@ -864,7 +865,8 @@ MessageChannel::Send(Message* aMsg, Message* aReply) return false; } - if (DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_NORMAL && + if (mCurrentTransaction && + DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_NORMAL && msg->priority() > IPC::Message::PRIORITY_NORMAL) { // Don't allow sending CPOWs while we're dispatching a sync message. @@ -874,22 +876,23 @@ MessageChannel::Send(Message* aMsg, Message* aReply) if (mCurrentTransaction && (msg->priority() < DispatchingSyncMessagePriority() || - mAwaitingSyncReplyPriority > msg->priority() || - DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_URGENT || - DispatchingAsyncMessagePriority() == IPC::Message::PRIORITY_URGENT)) + mAwaitingSyncReplyPriority > msg->priority())) { CancelCurrentTransactionInternal(); mLink->SendMessage(new CancelMessage()); } IPC_ASSERT(msg->is_sync(), "can only Send() sync messages here"); - IPC_ASSERT(msg->priority() >= DispatchingSyncMessagePriority(), - "can't send sync message of a lesser priority than what's being dispatched"); - IPC_ASSERT(AwaitingSyncReplyPriority() <= msg->priority(), - "nested sync message sends must be of increasing priority"); - IPC_ASSERT(DispatchingSyncMessagePriority() != IPC::Message::PRIORITY_URGENT, - "not allowed to send messages while dispatching urgent messages"); + if (mCurrentTransaction) { + IPC_ASSERT(msg->priority() >= DispatchingSyncMessagePriority(), + "can't send sync message of a lesser priority than what's being dispatched"); + IPC_ASSERT(AwaitingSyncReplyPriority() <= msg->priority(), + "nested sync message sends must be of increasing priority"); + IPC_ASSERT(DispatchingSyncMessagePriority() != IPC::Message::PRIORITY_URGENT, + "not allowed to send messages while dispatching urgent messages"); + } + IPC_ASSERT(DispatchingAsyncMessagePriority() != IPC::Message::PRIORITY_URGENT, "not allowed to send messages while dispatching urgent messages"); @@ -985,6 +988,7 @@ MessageChannel::Send(Message* aMsg, Message* aReply) bool MessageChannel::Call(Message* aMsg, Message* aReply) { + nsAutoPtr msg(aMsg); AssertWorkerThread(); mMonitor->AssertNotCurrentThreadOwns(); @@ -994,7 +998,7 @@ MessageChannel::Call(Message* aMsg, Message* aReply) // This must come before MonitorAutoLock, as its destructor acquires the // monitor lock. - CxxStackFrame cxxframe(*this, OUT_MESSAGE, aMsg); + CxxStackFrame cxxframe(*this, OUT_MESSAGE, msg); // mMonitor can be NULL in some conditions if (!mMonitor) { @@ -1004,7 +1008,7 @@ MessageChannel::Call(Message* aMsg, Message* aReply) MonitorAutoLock lock(*mMonitor); if (!Connected()) { - ReportConnectionError("MessageChannel::Call", aMsg); + ReportConnectionError("MessageChannel::Call", msg); return false; } @@ -1013,9 +1017,7 @@ MessageChannel::Call(Message* aMsg, Message* aReply) "cannot issue Interrupt call while blocked on sync request"); IPC_ASSERT(!DispatchingSyncMessage(), "violation of sync handler invariant"); - IPC_ASSERT(aMsg->is_interrupt(), "can only Call() Interrupt messages here"); - - nsAutoPtr msg(aMsg); + IPC_ASSERT(msg->is_interrupt(), "can only Call() Interrupt messages here"); msg->set_seqno(NextSeqno()); msg->set_interrupt_remote_stack_depth_guess(mRemoteStackDepthGuess); @@ -1334,11 +1336,6 @@ MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply) MOZ_ASSERT_IF(prio > IPC::Message::PRIORITY_NORMAL, NS_IsMainThread()); MaybeScriptBlocker scriptBlocker(this, prio > IPC::Message::PRIORITY_NORMAL); - IPC_ASSERT(prio >= DispatchingSyncMessagePriority(), - "priority inversion while dispatching sync message"); - IPC_ASSERT(prio >= mAwaitingSyncReplyPriority, - "dispatching a message of lower priority while waiting for a response"); - MessageChannel* dummy; MessageChannel*& blockingVar = ShouldBlockScripts() ? gParentProcessBlocker : dummy; @@ -1412,8 +1409,9 @@ MessageChannel::DispatchInterruptMessage(const Message& aMsg, size_t stackDepth) // processing of the other side's in-call. bool defer; const char* winner; - switch (mListener->MediateInterruptRace((mSide == ChildSide) ? aMsg : mInterruptStack.top(), - (mSide != ChildSide) ? mInterruptStack.top() : aMsg)) + const Message& parentMsg = (mSide == ChildSide) ? aMsg : mInterruptStack.top(); + const Message& childMsg = (mSide == ChildSide) ? mInterruptStack.top() : aMsg; + switch (mListener->MediateInterruptRace(parentMsg, childMsg)) { case RIPChildWins: winner = "child"; @@ -1490,9 +1488,6 @@ MessageChannel::MaybeUndeferIncall() IPC_ASSERT(mDeferred.top().interrupt_remote_stack_depth_guess() <= stackDepth, "fatal logic error"); - if (mDeferred.top().interrupt_remote_stack_depth_guess() < RemoteViewOfStackDepth(stackDepth)) - return; - // maybe time to process this message Message call = mDeferred.top(); mDeferred.pop(); @@ -2042,22 +2037,33 @@ MessageChannel::CancelCurrentTransactionInternal() // tampered with (by us). If so, they don't reset the variable to the old // value. - MOZ_ASSERT(!mCurrentTransaction); + MOZ_ASSERT(mCurrentTransaction); mCurrentTransaction = 0; + + mAwaitingSyncReply = false; + mAwaitingSyncReplyPriority = 0; + + // We could also zero out mDispatchingSyncMessage here. However, that would + // cause a race because mDispatchingSyncMessage is a worker-thread-only + // field and we can be called on the I/O thread. Luckily, we can check to + // see if mCurrentTransaction is 0 before examining DispatchSyncMessage. } void MessageChannel::CancelCurrentTransaction() { MonitorAutoLock lock(*mMonitor); - CancelCurrentTransactionInternal(); - mLink->SendMessage(new CancelMessage()); + if (mCurrentTransaction) { + CancelCurrentTransactionInternal(); + mLink->SendMessage(new CancelMessage()); + } } void CancelCPOWs() { if (gParentProcessBlocker) { + mozilla::Telemetry::Accumulate(mozilla::Telemetry::IPC_TRANSACTION_CANCEL, true); gParentProcessBlocker->CancelCurrentTransaction(); } } diff --git a/ipc/glue/MessageChannel.h b/ipc/glue/MessageChannel.h index b28ebbe55c..025c802de2 100644 --- a/ipc/glue/MessageChannel.h +++ b/ipc/glue/MessageChannel.h @@ -570,7 +570,7 @@ class MessageChannel : HasResultCodes public: explicit AutoEnterTransaction(MessageChannel *aChan, int32_t aMsgSeqno) : mChan(aChan), - mNewTransaction(0), + mNewTransaction(INT32_MAX), mOldTransaction(mChan->mCurrentTransaction) { mChan->mMonitor->AssertCurrentThreadOwns(); diff --git a/ipc/glue/Neutering.h b/ipc/glue/Neutering.h index 70657c53c1..d4ca816da0 100644 --- a/ipc/glue/Neutering.h +++ b/ipc/glue/Neutering.h @@ -57,6 +57,21 @@ private: bool mReneuter; }; +class MOZ_RAII SuppressedNeuteringRegion +{ +public: + SuppressedNeuteringRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM); + ~SuppressedNeuteringRegion(); + + static inline bool IsNeuteringSuppressed() { return sSuppressNeutering; } + +private: + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + bool mReenable; + + static bool sSuppressNeutering; +}; + } // namespace ipc } // namespace mozilla diff --git a/ipc/glue/ProcessUtils.h b/ipc/glue/ProcessUtils.h index 99d0f532dd..9aa6190c17 100644 --- a/ipc/glue/ProcessUtils.h +++ b/ipc/glue/ProcessUtils.h @@ -21,7 +21,7 @@ void SetThisProcessName(const char *aName); #ifdef MOZ_B2G_LOADER // see ProcessUtils_linux.cpp for explaination. void ProcLoaderClientGeckoInit(); - +bool ProcLoaderIsInitialized(); bool ProcLoaderLoad(const char *aArgv[], const char *aEnvp[], const base::file_handle_mapping_vector &aFdsRemap, diff --git a/ipc/glue/ProcessUtils_linux.cpp b/ipc/glue/ProcessUtils_linux.cpp index c4eb81bf8f..1fec223edc 100644 --- a/ipc/glue/ProcessUtils_linux.cpp +++ b/ipc/glue/ProcessUtils_linux.cpp @@ -227,6 +227,11 @@ ProcLoaderClientGeckoInit() sProcLoaderLoop = MessageLoop::current(); } +bool ProcLoaderIsInitialized() +{ + return sProcLoaderPid != 0; +} + /** * Shutdown and destroy the client of B2G loader service. */ diff --git a/ipc/glue/ProtocolUtils.cpp b/ipc/glue/ProtocolUtils.cpp index 1240eb1ee3..9951b74561 100644 --- a/ipc/glue/ProtocolUtils.cpp +++ b/ipc/glue/ProtocolUtils.cpp @@ -26,6 +26,18 @@ using base::ProcessId; namespace mozilla { namespace ipc { +ProtocolCloneContext::ProtocolCloneContext() + : mNeckoParent(nullptr) +{} + +ProtocolCloneContext::~ProtocolCloneContext() +{} + +void ProtocolCloneContext::SetContentParent(ContentParent* aContentParent) +{ + mContentParent = aContentParent; +} + static StaticMutex gProtocolMutex; IToplevelProtocol::IToplevelProtocol(ProtocolId aProtoId) diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h index cb69a8eada..50b2d4ca3b 100644 --- a/ipc/glue/ProtocolUtils.h +++ b/ipc/glue/ProtocolUtils.h @@ -131,19 +131,15 @@ class ProtocolCloneContext typedef mozilla::dom::ContentParent ContentParent; typedef mozilla::net::NeckoParent NeckoParent; - ContentParent* mContentParent; + RefPtr mContentParent; NeckoParent* mNeckoParent; public: - ProtocolCloneContext() - : mContentParent(nullptr) - , mNeckoParent(nullptr) - {} + ProtocolCloneContext(); - void SetContentParent(ContentParent* aContentParent) - { - mContentParent = aContentParent; - } + ~ProtocolCloneContext(); + + void SetContentParent(ContentParent* aContentParent); ContentParent* GetContentParent() { return mContentParent; } diff --git a/ipc/glue/WindowsMessageLoop.cpp b/ipc/glue/WindowsMessageLoop.cpp index b463edd064..5f373f46e3 100644 --- a/ipc/glue/WindowsMessageLoop.cpp +++ b/ipc/glue/WindowsMessageLoop.cpp @@ -15,6 +15,7 @@ #include "nsServiceManagerUtils.h" #include "nsString.h" #include "nsIXULAppInfo.h" +#include "nsWindowsDllInterceptor.h" #include "WinUtils.h" #include "mozilla/ArrayUtils.h" @@ -436,6 +437,93 @@ ProcessOrDeferMessage(HWND hwnd, return res; } +/* + * It is bad to subclass a window when neutering is active because you'll end + * up subclassing the *neutered* window procedure instead of the real window + * procedure. Since CreateWindow* fires WM_CREATE (and could thus trigger + * neutering), we intercept these calls and suppress neutering for the duration + * of the call. This ensures that any subsequent subclassing replaces the + * correct window procedure. + */ +WindowsDllInterceptor sUser32Interceptor; +typedef HWND (WINAPI *CreateWindowExWPtr)(DWORD,LPCWSTR,LPCWSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID); +typedef HWND (WINAPI *CreateWindowExAPtr)(DWORD,LPCSTR,LPCSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID); +typedef HWND (WINAPI *CreateWindowWPtr)(LPCWSTR,LPCWSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID); +typedef HWND (WINAPI *CreateWindowAPtr)(LPCSTR,LPCSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID); + +CreateWindowExWPtr sCreateWindowExWStub = nullptr; +CreateWindowExAPtr sCreateWindowExAStub = nullptr; +CreateWindowWPtr sCreateWindowWStub = nullptr; +CreateWindowAPtr sCreateWindowAStub = nullptr; + +HWND WINAPI +CreateWindowExWHook(DWORD aExStyle, LPCWSTR aClassName, LPCWSTR aWindowName, + DWORD aStyle, int aX, int aY, int aWidth, int aHeight, + HWND aParent, HMENU aMenu, HINSTANCE aInstance, + LPVOID aParam) +{ + SuppressedNeuteringRegion doNotNeuterThisWindowYet; + return sCreateWindowExWStub(aExStyle, aClassName, aWindowName, aStyle, aX, aY, + aWidth, aHeight, aParent, aMenu, aInstance, aParam); +} + +HWND WINAPI +CreateWindowExAHook(DWORD aExStyle, LPCSTR aClassName, LPCSTR aWindowName, + DWORD aStyle, int aX, int aY, int aWidth, int aHeight, + HWND aParent, HMENU aMenu, HINSTANCE aInstance, + LPVOID aParam) +{ + SuppressedNeuteringRegion doNotNeuterThisWindowYet; + return sCreateWindowExAStub(aExStyle, aClassName, aWindowName, aStyle, aX, aY, + aWidth, aHeight, aParent, aMenu, aInstance, aParam); +} + +HWND WINAPI +CreateWindowWHook(LPCWSTR aClassName, LPCWSTR aWindowName, DWORD aStyle, int aX, + int aY, int aWidth, int aHeight, HWND aParent, HMENU aMenu, + HINSTANCE aInstance, LPVOID aParam) +{ + SuppressedNeuteringRegion doNotNeuterThisWindowYet; + return sCreateWindowWStub(aClassName, aWindowName, aStyle, aX, aY, aWidth, + aHeight, aParent, aMenu, aInstance, aParam); +} + +HWND WINAPI +CreateWindowAHook(LPCSTR aClassName, LPCSTR aWindowName, DWORD aStyle, int aX, + int aY, int aWidth, int aHeight, HWND aParent, HMENU aMenu, + HINSTANCE aInstance, LPVOID aParam) +{ + SuppressedNeuteringRegion doNotNeuterThisWindowYet; + return sCreateWindowAStub(aClassName, aWindowName, aStyle, aX, aY, aWidth, + aHeight, aParent, aMenu, aInstance, aParam); +} + +void +InitCreateWindowHook() +{ + sUser32Interceptor.Init("user32.dll"); + if (!sCreateWindowExWStub) { + sUser32Interceptor.AddHook("CreateWindowExW", + reinterpret_cast(CreateWindowExWHook), + (void**) &sCreateWindowExWStub); + } + if (!sCreateWindowExAStub) { + sUser32Interceptor.AddHook("CreateWindowExA", + reinterpret_cast(CreateWindowExAHook), + (void**) &sCreateWindowExAStub); + } + if (!sCreateWindowWStub) { + sUser32Interceptor.AddHook("CreateWindowW", + reinterpret_cast(CreateWindowWHook), + (void**) &sCreateWindowWStub); + } + if (!sCreateWindowAStub) { + sUser32Interceptor.AddHook("CreateWindowA", + reinterpret_cast(CreateWindowAHook), + (void**) &sCreateWindowAStub); + } +} + } // namespace // We need the pointer value of this in PluginInstanceChild. @@ -610,7 +698,9 @@ CallWindowProcedureHook(int nCode, HWND hWnd = reinterpret_cast(lParam)->hwnd; - if (!gNeuteredWindows->Contains(hWnd) && NeuterWindowProcedure(hWnd)) { + if (!gNeuteredWindows->Contains(hWnd) && + !SuppressedNeuteringRegion::IsNeuteringSuppressed() && + NeuterWindowProcedure(hWnd)) { if (!gNeuteredWindows->AppendElement(hWnd)) { NS_ERROR("Out of memory!"); RestoreWindowProcedure(hWnd); @@ -710,6 +800,8 @@ InitUIThread() gCOMWindow = FindCOMWindow(); } MOZ_ASSERT(gWinEventHook); + + InitCreateWindowHook(); } } // namespace windows @@ -943,6 +1035,26 @@ DeneuteredWindowRegion::~DeneuteredWindowRegion() } } +SuppressedNeuteringRegion::SuppressedNeuteringRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL) + : mReenable(::gUIThreadId == ::GetCurrentThreadId() && ::gWindowHook) +{ + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + if (mReenable) { + MOZ_ASSERT(!sSuppressNeutering); + sSuppressNeutering = true; + } +} + +SuppressedNeuteringRegion::~SuppressedNeuteringRegion() +{ + if (mReenable) { + MOZ_ASSERT(sSuppressNeutering); + sSuppressNeutering = false; + } +} + +bool SuppressedNeuteringRegion::sSuppressNeutering = false; + bool MessageChannel::WaitForSyncNotify(bool aHandleWindowsMessages) { @@ -997,6 +1109,8 @@ MessageChannel::WaitForSyncNotify(bool aHandleWindowsMessages) NS_ASSERTION(timerId, "SetTimer failed!"); } + NeuteredWindowRegion neuteredRgn(true); + { while (1) { MSG msg = { 0 }; diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h index 407a8d1f0a..693cc7360f 100644 --- a/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h +++ b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h @@ -16,7 +16,7 @@ class IPDLUnitTestProcessChild : public mozilla::ipc::ProcessChild typedef mozilla::ipc::ProcessChild ProcessChild; public: - IPDLUnitTestProcessChild(ProcessId aParentPid) : + explicit IPDLUnitTestProcessChild(ProcessId aParentPid) : ProcessChild(aParentPid) { } diff --git a/ipc/ipdl/test/cxx/PTestRaceDeadlock.ipdl b/ipc/ipdl/test/cxx/PTestRaceDeadlock.ipdl new file mode 100644 index 0000000000..1e4f574509 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestRaceDeadlock.ipdl @@ -0,0 +1,20 @@ +namespace mozilla { +namespace _ipdltest { + +intr protocol PTestRaceDeadlock { +both: + async StartRace(); + +parent: + intr Lose(); + +child: + intr Win(); + intr Rpc(); + async __delete__(); + +/* Tests that race resolution does not cause deadlocks */ +}; + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestBridgeMain.h b/ipc/ipdl/test/cxx/TestBridgeMain.h index 2395bbdb96..a5c7c10cbc 100644 --- a/ipc/ipdl/test/cxx/TestBridgeMain.h +++ b/ipc/ipdl/test/cxx/TestBridgeMain.h @@ -42,7 +42,7 @@ class TestBridgeMainSubParent : public PTestBridgeMainSubParent { public: - TestBridgeMainSubParent(Transport* aTransport) + explicit TestBridgeMainSubParent(Transport* aTransport) : mTransport(aTransport) {} virtual ~TestBridgeMainSubParent() {} @@ -126,7 +126,7 @@ class TestBridgeMainSubChild : public PTestBridgeMainSubChild { public: - TestBridgeMainSubChild(Transport* aTransport) + explicit TestBridgeMainSubChild(Transport* aTransport) : mGotHi(false) , mTransport(aTransport) {} diff --git a/ipc/ipdl/test/cxx/TestDataStructures.h b/ipc/ipdl/test/cxx/TestDataStructures.h index a372b3c71b..f77cfa100a 100644 --- a/ipc/ipdl/test/cxx/TestDataStructures.h +++ b/ipc/ipdl/test/cxx/TestDataStructures.h @@ -20,7 +20,7 @@ class TestDataStructuresSub : public PTestDataStructuresSubChild { public: - TestDataStructuresSub(uint32_t i) : mI(i) + explicit TestDataStructuresSub(uint32_t i) : mI(i) { } virtual ~TestDataStructuresSub() { } diff --git a/ipc/ipdl/test/cxx/TestOpens.h b/ipc/ipdl/test/cxx/TestOpens.h index e8219f030b..b83645a823 100644 --- a/ipc/ipdl/test/cxx/TestOpens.h +++ b/ipc/ipdl/test/cxx/TestOpens.h @@ -40,7 +40,7 @@ namespace _ipdltest2 { class TestOpensOpenedParent : public PTestOpensOpenedParent { public: - TestOpensOpenedParent(Transport* aTransport) + explicit TestOpensOpenedParent(Transport* aTransport) : mTransport(aTransport) {} virtual ~TestOpensOpenedParent() {} @@ -83,7 +83,7 @@ namespace _ipdltest2 { class TestOpensOpenedChild : public PTestOpensOpenedChild { public: - TestOpensOpenedChild(Transport* aTransport) + explicit TestOpensOpenedChild(Transport* aTransport) : mGotHi(false) , mTransport(aTransport) {} diff --git a/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp b/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp new file mode 100644 index 0000000000..1d6ec4f58b --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp @@ -0,0 +1,130 @@ +#include "TestRaceDeadlock.h" + +#include "IPDLUnitTests.h" // fail etc. + +// #define TEST_TIMEOUT 5000 + +using namespace mozilla::ipc; +typedef mozilla::ipc::MessageChannel::Message Message; + +namespace mozilla { +namespace _ipdltest { + +static RacyInterruptPolicy +MediateRace(const Message& parent, const Message& child) +{ + return (PTestRaceDeadlock::Msg_Win__ID == parent.type()) ? + RIPParentWins : RIPChildWins; +} + +//----------------------------------------------------------------------------- +// parent + +TestRaceDeadlockParent::TestRaceDeadlockParent() +{ + MOZ_COUNT_CTOR(TestRaceDeadlockParent); +} + +TestRaceDeadlockParent::~TestRaceDeadlockParent() +{ + MOZ_COUNT_DTOR(TestRaceDeadlockParent); +} + +void +TestRaceDeadlockParent::Main() +{ + Test1(); + + Close(); +} + +bool +TestRaceDeadlockParent::ShouldContinueFromReplyTimeout() +{ + fail("This test should not hang"); + GetIPCChannel()->CloseWithTimeout(); + return false; +} + +void +TestRaceDeadlockParent::Test1() +{ +#if defined(TEST_TIMEOUT) + SetReplyTimeoutMs(TEST_TIMEOUT); +#endif + if (!SendStartRace()) { + fail("sending StartRace"); + } + if (!CallRpc()) { + fail("calling Rpc"); + } +} + +bool +TestRaceDeadlockParent::AnswerLose() +{ + return true; +} + +RacyInterruptPolicy +TestRaceDeadlockParent::MediateInterruptRace(const Message& parent, + const Message& child) +{ + return MediateRace(parent, child); +} + +//----------------------------------------------------------------------------- +// child + +TestRaceDeadlockChild::TestRaceDeadlockChild() +{ + MOZ_COUNT_CTOR(TestRaceDeadlockChild); +} + +TestRaceDeadlockChild::~TestRaceDeadlockChild() +{ + MOZ_COUNT_DTOR(TestRaceDeadlockChild); +} + +bool +TestRaceDeadlockParent::RecvStartRace() +{ + if (!CallWin()) { + fail("calling Win"); + } + return true; +} + +bool +TestRaceDeadlockChild::RecvStartRace() +{ + if (!SendStartRace()) { + fail("calling SendStartRace"); + } + if (!CallLose()) { + fail("calling Lose"); + } + return true; +} + +bool +TestRaceDeadlockChild::AnswerWin() +{ + return true; +} + +bool +TestRaceDeadlockChild::AnswerRpc() +{ + return true; +} + +RacyInterruptPolicy +TestRaceDeadlockChild::MediateInterruptRace(const Message& parent, + const Message& child) +{ + return MediateRace(parent, child); +} + +} // namespace _ipdltest +} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestRaceDeadlock.h b/ipc/ipdl/test/cxx/TestRaceDeadlock.h new file mode 100644 index 0000000000..6bb8012898 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestRaceDeadlock.h @@ -0,0 +1,75 @@ +#ifndef mozilla__ipdltest_TestRaceDeadlock_h +#define mozilla__ipdltest_TestRaceDeadlock_h 1 + +#include "mozilla/_ipdltest/IPDLUnitTests.h" + +#include "mozilla/_ipdltest/PTestRaceDeadlockParent.h" +#include "mozilla/_ipdltest/PTestRaceDeadlockChild.h" + +namespace mozilla { +namespace _ipdltest { + +class TestRaceDeadlockParent : + public PTestRaceDeadlockParent +{ +public: + TestRaceDeadlockParent(); + virtual ~TestRaceDeadlockParent(); + + static bool RunTestInProcesses() { return true; } + static bool RunTestInThreads() { return true; } + + void Main(); + +protected: + virtual bool ShouldContinueFromReplyTimeout() override; + + void Test1(); + + virtual bool RecvStartRace() override; + virtual bool AnswerLose() override; + + virtual mozilla::ipc::RacyInterruptPolicy + MediateInterruptRace(const Message& parent, const Message& child) override; + + virtual void ActorDestroy(ActorDestroyReason why) override + { + if (NormalShutdown != why) + fail("unexpected destruction!"); + passed("ok"); + QuitParent(); + } +}; + + +class TestRaceDeadlockChild : + public PTestRaceDeadlockChild +{ +public: + TestRaceDeadlockChild(); + virtual ~TestRaceDeadlockChild(); + +protected: + virtual bool RecvStartRace() override; + + virtual bool AnswerWin() override; + + virtual bool AnswerRpc() override; + + virtual mozilla::ipc::RacyInterruptPolicy + MediateInterruptRace(const Message& parent, const Message& child) override; + + virtual void ActorDestroy(ActorDestroyReason why) override + { + if (NormalShutdown != why) + fail("unexpected destruction!"); + QuitChild(); + } +}; + + +} // namespace _ipdltest +} // namespace mozilla + + +#endif // ifndef mozilla__ipdltest_TestRaceDeadlock_h diff --git a/ipc/ipdl/test/cxx/TestShutdown.h b/ipc/ipdl/test/cxx/TestShutdown.h index 249ca415f1..c79cbb8fc6 100644 --- a/ipc/ipdl/test/cxx/TestShutdown.h +++ b/ipc/ipdl/test/cxx/TestShutdown.h @@ -22,7 +22,7 @@ class TestShutdownSubsubParent : public PTestShutdownSubsubParent { public: - TestShutdownSubsubParent(bool expectParentDeleted) : + explicit TestShutdownSubsubParent(bool expectParentDeleted) : mExpectParentDeleted(expectParentDeleted) { } @@ -44,7 +44,7 @@ class TestShutdownSubParent : public PTestShutdownSubParent { public: - TestShutdownSubParent(bool expectCrash) : + explicit TestShutdownSubParent(bool expectCrash) : mExpectCrash(expectCrash), mDeletedCount(0) { @@ -131,7 +131,7 @@ class TestShutdownSubsubChild : public PTestShutdownSubsubChild { public: - TestShutdownSubsubChild(bool expectParentDeleted) : + explicit TestShutdownSubsubChild(bool expectParentDeleted) : mExpectParentDeleted(expectParentDeleted) { } @@ -152,7 +152,7 @@ class TestShutdownSubChild : public PTestShutdownSubChild { public: - TestShutdownSubChild(bool expectCrash) : mExpectCrash(expectCrash) + explicit TestShutdownSubChild(bool expectCrash) : mExpectCrash(expectCrash) { } diff --git a/ipc/ipdl/test/cxx/moz.build b/ipc/ipdl/test/cxx/moz.build index 008d028a3e..9722dbc7e8 100644 --- a/ipc/ipdl/test/cxx/moz.build +++ b/ipc/ipdl/test/cxx/moz.build @@ -33,6 +33,7 @@ SOURCES += [ 'TestMultiMgrs.cpp', 'TestNestedLoops.cpp', 'TestOpens.cpp', + 'TestRaceDeadlock.cpp', 'TestRaceDeferral.cpp', 'TestRacyInterruptReplies.cpp', 'TestRacyReentry.cpp', @@ -102,6 +103,7 @@ IPDL_SOURCES += [ 'PTestNestedLoops.ipdl', 'PTestOpens.ipdl', 'PTestOpensOpened.ipdl', + 'PTestRaceDeadlock.ipdl', 'PTestRaceDeferral.ipdl', 'PTestRacyInterruptReplies.ipdl', 'PTestRacyReentry.ipdl', diff --git a/ipc/unixfd/UnixSocketWatcher.cpp b/ipc/unixfd/UnixSocketWatcher.cpp index 541b090aea..2ce32e93df 100644 --- a/ipc/unixfd/UnixSocketWatcher.cpp +++ b/ipc/unixfd/UnixSocketWatcher.cpp @@ -29,14 +29,14 @@ UnixSocketWatcher::Connect(const struct sockaddr* aAddr, socklen_t aAddrLen) MOZ_ASSERT(IsOpen()); MOZ_ASSERT(aAddr || !aAddrLen); - if (connect(GetFd(), aAddr, aAddrLen) < 0) { + if (TEMP_FAILURE_RETRY(connect(GetFd(), aAddr, aAddrLen) < 0)) { if (errno == EINPROGRESS) { mConnectionStatus = SOCKET_IS_CONNECTING; // Set up a write watch to receive the connect signal AddWatchers(WRITE_WATCHER, false); - } else { - OnError("connect", errno); + return NS_OK; } + OnError("connect", errno); return NS_ERROR_FAILURE; } diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 56d70f8b8b..a3b7c9e986 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -31,7 +31,8 @@ using mozilla::Maybe; class MOZ_STACK_CLASS AutoCompilationTraceLogger { public: - AutoCompilationTraceLogger(ExclusiveContext* cx, const TraceLoggerTextId id); + AutoCompilationTraceLogger(ExclusiveContext* cx, const TraceLoggerTextId id, + const ReadOnlyCompileOptions& options); private: TraceLoggerThread* logger; @@ -117,10 +118,11 @@ class MOZ_STACK_CLASS BytecodeCompiler Maybe emitter; }; -AutoCompilationTraceLogger::AutoCompilationTraceLogger(ExclusiveContext* cx, const TraceLoggerTextId id) +AutoCompilationTraceLogger::AutoCompilationTraceLogger(ExclusiveContext* cx, + const TraceLoggerTextId id, const ReadOnlyCompileOptions& options) : logger(cx->isJSContext() ? TraceLoggerForMainThread(cx->asJSContext()->runtime()) : TraceLoggerForCurrentThread()), - event(logger, TraceLogger_AnnotateScripts), + event(logger, TraceLogger_AnnotateScripts, options), scriptLogger(logger, event), typeLogger(logger, id) {} @@ -131,7 +133,7 @@ BytecodeCompiler::BytecodeCompiler(ExclusiveContext* cx, SourceBufferHolder& sourceBuffer, Handle enclosingStaticScope, TraceLoggerTextId logId) - : traceLogger(cx, logId), + : traceLogger(cx, logId, options), keepAtoms(cx->perThreadData), cx(cx), alloc(alloc), @@ -785,7 +787,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha .setNoScriptRval(false) .setSelfHostingMode(false); - AutoCompilationTraceLogger traceLogger(cx, TraceLogger_ParserCompileLazy); + AutoCompilationTraceLogger traceLogger(cx, TraceLogger_ParserCompileLazy, options); Parser parser(cx, &cx->tempLifoAlloc(), options, chars, length, /* foldConstants = */ true, nullptr, lazy); diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 0013318b81..dea201d175 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -5938,38 +5938,32 @@ BytecodeEmitter::emitFor(ParseNode* pn) bool BytecodeEmitter::emitComprehensionForInOrOfVariables(ParseNode* pn, bool* letBlockScope) { - // ES6 specifies that loop variables get a fresh binding in each iteration. - // This is currently implemented for C-style for(;;) loops, but not - // for-in/of loops, though a similar approach should work. See bug 449811. - // - // In `for (let x in/of EXPR)`, ES6 specifies that EXPR is evaluated in a - // scope containing an uninitialized `x`. If EXPR accesses `x`, we should - // get a ReferenceError due to the TDZ violation. This is not yet - // implemented. See bug 1069480. + // ES6 specifies that lexical for-loop variables get a fresh binding each + // iteration, and that evaluation of the expression looped over occurs with + // these variables uninitialized. But these rules only apply to *standard* + // for-in/of loops, and we haven't extended these requirements to + // comprehension syntax. *letBlockScope = pn->isKind(PNK_LEXICALSCOPE); - MOZ_ASSERT_IF(*letBlockScope, pn->isLexical()); + if (*letBlockScope) { + // This is initially-ES7-tracked syntax, now with considerably + // murkier outlook. The |enterBlockScope()| precipitated by the + // outparam-set here initializes the let-binding in + // |emitComprehensionFor{In,Of}| with |undefined|, so there's nothing + // to do here. + MOZ_ASSERT(pn->isLexical()); + } else { + // This is legacy comprehension syntax. We'll have PNK_LET here, using + // a lexical scope provided by/for the entire comprehension. Name + // analysis assumes declarations initialize lets, but as we're handling + // this declaration manually, we must also initialize manually to avoid + // triggering dead zone checks. + MOZ_ASSERT(pn->isKind(PNK_LET)); + MOZ_ASSERT(pn->pn_count == 1); - // If the left part is 'var x', emit code to define x if necessary using a - // prologue opcode, but do not emit a pop. If it is 'let x', enterBlockScope - // will initialize let bindings in emitForOf and emitForIn with - // undefineds. - // - // Due to the horror of legacy comprehensions, there is a third case where - // we have PNK_LET without a lexical scope, because those expressions are - // parsed with single lexical scope for the entire comprehension. In this - // case we must initialize the lets to not trigger dead zone checks via - // InitializeVars. - if (!*letBlockScope) { emittingForInit = true; - if (pn->isKind(PNK_VAR)) { - if (!emitVariables(pn, DefineVars)) - return false; - } else { - MOZ_ASSERT(pn->isKind(PNK_LET)); - if (!emitVariables(pn, InitializeVars)) - return false; - } + if (!emitVariables(pn, InitializeVars)) + return false; emittingForInit = false; } diff --git a/testing/web-platform/meta/html/browsers/the-window-object/window-properties.html.ini b/testing/web-platform/meta/html/browsers/the-window-object/window-properties.html.ini index 5f86b8fedb..0a2d80718d 100644 --- a/testing/web-platform/meta/html/browsers/the-window-object/window-properties.html.ini +++ b/testing/web-platform/meta/html/browsers/the-window-object/window-properties.html.ini @@ -12,6 +12,3 @@ [Window attribute: onmousewheel] expected: FAIL - [Window attribute: onstorage] - expected: FAIL - diff --git a/testing/web-platform/meta/html/dom/interfaces.html.ini b/testing/web-platform/meta/html/dom/interfaces.html.ini index b9837a2847..05146d3427 100644 --- a/testing/web-platform/meta/html/dom/interfaces.html.ini +++ b/testing/web-platform/meta/html/dom/interfaces.html.ini @@ -655,12 +655,6 @@ [HTMLLinkElement interface: document.createElement("link") must inherit property "crossOrigin" with the proper type (1)] expected: FAIL - [HTMLBodyElement interface: attribute onstorage] - expected: FAIL - - [HTMLBodyElement interface: document.createElement("body") must inherit property "onstorage" with the proper type (17)] - expected: FAIL - [HTMLPreElement must be primary interface of document.createElement("listing")] expected: FAIL @@ -2104,9 +2098,6 @@ [Window interface: attribute ontoggle] expected: FAIL - [Window interface: attribute onstorage] - expected: FAIL - [Window interface: operation setTimeout(Function,long,any)] expected: FAIL @@ -2158,9 +2149,6 @@ [Window interface: window must inherit property "ontoggle" with the proper type (98)] expected: FAIL - [Window interface: window must inherit property "onstorage" with the proper type (112)] - expected: FAIL - [Window interface: calling createImageBitmap(ImageBitmapSource,long,long,long,long) on window with too few arguments must throw TypeError] expected: FAIL @@ -2620,12 +2608,6 @@ [HTMLMarqueeElement interface: document.createElement("marquee") must inherit property "stop" with the proper type (15)] expected: FAIL - [HTMLFrameSetElement interface: attribute onstorage] - expected: FAIL - - [HTMLFrameSetElement interface: document.createElement("frameset") must inherit property "onstorage" with the proper type (13)] - expected: FAIL - [Document interface: iframe.contentDocument must inherit property "styleSheetSets" with the proper type (31)] expected: FAIL diff --git a/testing/web-platform/meta/webstorage/event_body_attribute.html.ini b/testing/web-platform/meta/webstorage/event_body_attribute.html.ini index c31f011354..4d53fabc8b 100644 --- a/testing/web-platform/meta/webstorage/event_body_attribute.html.ini +++ b/testing/web-platform/meta/webstorage/event_body_attribute.html.ini @@ -1,5 +1,4 @@ [event_body_attribute.html] type: testharness - [localStorage mutations fire StorageEvents that are caught by the event listener specified as an attribute on the body.] - expected: FAIL - + disabled: + if e10s: https://bugzilla.mozilla.org/show_bug.cgi?id=1205675 diff --git a/testing/web-platform/tests/webstorage/eventTestHarness.js b/testing/web-platform/tests/webstorage/eventTestHarness.js new file mode 100644 index 0000000000..7d9ed01870 --- /dev/null +++ b/testing/web-platform/tests/webstorage/eventTestHarness.js @@ -0,0 +1,60 @@ +iframe = document.createElement("IFRAME"); +iframe.src = "about:blank"; +document.body.appendChild(iframe); +iframe.contentWindow.document.body.textContent = "Nothing to see here."; + +storageEventList = new Array(); +iframe.contentWindow.onstorage = function(e) { + window.parent.storageEventList.push(e); +}; + +function runAfterNStorageEvents(callback, expectedNumEvents) +{ + countStorageEvents(callback, expectedNumEvents, 0) +} + +function countStorageEvents(callback, expectedNumEvents, times) +{ + function onTimeout() + { + var currentCount = storageEventList.length; + if (currentCount == expectedNumEvents) { + callback(); + } else if (currentCount > expectedNumEvents) { + msg = "got at least " + currentCount + ", expected only " + expectedNumEvents + " events"; + callback(msg); + } else if (times > 50) { + msg = "Timeout: only got " + currentCount + ", expected " + expectedNumEvents + " events"; + callback(msg); + } else { + countStorageEvents(callback, expectedNumEvents, times+1); + } + } + setTimeout(onTimeout, 20); +} + +function clearStorage(storageName, callback) +{ + if (window[storageName].length === 0) { + storageEventList = []; + setTimeout(callback, 0); + } else { + window[storageName].clear(); + runAfterNStorageEvents(function() { + storageEventList = []; + callback(); + }, 1); + } +} + +function testStorages(testCallback) +{ + testCallback("sessionStorage"); + var hit = false; + add_result_callback(function() { + if (!hit) { + hit = true; + testCallback("localStorage"); + } + }); +} diff --git a/testing/web-platform/tests/webstorage/event_body_attribute.js b/testing/web-platform/tests/webstorage/event_body_attribute.js new file mode 100644 index 0000000000..a0e596da95 --- /dev/null +++ b/testing/web-platform/tests/webstorage/event_body_attribute.js @@ -0,0 +1,116 @@ +testStorages(function(storageString) { + async_test(function(t) { + assert_true(storageString in window, storageString + " exist"); + var storage = window[storageString]; + t.add_cleanup(function() { storage.clear() }); + + clearStorage(storageString, t.step_func(step0)); + assert_equals(storage.length, 0, "storage.length"); + + function step0(msg) + { + iframe.onload = t.step_func(step1); + // Null out the existing handler eventTestHarness.js set up; + // otherwise this test won't be testing much of anything useful. + iframe.contentWindow.onstorage = null; + iframe.src = "resources/event_body_handler.html"; + } + + function step1(msg) + { + storageEventList = new Array(); + storage.setItem('FOO', 'BAR'); + + runAfterNStorageEvents(t.step_func(step2), 1); + } + + function step2(msg) + { + if (msg != undefined) { + assert_unreached(msg); + } + assert_equals(storageEventList.length, 1); + assert_equals(storageEventList[0].key, "FOO"); + assert_equals(storageEventList[0].oldValue, null); + assert_equals(storageEventList[0].newValue, "BAR"); + + storage.setItem('FU', 'BAR'); + storage.setItem('a', '1'); + storage.setItem('b', '2'); + storage.setItem('b', '3'); + + runAfterNStorageEvents(t.step_func(step3), 5); + } + + function step3(msg) + { + if (msg != undefined) { + assert_unreached(msg); + } + assert_equals(storageEventList.length, 5); + assert_equals(storageEventList[1].key, "FU"); + assert_equals(storageEventList[1].oldValue, null); + assert_equals(storageEventList[1].newValue, "BAR"); + + assert_equals(storageEventList[2].key, "a"); + assert_equals(storageEventList[2].oldValue, null); + assert_equals(storageEventList[2].newValue, "1"); + + assert_equals(storageEventList[3].key, "b"); + assert_equals(storageEventList[3].oldValue, null); + assert_equals(storageEventList[3].newValue, "2"); + + assert_equals(storageEventList[4].key, "b"); + assert_equals(storageEventList[4].oldValue, "2"); + assert_equals(storageEventList[4].newValue, "3"); + + storage.removeItem('FOO'); + + runAfterNStorageEvents(t.step_func(step4), 6); + } + + function step4(msg) + { + if(msg != undefined) { + assert_unreached(msg); + } + assert_equals(storageEventList.length, 6); + assert_equals(storageEventList[5].key, "FOO"); + assert_equals(storageEventList[5].oldValue, "BAR"); + assert_equals(storageEventList[5].newValue, null); + + storage.removeItem('FU'); + + runAfterNStorageEvents(t.step_func(step5), 7); + } + + function step5(msg) + { + if(msg != undefined) { + assert_unreached(msg); + } + assert_equals(storageEventList.length, 7); + assert_equals(storageEventList[6].key, "FU"); + assert_equals(storageEventList[6].oldValue, "BAR"); + assert_equals(storageEventList[6].newValue, null); + + storage.clear(); + + runAfterNStorageEvents(t.step_func(step6), 8); + } + + function step6(msg) + { + if(msg != undefined) { + assert_unreached(msg); + } + assert_equals(storageEventList.length, 8); + assert_equals(storageEventList[7].key, null); + assert_equals(storageEventList[7].oldValue, null); + assert_equals(storageEventList[7].newValue, null); + + t.done(); + } + + }, storageString + " mutations fire StorageEvents that are caught by the event listener specified as an attribute on the body."); +}); diff --git a/testing/web-platform/tests/webstorage/event_body_handler.html b/testing/web-platform/tests/webstorage/event_body_handler.html new file mode 100644 index 0000000000..11d8ec9447 --- /dev/null +++ b/testing/web-platform/tests/webstorage/event_body_handler.html @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index e23a3530d8..b8fa70c0dd 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -5172,6 +5172,12 @@ "keyed" : true, "description" : "Exceptions thrown by add-ons" }, + "IPC_TRANSACTION_CANCEL": { + "alert_emails": ["billm@mozilla.com"], + "expires_in_version": "never", + "kind": "boolean", + "description": "True when an IPC transaction is canceled" + }, "IPC_SAME_PROCESS_MESSAGE_COPY_OOM_KB": { "expires_in_version": "50", "kind": "exponential", diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 941577a508..5b1be3e729 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -98,6 +98,7 @@ NS_EVENT_MESSAGE(eHashChange) NS_EVENT_MESSAGE(eImageAbort) NS_EVENT_MESSAGE(eLoadError) NS_EVENT_MESSAGE(ePopState) +NS_EVENT_MESSAGE(eStorage) NS_EVENT_MESSAGE(eBeforeUnload) NS_EVENT_MESSAGE(eReadyStateChange) diff --git a/widget/GfxInfoBase.cpp b/widget/GfxInfoBase.cpp index 438e6cceaa..1121ba9b12 100644 --- a/widget/GfxInfoBase.cpp +++ b/widget/GfxInfoBase.cpp @@ -1136,7 +1136,7 @@ nsresult GfxInfoBase::GetInfo(JSContext* aCx, JS::MutableHandle aResu const nsCString& GfxInfoBase::GetApplicationVersion() { - static nsAutoCString version; + static nsCString version; static bool versionInitialized = false; if (!versionInitialized) { // If we fail to get the version, we will not try again. diff --git a/widget/TextEventDispatcher.h b/widget/TextEventDispatcher.h index 018168e2cb..d95f128454 100644 --- a/widget/TextEventDispatcher.h +++ b/widget/TextEventDispatcher.h @@ -269,7 +269,7 @@ private: void Clear(); private: - nsAutoString mString; + nsString mString; RefPtr mClauses; TextRange mCaret; diff --git a/widget/gtk/WakeLockListener.cpp b/widget/gtk/WakeLockListener.cpp index ec16012c80..d321d00c48 100644 --- a/widget/gtk/WakeLockListener.cpp +++ b/widget/gtk/WakeLockListener.cpp @@ -63,7 +63,7 @@ private: void InhibitFailed(); void InhibitSucceeded(uint32_t aInhibitRequest); - nsAutoCString mTopic; + nsCString mTopic; DBusConnection* mConnection; DesktopEnvironment mDesktopEnvironment;