libimobiledevice-win32 / imobiledevice-net

.NET (C#, VB.NET,...) bindings for libimobiledevice
GNU Lesser General Public License v2.1
297 stars 77 forks source link

PlistHandle Dispose System.System.AccessViolationException #167

Open karthikeyan1241997 opened 3 years ago

karthikeyan1241997 commented 3 years ago

I am getting AccessViolationException When GC finializes PlistHandle or when i call plistHandle.Dispose(). Issue occurred in Windows 10(64 bit) running latest version. Targeting .NET framework 4.6.2

Here is the Statcktrace:

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at iMobileDevice.Plist.PlistNativeMethods.plist_free(IntPtr plist)
   at iMobileDevice.Plist.PlistApi.plist_free(IntPtr plist)
   at iMobileDevice.Plist.PlistHandle.ReleaseHandle()
   at System.Runtime.InteropServices.SafeHandle.InternalFinalize()
   at System.Runtime.InteropServices.SafeHandle.Dispose(Boolean disposing)
   at System.Runtime.InteropServices.SafeHandle.Finalize()

Code Causing this Exception:

 lockdownError = Lockdown.lockdownd_get_value(lockdownClientHandle, null, null, out PlistHandle valuePlist);
 if(lockdownError != LockdownError.Success)
 {
       Debug.WriteLine("Failed. Error:" + lockdownError);
       continue;
 }
 Plist.plist_get_string_val(Plist.plist_dict_get_item(valuePlist, "DeviceName"), out string deviceName);
 Plist.plist_get_string_val(Plist.plist_dict_get_item(valuePlist, "BuildVersion"), out string buildVersion);
 Plist.plist_get_string_val(Plist.plist_dict_get_item(valuePlist, "SerialNumber"), out string serialNumber);
 Plist.plist_get_string_val(Plist.plist_dict_get_item(valuePlist, "ProductType"), out string productType);
 Plist.plist_get_string_val(Plist.plist_dict_get_item(valuePlist, "DeviceClass"), out string deviceClass);
karthikeyan1241997 commented 3 years ago

Seems issue is due to ValuePlist is disposed first before disposing the inner values handles. Exception can be avoided by manually disposing the inner plist data handles.

Updated sample:

PlistHandle deviceNameHandle = Plist.plist_dict_get_item(valuePlist, "DeviceName");
Plist.plist_get_string_val(deviceNameHandle, out string deviceName);
PlistHandle buildVersionHandle = Plist.plist_dict_get_item(valuePlist, "BuildVersion");
Plist.plist_get_string_val(buildVersionHandle, out string buildVersion);
PlistHandle serialNumberHandle = Plist.plist_dict_get_item(valuePlist, "SerialNumber");
Plist.plist_get_string_val(serialNumberHandle, out string serialNumber);
PlistHandle productTypeHandle = Plist.plist_dict_get_item(valuePlist, "ProductType");
Plist.plist_get_string_val(productTypeHandle, out string productType);
PlistHandle deviceClassHandle = Plist.plist_dict_get_item(valuePlist, "DeviceClass");
Plist.plist_get_string_val(deviceClassHandle, out string deviceClass);

 // Dispose inner Plist handles before Releasing ValuePlist Handle so that
 // System.AccessViolationException is avoided.
deviceNameHandle.Dispose();
buildVersionHandle.Dispose();
serialNumberHandle.Dispose();
productTypeHandle.Dispose();
deviceClassHandle.Dispose();