ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,155 @@
     1.4 +#include "TestInterruptErrorCleanup.h"
     1.5 +
     1.6 +#include "mozilla/CondVar.h"
     1.7 +#include "mozilla/Mutex.h"
     1.8 +
     1.9 +#include "IPDLUnitTests.h"      // fail etc.
    1.10 +#include "IPDLUnitTestSubprocess.h"
    1.11 +
    1.12 +using mozilla::CondVar;
    1.13 +using mozilla::Mutex;
    1.14 +using mozilla::MutexAutoLock;
    1.15 +
    1.16 +namespace mozilla {
    1.17 +namespace _ipdltest {
    1.18 +
    1.19 +//-----------------------------------------------------------------------------
    1.20 +// parent
    1.21 +
    1.22 +namespace {
    1.23 +
    1.24 +// NB: this test does its own shutdown, rather than going through
    1.25 +// QuitParent(), because it's testing degenerate edge cases
    1.26 +
    1.27 +void DeleteSubprocess(Mutex* mutex, CondVar* cvar)
    1.28 +{
    1.29 +    MutexAutoLock lock(*mutex);
    1.30 +
    1.31 +    delete gSubprocess;
    1.32 +    gSubprocess = nullptr;
    1.33 +
    1.34 +    cvar->Notify();
    1.35 +}
    1.36 +
    1.37 +void DeleteTheWorld()
    1.38 +{
    1.39 +    delete static_cast<TestInterruptErrorCleanupParent*>(gParentActor);
    1.40 +    gParentActor = nullptr;
    1.41 +
    1.42 +    // needs to be synchronous to avoid affecting event ordering on
    1.43 +    // the main thread
    1.44 +    Mutex mutex("TestInterruptErrorCleanup.DeleteTheWorld.mutex");
    1.45 +    CondVar cvar(mutex, "TestInterruptErrorCleanup.DeleteTheWorld.cvar");
    1.46 +
    1.47 +    MutexAutoLock lock(mutex);
    1.48 +
    1.49 +    XRE_GetIOMessageLoop()->PostTask(
    1.50 +      FROM_HERE,
    1.51 +      NewRunnableFunction(DeleteSubprocess, &mutex, &cvar));
    1.52 +
    1.53 +    cvar.Wait();
    1.54 +}
    1.55 +
    1.56 +void Done()
    1.57 +{
    1.58 +  static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
    1.59 +  nsCOMPtr<nsIAppShell> appShell (do_GetService(kAppShellCID));
    1.60 +  appShell->Exit();
    1.61 +
    1.62 +  passed(__FILE__);
    1.63 +}
    1.64 +
    1.65 +} // namespace <anon>
    1.66 +
    1.67 +TestInterruptErrorCleanupParent::TestInterruptErrorCleanupParent()
    1.68 +    : mGotProcessingError(false)
    1.69 +{
    1.70 +    MOZ_COUNT_CTOR(TestInterruptErrorCleanupParent);
    1.71 +}
    1.72 +
    1.73 +TestInterruptErrorCleanupParent::~TestInterruptErrorCleanupParent()
    1.74 +{
    1.75 +    MOZ_COUNT_DTOR(TestInterruptErrorCleanupParent);
    1.76 +}
    1.77 +
    1.78 +void
    1.79 +TestInterruptErrorCleanupParent::Main()
    1.80 +{
    1.81 +    // This test models the following sequence of events
    1.82 +    //
    1.83 +    // (1) Parent: Interrupt out-call
    1.84 +    // (2) Child: crash
    1.85 +    // --[Parent-only hereafter]--
    1.86 +    // (3) Interrupt out-call return false
    1.87 +    // (4) Close()
    1.88 +    // --[event loop]--
    1.89 +    // (5) delete parentActor
    1.90 +    // (6) delete childProcess
    1.91 +    // --[event loop]--
    1.92 +    // (7) Channel::OnError notification
    1.93 +    // --[event loop]--
    1.94 +    // (8) Done, quit
    1.95 +    //
    1.96 +    // See bug 535298 and friends; this seqeunce of events captures
    1.97 +    // three differnent potential errors
    1.98 +    //  - Close()-after-error (semantic error previously)
    1.99 +    //  - use-after-free of parentActor
   1.100 +    //  - use-after-free of channel
   1.101 +    //
   1.102 +    // Because of legacy constraints related to nsNPAPI* code, we need
   1.103 +    // to ensure that this sequence of events can occur without
   1.104 +    // errors/crashes.
   1.105 +
   1.106 +    MessageLoop::current()->PostTask(
   1.107 +        FROM_HERE, NewRunnableFunction(DeleteTheWorld));
   1.108 +
   1.109 +    // it's a failure if this *succeeds*
   1.110 +    if (CallError())
   1.111 +        fail("expected an error!");
   1.112 +
   1.113 +    if (!mGotProcessingError)
   1.114 +        fail("expected a ProcessingError() notification");
   1.115 +
   1.116 +    // it's OK to Close() a channel after an error, because nsNPAPI*
   1.117 +    // wants to do this
   1.118 +    Close();
   1.119 +
   1.120 +    // we know that this event *must* be after the MaybeError
   1.121 +    // notification enqueued by AsyncChannel, because that event is
   1.122 +    // enqueued within the same mutex that ends up signaling the
   1.123 +    // wakeup-on-error of |CallError()| above
   1.124 +    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction(Done));
   1.125 +}
   1.126 +
   1.127 +void
   1.128 +TestInterruptErrorCleanupParent::ProcessingError(Result what)
   1.129 +{
   1.130 +    if (what != MsgDropped)
   1.131 +        fail("unexpected processing error");
   1.132 +    mGotProcessingError = true;
   1.133 +}
   1.134 +
   1.135 +//-----------------------------------------------------------------------------
   1.136 +// child
   1.137 +
   1.138 +TestInterruptErrorCleanupChild::TestInterruptErrorCleanupChild()
   1.139 +{
   1.140 +    MOZ_COUNT_CTOR(TestInterruptErrorCleanupChild);
   1.141 +}
   1.142 +
   1.143 +TestInterruptErrorCleanupChild::~TestInterruptErrorCleanupChild()
   1.144 +{
   1.145 +    MOZ_COUNT_DTOR(TestInterruptErrorCleanupChild);
   1.146 +}
   1.147 +
   1.148 +bool
   1.149 +TestInterruptErrorCleanupChild::AnswerError()
   1.150 +{
   1.151 +    _exit(0);
   1.152 +    NS_RUNTIMEABORT("unreached");
   1.153 +    return false;
   1.154 +}
   1.155 +
   1.156 +
   1.157 +} // namespace _ipdltest
   1.158 +} // namespace mozilla

mercurial