Menu

#31 Safe handle has been closed Exception

v2.2.8
open-duplicate
7
2017-12-06
2010-12-02
No

I'm getting the above exception with 2.2.8 (from UsbTransfer finalizer called from the GC); it looks as though it's caused by my UsbEndpointReader's TransferContext not being disposed. I've gone through the code and it seems like it's down to the way IDisposable has been implemented on some of the classes (so this may happen elsewhere). In your Finalizer you shouldn't access any members as, and is the case here (OverlappedTransferContext accesses UsbDevice.Handle (via OverlappedTransferContext->Wait()/UsbEndpointBase.Handle)) the member may already be disposed (you can't determine the order objects will be finalized).

Usually the pattern would be :

class x : IDisposable
{
private bool _disposed;

~x()
{
Dispose(false);
}

protected virtual void Dispose(bool disposing)
{
if(disposing && !_disposed)
{
_diposed = true;
/// do stuff here
}
}

void Dispose()
{
Dispose(true);
GC.SurpressFinalize(this);
}
}

Might just be quicker to dispose the context in UsbEndpointBase, but working in the finalizer is bound to cause problems sooner or later.

Discussion

  • Travis Robinson

    Travis Robinson - 2010-12-02

    Thanks for pointing this out. This was actually reported last week; I came to the same conclusion; that there were some issues in they way IDisposable was implemented in a few of the classes. :)

    The original report is here:
    https://sourceforge.net/tracker/?func=detail&atid=1140572&aid=3122105&group_id=206606

    Your tracker has more info, so I will keep them both. It should also notify when this issue is resolved.

    Thanks Again,
    Travis

     
  • Travis Robinson

    Travis Robinson - 2010-12-02
    • milestone: --> v2.2.8
    • priority: 5 --> 7
    • status: open --> open-duplicate
     
  • Chuck Gannon

    Chuck Gannon - 2014-04-15

    I am having a similar issue with our application.

    I have tried using the r113 release as well. I incorporated the code into our solution. If I disconnect our USB device and quickly reconnect, I get get exception in OverlappedTransferContext.cs in method Wait at line 97.

    The EndPointBase throwing the exception is always LibUsbDotNet.UsbEndpointWriter. The endpoint writer indicates it is already disposed and the EndpointBase.Handle indicates it is closed.

    If I dummy up the code and add a check for EndpointBase.Handle.IsClosed before calling GetOverlappedResult I can stop it from throwing. I'm guessing this is not the optimal solution. Also not sure if we are correctly closing everything when we detect disconnect (although our code follows the examples in the project).

    Any help you can provide would be appreciated. Thanks
    -Chuck

     
  • mayur p

    mayur p - 2017-12-06

    Hello,
    I am having similar issue. I am using version 2.2.8
    Whenever I switch Off-On my device at some point I get the object disposed exception.

    Request you to kindly help on this.
    Thank you...

    ~mayur

    Following is my code:

        private void UsbDeviceNotifier_OnDeviceNotify(object sender, DeviceNotifyEventArgs e)
         {
            switch (e.EventType)
            {
                case EventType.DeviceArrival:
    
                    if (!Connected)
                    {
                        try
                        {
                            //clear the info so far
                            if (usbDevice != null)
                            {
                                writer.Dispose();
                                wholeUsbDevice.ReleaseInterface(0);
                                wholeUsbDevice.Close();
                                usbDevice.Close();
                                UsbDevice.Exit();
                            }
    
                            if (usbDeviceFinder == null)
                            {
                                usbDeviceFinder = new UsbDeviceFinder(vendorId, productId);
                            }
    
                            if (e.Device.IdVendor == usbDeviceFinder.Vid && e.Device.IdProduct == usbDeviceFinder.Pid)
                            {
                                //Connect and Initialize
                                usbDevice = UsbDevice.OpenUsbDevice(usbDeviceFinder);
    
                                if (usbDevice == null)
                                {
                                    Connected = false;
                                    return;
                                }
    
                                wholeUsbDevice = usbDevice as IUsbDevice;
    
                                if (!ReferenceEquals(wholeUsbDevice, null))
                                {
                                    // This is a "whole" USB device. Before it can be used, 
                                    // the desired configuration and interface must be selected.
    
                                    // Select config #1
                                    wholeUsbDevice.SetConfiguration(1);
    
                                    // Claim interface #0.
                                    wholeUsbDevice.ClaimInterface(0);
                                }
    
                                writer = usbDevice.OpenEndpointWriter(WriteEndpointID.Ep02);
                                reader = usbDevice.OpenEndpointReader(ReadEndpointID.Ep01);
    
                                if (writer == null || writer.IsDisposed || reader == null || reader.IsDisposed)
                                {
                                    Connected = false;
                                    return;
                                }
    
                                Connected = true;
                            }
                        }
                        catch (Exception)
                        {
                            throw;
                        }
                    }
    
                    break;
    
                case EventType.DeviceRemoveComplete:
    
                    if (!(e.Device.IdVendor == usbDeviceFinder.Vid && e.Device.IdProduct == usbDeviceFinder.Pid))
                    {
                        return;
                    }
    
                    CloseConnection();
    
                    break;
    
                default:
                    break;
            }
        }
    
        public void CloseConnection()
        {
            Connected = false;
    
                try
                {
                    if (usbDevice != null)
                    {
                        if (usbDevice.IsOpen)
                        {
                            // If this is a "whole" usb device (libusb-win32, linux libusb-1.0)
                            // it exposes an IUsbDevice interface. If not (WinUSB) the 
                            // 'wholeUsbDevice' variable will be null indicating this is 
                            // an interface of a device; it does not require or support 
                            // configuration and interface selection.
                            IUsbDevice wholeUsbDevice = usbDevice as IUsbDevice;
    
                            if (!ReferenceEquals(wholeUsbDevice, null))
                            {
                                // Release interface #0.
                                wholeUsbDevice.ReleaseInterface(0);
                            }
    
                            usbDevice.Close();
                        }
                        //usbDevice = null;
                        ////Connected = false;
    
                        // Free usb resources
                        UsbDevice.Exit();
                    }
                }
                catch (Exception)
                {
                    throw;
                }
    
        }
    
          private CancellationTokenSource cancellationTokenSource;
    
        public byte[] WritePortData(byte[] data)
        {
    
                try
                {
                    using (cancellationTokenSource = new CancellationTokenSource(timeout))
                    {
                        var cancellationToken = cancellationTokenSource.Token;
    
                        if (cancellationToken.IsCancellationRequested)
                        {
                            cancellationToken.ThrowIfCancellationRequested();
                        }
    
                            if (writer == null || writer.IsDisposed)
                            {
                                TryReconnectDevice();
                            }
    
                            int bytesWritten;
                            ErrorCode errorCode;
    
                            if (writer.EndpointInfo != null)
                            {
                                errorCode = this.writer.Write(data, timeout, out bytesWritten);
    
                                if (errorCode != ErrorCode.None)
                                {
                                    if (TryReconnectDevice())
                                    {
                                        //reconnected, try to write to the device again
                                        errorCode = writer.Write(data, timeout, out bytesWritten);
    
                                        if (errorCode != ErrorCode.None)
                                        {
                                            RaiseDisconnectionEvent();
                                        }
                                    }
                                }
                            }
                    }
    
                    byte[] response = new byte[0];
    
                        response = ReadPortData(data);
                        return response;
                    }
                }
                catch (OperationCanceledException)
                {
                    throw new TimeoutException("Timeout");
                }
                catch (ObjectDisposedException oex)
                {
                    LogException("ReadPortData - ObjectDisposedException", oex);
                    throw;
                }
                catch (Exception ex)
                {
                    LogException("ReadPortData", ex);
                    throw;
                }
            }
        }
    
        private byte[] ReadPortData(byte[] data)
        {
            byte[] resp = new byte[0];
    
            if (usbDevice == null)
            {
                TryReconnectDevice();
            }
    
            if (reader == null || reader.IsDisposed)
            {
                TryReconnectDevice();
            }
    
            try
            {
                using (cancellationTokenSource = new CancellationTokenSource(timeout))
                {
                    var cancellationToken = cancellationTokenSource.Token;
    
                    if (cancellationToken.IsCancellationRequested)
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                    }
    
                    var readBuffer = new byte[Constants.USB_Block_Size];
                    reader.Flush();
                    int bytesRead;
    
                    ErrorCode errorCode;
    
                    errorCode = reader.Read(readBuffer, timeout, out bytesRead);
    
                    if (errorCode != ErrorCode.None)
                    {
                        if (TryReconnectDevice())
                        {
                            //reconnected, try to write to the device again
                            errorCode = reader.Read(readBuffer, timeout, out bytesRead);
    
                            string errorString = UsbDevice.LastErrorString;
    
                            if(errorCode == ErrorCode.IoTimedOut)
                            {
                                errorString = ErrorCode.IoTimedOut.ToString();
                            }
    
                            if (errorCode != ErrorCode.None)
                            {
                                throw new Exception(errorString);
                            }
                        }
                    }
    
                    resp = readBuffer.Skip(0).Take(bytesRead).ToArray();
                }
            }
            catch (Exception ex)
            {
                LogException("ReadPortData", ex);
                throw;
            }
    
            return resp;
        }
    
          public bool OpenConnection()
        {
            if (Connected)
            {
                return true;
            }
    
            try
            {
                lock (lockObject)
                {
                    //clear the info so far
                    if (usbDevice != null)
                    {
                        writer.Dispose();
                        wholeUsbDevice.ReleaseInterface(0);
                        wholeUsbDevice.Close();
                        usbDevice.Close();
                        UsbDevice.Exit();
                    }
    
                    //now start over
                    if (usbDeviceFinder == null)
                    {
                        usbDeviceFinder = new UsbDeviceFinder(vendorId, productId);
                    }
    
                    usbDevice = UsbDevice.OpenUsbDevice(usbDeviceFinder);
    
                    // If the device is open and ready
                    if (usbDevice == null)
                    {
                        //log the error
                        //Connected = false;
                        //return false;
                        throw new DeviceDisconnectedException();
                    }
                    else
                    {
                        wholeUsbDevice = usbDevice as IUsbDevice;
    
                        if (!ReferenceEquals(wholeUsbDevice, null))
                        {
                            // Select config #1
                            wholeUsbDevice.SetConfiguration(1);
    
                            // Claim interface #0.
                            wholeUsbDevice.ClaimInterface(0);
                        }
    
                        writer = usbDevice.OpenEndpointWriter(WriteEndpointID.Ep02);
                        reader = usbDevice.OpenEndpointReader(ReadEndpointID.Ep01);
    
                        if (writer == null || writer.IsDisposed || reader == null || reader.IsDisposed)
                        {
                            throw new DeviceNotReadyException();
                            //Connected = false;
                            //return false;
                        }
    
                        Connected = true;
                        return true;
                    } 
                }
            }
            catch (Exception ex)
            {
                LogException("OpenConnection", ex);
                throw;
            }
        }
    
        private bool TryReconnectDevice()
        {
            var connected = false;
    
            var retries = Constants.Retries;
    
            do
            {
                try
                {
                    connected = OpenConnection();
                    retries = Constants.Retries;
                    break;
                }
                catch (DeviceDisconnectedException)
                {
                    retries--;
                }
                catch (Exception ex)
                {
                    LogException("TryReconnectDevice", ex);
                    throw;
                }
    
            } while (retries > 0);
    
            if(retries <= 0)
            {
                throw new DeviceDisconnectedException();
                //PortClosed?.Invoke(this, new EventArgs());
            }
    
            return connected;
        }
    
     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.