Search code examples
c#.net-coreraspberry-pi3pinvokelib-nfc

Invalid pointer exception using pinvoke on libnfc for string values


I am trying to communicate with an NFC reader/writer on a raspberry pi 3 using dotnet core.

I have to say that the different libnfc command line tools I used are all working fine (aka I can read and poll my tags, no problem on this side).

The idea is to use dotnet core and C# to orchestrate the libnfc library and it seems to work fine except as soon as the function I call returns a string, I get the following error message:

*** Error in `./NfcTest': free(): invalid pointer: 0x6d4ebc00 ***

NfcTest being the name of my app of course.

Here is the pinvoke definition

[DllImport("libnfc", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string nfc_version();

Please note that after looking up on the web I did add the [return] attribute myself but it did not change anything to the result. Same error is raised.

The code of the nfc_version in libnfc is here: https://github.com/nfc-tools/libnfc/blob/c3f739dea339a71c59d7d53ab6b0ecc477c3ab73/libnfc/nfc.c#L1325

It seems to return a "constant" and no do any freeing of any kind. So my guess would be that I misconfigured one of the attributes.

Another example is that I call the following:

[DllImport("libnfc", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern string nfc_device_get_name(IntPtr pnd);

While I can perfectly call other methods (i.e. poll) using the pointer (pnd param) calling this one returns the same error as with the Version method. Both methods returning a string are making me wondering if the problem would not be in the DllImport but I'm not too sure how to fix that.

Link to lib code for that example: https://github.com/nfc-tools/libnfc/blob/c3f739dea339a71c59d7d53ab6b0ecc477c3ab73/libnfc/nfc.c#L1215

Any wisdom would be greatly appreciated.


Solution

  • The comment from Matthew Watson and the link he shared had the correct answer!

    So I modified the pinvoke line like this:

    [DllImport("libnfc", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr nfc_version();
    

    Then I called it this way:

    public string Version()
    {
        IntPtr ptr = Functions.nfc_version();
        var str = Marshal.PtrToStringAuto(ptr);
        return str;   
    }
    

    And it works like a charm!

    Thanks!