Bug 4398 - Calling a pinvoke method that has a char** signature (ref IntPtr) will cause the debugger to throw a null reference exception if a finally block is present with no catch block
Summary: Calling a pinvoke method that has a char** signature (ref IntPtr) will cause ...
Status: RESOLVED INVALID
Alias: None
Product: Runtime
Classification: Mono
Component: Debugger ()
Version: unspecified
Hardware: PC Linux
: --- normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2012-04-11 18:34 UTC by David Ferguson
Modified: 2012-04-13 02:07 UTC (History)
3 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Sample application that will cause exception (2.89 KB, text/x-csharp)
2012-04-11 18:34 UTC, David Ferguson
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED INVALID

Description David Ferguson 2012-04-11 18:34:50 UTC
Created attachment 1656 [details]
Sample application that will cause exception

I encountered a NullReferenceException when using calls to libblkid.  This only occurred when I was freeing resources in a finally block.  Here's a quick test app (also attached):

[DllImport("libblkid.so")]
private static extern IntPtr blkid_new_probe_from_filename([MarshalAs(UnmanagedType.LPStr)] string path);
[DllImport("libblkid.so")]
private static extern void blkid_do_probe(IntPtr probe);
[DllImport("libblkid.so")]
private static extern int blkid_probe_lookup_value(IntPtr probe, string name, out IntPtr uuid, ref int length);
[DllImport("libblkid.so")]
private static extern void blkid_free_probe(IntPtr probe);

public static int Main(string[] args)
{
    GetUuid("/dev/sda1");
    GetUuid("/dev/sda3");
    GetUuid("/dev/sda5");

    return 0;
}

public static void GetUuid(string name)
{
    var size = 0;
    IntPtr uuid = IntPtr.Zero;
    IntPtr probe = IntPtr.Zero;

    try
    {
        // name is typically "/dev/sda1"
        probe = blkid_new_probe_from_filename(name);
        if (probe != IntPtr.Zero) 
        {
            blkid_do_probe(probe);

            var attribute = @"UUID";
            var test = blkid_probe_lookup_value(probe, attribute, out uuid, ref size);
            Console.WriteLine("Test: " + test);
            if (uuid != IntPtr.Zero) {
                Console.WriteLine("Size: " + size);
                Console.WriteLine("UUID : " + Marshal.PtrToStringAnsi(uuid));
              }
        } else
        Console.WriteLine("No permissions!");
    }
//    catch (Exception e)
//    {
        // If this catch block doesn't exist (only the t/f), I get a null reference
        // exception on the line that first touches uuid after execution.  This seems
        // to be an issue with the soft debugger.
//        Console.WriteLine("Exception: " + e.Message);
//    }
    finally
    {
           if (probe != IntPtr.Zero)
                blkid_free_probe(probe);
    }
}

If I run this program in debug mode with the latest monodevelop and the latest mono (both master), I will get a null reference exception at 'if (uuid != IntPtr.Zero)'.  If I run this without the debugger, the application runs fine.  If I run it with the debugger and with the catch put back, it runs fine.  If I take the try/finally out, it runs fine. 

If I change the runtime framework to 2.10.5 (my system ubuntu install) the exception will not be thrown, however the console outputs for Size and UUID will not be shown (this is in debug mode, without the catch block or with it).  Note, I'm running from within MD, changing the framework options.  Running without the debugger will display the output.
Comment 1 Zoltan Varga 2012-04-12 04:08:13 UTC
I'm not sure this is the source of the problem, but the last parameter of blkid_probe_lookup_value is 
a 'size_t*', not an 'int*', which could be a 64 bit integer on x86-64. So it might be better to map it to
a 'ref long'.
Comment 2 David Ferguson 2012-04-12 09:03:00 UTC
Zoltan,

I completely missed that it was a size_t*.  I actually used IntPtr since I didn't want to have a conditional compile based on the platform I was targetting.  Both ref long and IntPtr seem to work fine on my 64 bit install.
Comment 3 Zoltan Varga 2012-04-12 12:03:11 UTC
So changing it to 'ref long' from 'ref int' fixes the problem ?
Comment 4 David Ferguson 2012-04-12 17:18:30 UTC
Yes, I tested both 'ref long' and 'ref IntPtr' and they both fix the behavior on my 64 bit linux box.  I chose to use 'ref IntPtr' because I didn't want multiple builds depending on the bitness of the platform.
Comment 5 Zoltan Varga 2012-04-13 02:07:13 UTC
-> NOTABUG then.