Thread Rating:
  • 0 Votes - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
DviSessionUpnp::Post crash after device destroyed
03-09-2016, 08:58 PM
Post: #1
DviSessionUpnp::Post crash after device destroyed
I am seeing an access violation if the application (device stack) destroys the device while an incoming request is in progress.

I haven't been able to find the exact location of the crash. The following is written to standard output:

ohNet fatal error: Unhandled exception AssertionFailed at Os/Windows/SignalHandlers.cpp:19 in thread UpnpSession 1
_OhNetLibraryStartCombined@4
RtlRaiseStatus
RtlRaiseStatus
KiUserExceptionDispatcher
EtwEventEnabled
_OhNetLibraryStartCombined@4
??0DvInvocationCPrivate@Net@OpenHome@@QAE@AAVIDviInvocation@12@@Z
??0DvInvocationCPrivate@Net@OpenHome@@QAE@AAVIDviInvocation@12@@Z
??0DvInvocationCPrivate@Net@OpenHome@@QAE@AAVIDviInvocation@12@@Z
?CallAssertHandlerVA@OpenHome@@YAXPBDI0ZZ
??1AutoSemaphore@OpenHome@@QAE@XZ
_OhNetLibraryStartCombined@4
RtlInitializeExceptionChain
RtlInitializeExceptionChain

From looking at the log outout, it appears the access violation is somewhere in this code in DviSessionUpnp::Post():

Code:
else {
    iDechunker->SetChunked(true);
    for (;;) {
        Brn buf = iDechunker->Read(kMaxRequestBytes); // expect much less than this to be returned
        if (buf.Bytes() == 0) { // end of stream
            break;
        }
        if (iSoapRequest.Bytes() + buf.Bytes() > iSoapRequest.MaxBytes()) {
            iErrorStatus = &HttpStatus::kRequestEntityTooLarge;
            THROW(ReaderError);
        }
        iSoapRequest.Append(buf);
    }
}

Invoke();

The device is destroyed while iDechunker->Read is waiting for input. The iDechunker->Read call returns some data after the device has been destroyed but the Invoke() line is never reached.

The application code that destroys the device disposes the provider and then destroys the device. Is this correct or should I be doing something more?

I am attaching an extract from the MinimServer log file. The sequence of events is as follows:

Lines 1-28: successful GetSearchCapabilities request
Lines 29-41: start of GetSortCapabilities request
Lines 42-243: device destroyed by the application
Lines 354-355: completion of GetSortCapabilities request
Line 365: ohNet crash

Please let me know if I can provide any further information. The crash is easily reproducible.


Attached File(s)
.txt  CrashLog.txt (Size: 30.92 KB / Downloads: 0)
Find all posts by this user
11-09-2016, 09:51 PM
Post: #2
RE: DviSessionUpnp::Post crash after device destroyed
I have identifed the cause of this crash. The sequence of events is as follows:

1) In DviSessionUpnp::Post (line 731 of DviServerUpnp.cpp), the code obtains pointers to the invocation device and service. At this point, the device has not been destroyed and these pointers are valid.

2) Later in the same method, (line 765 of DviServerUpnp.cpp), there is a call to DviSessionUpnp::Invoke and this method (at line 1035) calls Invoke() on iInvocationService.

3) By this time, the device has been destroyed and the invocation device and service objects have been deleted, so iInvocationDevice and iInvocationService are both pointing to random memory.

4) In DviSessionUpnp::Invoke (line 164 of DviService.cpp), the call to iLock.Wait() causes an access violation because iLock is not pointing to a valid Mutex object.

I am attaching a patch to fix this problem. It adds references to the device and service objects to prevent these objects being deleted while they are in use by DviSessionUpnp::Post and DviSessionUpnp::Invoke. The changes are as follows:

a) Change the DeviceMap::Find method to add a reference to the DviDevice object that is returned

b) Add a new overloaded DviService::ServiceReference method to find a service by name and add a reference to the DviService object that is returned

c) Change the DviSessionUpnp::ParseRequestUri method to use the new DviService::ServiceReference method and make similar changes in DviProviderSubscriptionLongPoll::Subscribe and DviSessionWebSocket::Subscribe

d) Create new utility classes AutoDeviceRef and AutoServiceRef to release the references automatically when the caller stack unwinds. Use these classes in DviSessionUpnp::Post, DviSessionUpnp::Subscribe, DviSessionUpnp::Unsubscribe, DviSessionUpnp::Renew, DviProviderSubscriptionLongPoll::Subscribe and DviSessionWebSocket::Subscribe to ensure that the references will always be released even if an exception is thrown.

I have tested the fix and I have verified that it works as intended. If the device is destroyed after the call to ParseRequestUri in DviSessionUpnp::Post and before the call to Invoke in DviSessionUpnp::Post, ohNet returns an error 500 response instead of crashing.


Attached File(s)
.zip  serviceref.zip (Size: 4.04 KB / Downloads: 1)
Find all posts by this user
22-09-2016, 03:37 PM
Post: #3
RE: DviSessionUpnp::Post crash after device destroyed
(11-09-2016 09:51 PM)simoncn Wrote:  I am attaching a patch to fix this problem.

Thanks. The patch looks good; I've applied it locally so it'll hopefully be on github this evening.
Find all posts by this user
24-09-2016, 10:13 AM
Post: #4
RE: DviSessionUpnp::Post crash after device destroyed
(22-09-2016 03:37 PM)simonc Wrote:  Thanks. The patch looks good; I've applied it locally so it'll hopefully be on github this evening.

Thanks very much!
Find all posts by this user


Forum Jump: