diff options
Diffstat (limited to 'ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp')
-rw-r--r-- | ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp new file mode 100644 index 0000000000..3af7ad620d --- /dev/null +++ b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp @@ -0,0 +1,138 @@ +#include "TestInterruptErrorCleanup.h" + +#include "base/task.h" +#include "mozilla/CondVar.h" +#include "mozilla/Mutex.h" + +#include "IPDLUnitTests.h" // fail etc. +#include "IPDLUnitTestSubprocess.h" + +using mozilla::CondVar; +using mozilla::Mutex; +using mozilla::MutexAutoLock; + +namespace mozilla { +namespace _ipdltest { + +//----------------------------------------------------------------------------- +// parent + +namespace { + +// NB: this test does its own shutdown, rather than going through +// QuitParent(), because it's testing degenerate edge cases + +void DeleteSubprocess(Mutex* mutex, CondVar* cvar) { + MutexAutoLock lock(*mutex); + + gSubprocess->Destroy(); + gSubprocess = nullptr; + + cvar->Notify(); +} + +void DeleteTheWorld() { + delete static_cast<TestInterruptErrorCleanupParent*>(gParentActor); + gParentActor = nullptr; + + // needs to be synchronous to avoid affecting event ordering on + // the main thread + Mutex mutex MOZ_UNANNOTATED("TestInterruptErrorCleanup.DeleteTheWorld.mutex"); + CondVar cvar(mutex, "TestInterruptErrorCleanup.DeleteTheWorld.cvar"); + + MutexAutoLock lock(mutex); + + XRE_GetIOMessageLoop()->PostTask( + NewRunnableFunction("DeleteSubprocess", DeleteSubprocess, &mutex, &cvar)); + + cvar.Wait(); +} + +void Done() { + static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); + nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID)); + appShell->Exit(); + + passed(__FILE__); +} + +} // namespace + +TestInterruptErrorCleanupParent::TestInterruptErrorCleanupParent() + : mGotProcessingError(false) { + MOZ_COUNT_CTOR(TestInterruptErrorCleanupParent); +} + +TestInterruptErrorCleanupParent::~TestInterruptErrorCleanupParent() { + MOZ_COUNT_DTOR(TestInterruptErrorCleanupParent); +} + +void TestInterruptErrorCleanupParent::Main() { + // This test models the following sequence of events + // + // (1) Parent: Interrupt out-call + // (2) Child: crash + // --[Parent-only hereafter]-- + // (3) Interrupt out-call return false + // (4) Close() + // --[event loop]-- + // (5) delete parentActor + // (6) delete childProcess + // --[event loop]-- + // (7) Channel::OnError notification + // --[event loop]-- + // (8) Done, quit + // + // See bug 535298 and friends; this seqeunce of events captures + // three differnent potential errors + // - Close()-after-error (semantic error previously) + // - use-after-free of parentActor + // - use-after-free of channel + // + // Because of legacy constraints related to nsNPAPI* code, we need + // to ensure that this sequence of events can occur without + // errors/crashes. + + MessageLoop::current()->PostTask( + NewRunnableFunction("DeleteTheWorld", DeleteTheWorld)); + + // it's a failure if this *succeeds* + if (CallError()) fail("expected an error!"); + + if (!mGotProcessingError) fail("expected a ProcessingError() notification"); + + // it's OK to Close() a channel after an error, because nsNPAPI* + // wants to do this + Close(); + + // we know that this event *must* be after the MaybeError + // notification enqueued by AsyncChannel, because that event is + // enqueued within the same mutex that ends up signaling the + // wakeup-on-error of |CallError()| above + MessageLoop::current()->PostTask(NewRunnableFunction("Done", Done)); +} + +void TestInterruptErrorCleanupParent::ProcessingError(Result aCode, + const char* aReason) { + if (aCode != MsgDropped) fail("unexpected processing error"); + mGotProcessingError = true; +} + +//----------------------------------------------------------------------------- +// child + +TestInterruptErrorCleanupChild::TestInterruptErrorCleanupChild() { + MOZ_COUNT_CTOR(TestInterruptErrorCleanupChild); +} + +TestInterruptErrorCleanupChild::~TestInterruptErrorCleanupChild() { + MOZ_COUNT_DTOR(TestInterruptErrorCleanupChild); +} + +mozilla::ipc::IPCResult TestInterruptErrorCleanupChild::AnswerError() { + _exit(0); + MOZ_CRASH("unreached"); +} + +} // namespace _ipdltest +} // namespace mozilla |