ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

     1 #include "TestInterruptErrorCleanup.h"
     3 #include "mozilla/CondVar.h"
     4 #include "mozilla/Mutex.h"
     6 #include "IPDLUnitTests.h"      // fail etc.
     7 #include "IPDLUnitTestSubprocess.h"
     9 using mozilla::CondVar;
    10 using mozilla::Mutex;
    11 using mozilla::MutexAutoLock;
    13 namespace mozilla {
    14 namespace _ipdltest {
    16 //-----------------------------------------------------------------------------
    17 // parent
    19 namespace {
    21 // NB: this test does its own shutdown, rather than going through
    22 // QuitParent(), because it's testing degenerate edge cases
    24 void DeleteSubprocess(Mutex* mutex, CondVar* cvar)
    25 {
    26     MutexAutoLock lock(*mutex);
    28     delete gSubprocess;
    29     gSubprocess = nullptr;
    31     cvar->Notify();
    32 }
    34 void DeleteTheWorld()
    35 {
    36     delete static_cast<TestInterruptErrorCleanupParent*>(gParentActor);
    37     gParentActor = nullptr;
    39     // needs to be synchronous to avoid affecting event ordering on
    40     // the main thread
    41     Mutex mutex("TestInterruptErrorCleanup.DeleteTheWorld.mutex");
    42     CondVar cvar(mutex, "TestInterruptErrorCleanup.DeleteTheWorld.cvar");
    44     MutexAutoLock lock(mutex);
    46     XRE_GetIOMessageLoop()->PostTask(
    47       FROM_HERE,
    48       NewRunnableFunction(DeleteSubprocess, &mutex, &cvar));
    50     cvar.Wait();
    51 }
    53 void Done()
    54 {
    55   static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
    56   nsCOMPtr<nsIAppShell> appShell (do_GetService(kAppShellCID));
    57   appShell->Exit();
    59   passed(__FILE__);
    60 }
    62 } // namespace <anon>
    64 TestInterruptErrorCleanupParent::TestInterruptErrorCleanupParent()
    65     : mGotProcessingError(false)
    66 {
    67     MOZ_COUNT_CTOR(TestInterruptErrorCleanupParent);
    68 }
    70 TestInterruptErrorCleanupParent::~TestInterruptErrorCleanupParent()
    71 {
    72     MOZ_COUNT_DTOR(TestInterruptErrorCleanupParent);
    73 }
    75 void
    76 TestInterruptErrorCleanupParent::Main()
    77 {
    78     // This test models the following sequence of events
    79     //
    80     // (1) Parent: Interrupt out-call
    81     // (2) Child: crash
    82     // --[Parent-only hereafter]--
    83     // (3) Interrupt out-call return false
    84     // (4) Close()
    85     // --[event loop]--
    86     // (5) delete parentActor
    87     // (6) delete childProcess
    88     // --[event loop]--
    89     // (7) Channel::OnError notification
    90     // --[event loop]--
    91     // (8) Done, quit
    92     //
    93     // See bug 535298 and friends; this seqeunce of events captures
    94     // three differnent potential errors
    95     //  - Close()-after-error (semantic error previously)
    96     //  - use-after-free of parentActor
    97     //  - use-after-free of channel
    98     //
    99     // Because of legacy constraints related to nsNPAPI* code, we need
   100     // to ensure that this sequence of events can occur without
   101     // errors/crashes.
   103     MessageLoop::current()->PostTask(
   104         FROM_HERE, NewRunnableFunction(DeleteTheWorld));
   106     // it's a failure if this *succeeds*
   107     if (CallError())
   108         fail("expected an error!");
   110     if (!mGotProcessingError)
   111         fail("expected a ProcessingError() notification");
   113     // it's OK to Close() a channel after an error, because nsNPAPI*
   114     // wants to do this
   115     Close();
   117     // we know that this event *must* be after the MaybeError
   118     // notification enqueued by AsyncChannel, because that event is
   119     // enqueued within the same mutex that ends up signaling the
   120     // wakeup-on-error of |CallError()| above
   121     MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction(Done));
   122 }
   124 void
   125 TestInterruptErrorCleanupParent::ProcessingError(Result what)
   126 {
   127     if (what != MsgDropped)
   128         fail("unexpected processing error");
   129     mGotProcessingError = true;
   130 }
   132 //-----------------------------------------------------------------------------
   133 // child
   135 TestInterruptErrorCleanupChild::TestInterruptErrorCleanupChild()
   136 {
   137     MOZ_COUNT_CTOR(TestInterruptErrorCleanupChild);
   138 }
   140 TestInterruptErrorCleanupChild::~TestInterruptErrorCleanupChild()
   141 {
   142     MOZ_COUNT_DTOR(TestInterruptErrorCleanupChild);
   143 }
   145 bool
   146 TestInterruptErrorCleanupChild::AnswerError()
   147 {
   148     _exit(0);
   149     NS_RUNTIMEABORT("unreached");
   150     return false;
   151 }
   154 } // namespace _ipdltest
   155 } // namespace mozilla

mercurial