为什么访问非托管内存会导致System.AccessViolationException?

时间:2016-11-14 01:47:33

标签: c# c++ dll pinvoke

我正在尝试使用XGBoost's dll(libxgboost.dll)来创建DMatrix(类似于2D数组)并获取它有多少列。它运行正常,直到它在下面的代码中的System.AccessViolationException行引发int cols = ...

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);
    }
  }
}

为什么访问使用XGDMatrixNumCol(dmatrixPtr, dmatrixColumnsPtr)分配的非托管内存会导致System.AccessViolationException

一种可能是我正在使用pinvoke错误地执行这些功能。以下是我使用的每个dll函数的定义:

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是我项目的回购。我正在使用Visual Studio Enterprise 2015。它在Windows 10 Pro(64位)上以“调试”模式(针对x64)构建。可以找到libxgboost.dll的x64二进制文件here。虽然链接的repo确实包含libxgboost.dll的副本。

1 个答案:

答案 0 :(得分:-1)

这是我感谢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);
    }
  }
}
相关问题