Why does accessing unmanaged memory cause a System

2019-09-20 02:52发布

问题:

This question already has an answer here:

  • Use XGBoost DLL from c# via p/invoke 1 answer

I'm trying to use XGBoost's dll (libxgboost.dll) to create a DMatrix (which is like a 2D array) and get how many columns it has. It runs fine until it throws a System.AccessViolationException at the int cols = ... line in the code below:

using System;
using System.Runtime.InteropServices;

namespace basicXgboost
{
  class Program
  {
    [DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
    public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, IntPtr outputPtr);

    [DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
    public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, IntPtr dmatrixColumnsPtr);

    static void Main(string[] args)
    {
      IntPtr dmatrixPtr = Marshal.AllocHGlobal(1000000);
      IntPtr dmatrixColumnsPtr = Marshal.AllocHGlobal(10);

      int result = XGDMatrixCreateFromFile("../../libs/test.txt", 0, dmatrixPtr);
      int cols = XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr);

      Marshal.FreeHGlobal(dmatrixPtr);
      Marshal.FreeHGlobal(dmatrixColumnsPtr);
    }
  }
}

Why does accessing unmanaged memory allocated with XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr) cause a System.AccessViolationException?

One possibility might be that I'm using pinvoke incorrectly for these functions. Below are the definitions for each dll function I use:

XGDMatrixCreateFromFile()

/*!
 * \brief load a data matrix
 * \param fname the name of the file
 * \param silent whether print messages during loading
 * \param out a loaded data matrix
 * \return 0 when success, -1 when failure happens
 */
XGB_DLL int XGDMatrixCreateFromFile(const char *fname,
                                    int silent,
                                    DMatrixHandle *out);

XGDMatrixNumCol()

/*!
 * \brief get number of columns
 * \param handle the handle to the DMatrix
 * \param out The output of number of columns
 * \return 0 when success, -1 when failure happens
 */
XGB_DLL int XGDMatrixNumCol(DMatrixHandle handle,
                            bst_ulong *out);

Here is the repo for my project. I'm using Visual Studio Enterprise 2015 . It's built in "Debug" mode (targeting x64) on Windows 10 Pro (64-bit). x64 binaries for libxgboost.dll can be found here. Although the linked repo does contain a copy of libxgboost.dll.

回答1:

Here's the solution I've got thanks to NineBerry's answer.

using System;
using System.Runtime.InteropServices;

namespace basicXgboost
{
  class Program
  {
    [DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
    public static extern int XGDMatrixCreateFromFile([MarshalAs(UnmanagedType.LPStr)] string file, int silent, out IntPtr outputPtr);

    [DllImport("../../libs/libxgboost.dll", CharSet = CharSet.Auto)]
    public static extern int XGDMatrixNumCol(IntPtr dmatrixPtr, out ulong dmatrixColumnsPtr);

    static void Main(string[] args)
    {
      IntPtr dmatrixPtr;
      ulong dmatrixColumns;

      int result = XGDMatrixCreateFromFile("../../libs/test.txt", 0, out dmatrixPtr);
      int cols = XGDMatrixNumCol(dmatrixPtr, out dmatrixColumns);
    }
  }
}


标签: c# c++ dll pinvoke