GetProcessHeap / HeapAlloc导致内存损坏

时间:2014-03-23 17:39:31

标签: c++ windows memory-management dll

作为一个学习/测试我的限制练习,我正在尝试创建一个可以获取给定值的DLL,对其进行序列化,并对其进行反序列化以用于使用其他编译器编译的程序。到目前为止,一切都好于预期。但是,我遇到了一个似乎是内存损坏的问题。

这是我正在使用的代码:

//POD_base.h: contains the base template POD (plain old data) class. Also contains memory allocation and deallocation functions.
namespace pod_helpers
{
  void* pod_malloc(size_t size)
  {
    HANDLE heapHandle = GetProcessHeap();
    HANDLE storageHandle = nullptr;

    if (heapHandle == nullptr)
    {
      return nullptr;
    }

    storageHandle = HeapAlloc(heapHandle, 0, size);

    return storageHandle;
  }

  void pod_free(void* ptr)
  {
    HANDLE heapHandle = GetProcessHeap();
    if (heapHandle == nullptr)
    {
      return;
    }

    if (ptr == nullptr)
    {
      return;
    }

    HeapFree(heapHandle, 0, ptr);
  }
}

template<typename T>
class pod
{
protected:
  pod();
  pod(const T& value);
  pod(const pod& copy);                   // no copy ctor in any pod
  ~pod();

  pod<T>& operator=(pod<T> value);
  operator T() const;

  T get() const;
  void swap(pod<T>& first, pod<T>& second);
};

pod的{​​{1}}专门化:

int

我的DLL利用了这样的幕后类型转换:

//POD_basic_types.h: contains pod specializations for basic datatypes
template<>
class pod<int>
{
  typedef int original_type; //these typedefs are meant to make the specializations easier to write and understand, since they're all the same except for the underlying datatypes.
  typedef std::int32_t safe_type;

public:
  pod() : data(nullptr) {}

  pod(const original_type& value)
  {
    set_from(value);
  }

  pod(const pod<original_type>& copyVal)
  {
    original_type copyData = copyVal.get();
    set_from(copyData);
  }

  ~pod()
  {
    release();
  }

  pod<original_type>& operator=(pod<original_type> value)
  {
    swap(*this, value);

    return *this;
  }

  operator original_type() const
  {
    return get();
  }

protected:
  safe_type* data;

  original_type get() const
  {
    original_type result;

    result = static_cast<original_type>(*data);

    return result;
  }

  void set_from(const original_type& value)
  {
    data = reinterpret_cast<safe_type*>(pod_helpers::pod_malloc(sizeof(safe_type)));

    if (data == nullptr)
    {
      return;
    }

    new(data) safe_type (value);
  }

  void release()
  {
    if (data)
    {
      pod_helpers::pod_free(data);
      data = nullptr;
    }
  }

  void swap(pod<original_type>& first, pod<original_type>& second)
  {
    using std::swap;

    swap(first.data, second.data);
  }
};

然后我的测试程序通过virtual pod<int> Add(const pod<int> number1, const pod<int> number2); pod<int> CCDLL_v1_implementation::Add(const pod<int> number1, const pod<int> number2) { int workingNum1, workingNum2; workingNum1 = number1; workingNum2 = number2; return workingNum1 + workingNum2; } / LoadLibrary加载DLL。到现在为止还挺好;我已经确认实际加载了DLL并调用了GetProcAddress函数。我还验证了使用正确的值调用Add的{​​{1}}。但是,这就是事情发生的地方。

我希望pod<int>为一个set_from(在本例中为set_from)值分配足够的空间,然后将传递的值存储在已分配的内存中。当我在safe_type中检查std::int32_t的值时,似乎就是这种情况。但是,当我通过*data检索set_from的值时,广告连播的pod<int>似乎是垃圾。它不再指向get期间data传递的值。

我知道在EXE方面调用了pod,在DLL方面调用了set_from。我对这个过程的理解如下:

set_from

这似乎是破坏DLL或EXE必须访问其他分配的内存的地方。我见过elsewhere on SO使用get / EXE -> creates pod<int> (allocating memory via GetProcessHeap/HeapAlloc) -> constructs the pod with a given value, which is passed to set_from. The DLL's Add function is called, with the given pod passed to it. DLL -> accesses pod<int> -> gets the pod's stored value via get -> accesses the memory the EXE allocated DLL does its calculations (here, a simple addition) with the pod's value DLL -> creates pod<int> (allocating memory via GetProcessHeap/HeapAlloc) -> constructs the pod with a given value, which is passed to set_from. The DLL's newly-constructed pod is returned to the EXE. EXE -> accesses the pod's internal value via get -> accesses the memory the DLL allocated 的这种组合应跨DLL边界工作。 HeapCreate's documentation也暗示了同样的想法:

  

私有堆对象的内存只能由创建它的进程访问。如果动态链接库(DLL)创建私有堆,则会在调用DLL的进程的地址空间中创建堆,并且只能由该进程访问它。

the documentation for GetProcessHeap(强调我的):

  

GetProcessHeap函数获取调用进程的默认堆的句柄

然而,奇怪的是,GlobalAlloc遇到了同样的问题GetProcessHeap / HeapAlloc,让我进一步质疑这里出了什么问题。甚至更奇怪,当我使用相同的编译器编译EXE和DLL时,一切都按预期工作。

我对这个分配/解除分配过程的工作方式做出了错误的假设吗?我应该使用GetProcessHeap / HeapAlloc以外的其他内容吗?或者我只是想做不可能的事情?


使用评论中获得的信息进行更新:

通过引用传递GetProcessHeapHeapAlloc正常工作。只传递值不会。

我是否将“unwrapped”参数传递给pod - 获取函数或者我是否首先将参数包装在CCDLL_v1_implementation::Add(const pod<int>& number1, const pod<int>& number2)中似乎无关紧要:

pod

产生与

相同的损坏pod
pod<int> a = 9;
pod<int> b = 2;

CCDLL_lib->Add(a, b);

唯一的区别似乎是在data s中首先包装参数会在调用CCDLL_lib->Add(9, 2); 时调用copy c'tor,而保留参数unwrapped只会调用常规c'tor。 / p>

这似乎也不是类布局问题:

pod

在EXE / DLL边界的两边评估为true。


我设法证明问题在于EXE / DLL边界,尽管我仍然不知道为什么。

我在DLL中添加了一个新方法,因此我可以专注于一个参数而不是两个:

Add

然后我这样称呼它:

if (reinterpret_cast<const void*>(&data) == reinterpret_cast<const void*>(this))
{
  //simple debug messagebox here
}

从一系列调试消息框中,出现以下序列:

void Square(pod<int> number);

如果我更改pod<int> a = 9; CCDLL_lib->Square(a); 以接受引用(Regular c'tor called (EXE) set_from(9) called (EXE) copy c'tor called (EXE) get returns 9 to the copy c'tor (EXE) set_from(9) called (EXE) Square called (DLL) with an invalid pod (Visual Studio shows the data pointer pointing to garbage at this point) ),则会出现以下序列:

Square

0 个答案:

没有答案