C语言 为什么这个结构文字在VS2013中通过地址传递时会损坏,而不是gcc / clang



我正在为我维护的库组合一个Visual Studio 2013解决方案。该库主要使用竞技场分配,因此我们有一个分配器接口:

分配器.h

#define HAMMER_ALLOCATOR__H__
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct HAllocator_ {
    void* (*alloc)(struct HAllocator_* allocator, size_t size);
    void* (*realloc)(struct HAllocator_* allocator, void* ptr, size_t size);
    void (*free)(struct HAllocator_* allocator, void* ptr);
} HAllocator;
[... API functions ... ]
#ifdef __cplusplus
}
#endif
#endif

我们还实现了围绕mallocreallocfree的包装器:

system_allocator.c

#include <string.h>
#include <stdlib.h> 
#include "internal.h"
void* system_alloc(HAllocator *allocator, size_t size) { 
    void* ptr = malloc(size + sizeof(size_t));
    *(size_t*)ptr = size;
    return (uint8_t*)ptr + sizeof(size_t);
}
void* system_realloc(HAllocator *allocator, void* ptr, size_t size) {
    if (ptr == NULL)
        return system_alloc(allocator, size);
    ptr = realloc((uint8_t*)ptr - sizeof(size_t), size + sizeof(size_t));
    *(size_t*)ptr = size;
    return (uint8_t*)ptr + sizeof(size_t);
}
void system_free(HAllocator *allocator, void* ptr) {
    if (ptr != NULL)
        free((uint8_t*)ptr - sizeof(size_t));
}
HAllocator system_allocator = {
    .alloc = &system_alloc,
    .realloc = &system_realloc,
    .free = &system_free,
};

全局system_allocatorinternal.h 中声明为 extern#include s allocator.h ),并导出为符号(在 .def 文件中)。但是,显然该结构从未初始化过,因为当我的单元测试尝试按地址将system_allocator传递给取消引用alloc成员的函数时,它们会出错,并显示"在 hammer-test 中0x000007FEFAD3EB6D(hammer.dll)处未处理的异常.exe:0xC0000005:访问违规读取位置0xFFFFFFFFFFFFFFFF。

在调试器中检查传入的指针表明某些内容肯定不正确:

  • mm__ 0x000000013fb0a094 {锤子测试.exe!HAllocator_ system_allocator} {alloc=0x25ff00019ff625ff realloc=...} HAllocator_ *
    • 分配0x25ff00019ff625ff无效 * (HAllocator_ *,无符号__int64) *
    • Realloc 0x9ffa25ff00019ff8 无效 * (HAllocator_ *, 无效 *, 无符号 __int64) *
    • 免费 0x00019ffc25ff0001 无效 (HAllocator_ *, 无效 *) *

特别是因为,当我检查原始结构文字时,一切看起来都很合理:

    system_allocator = {alloc=0x000007fefad31410 {hammer.dll!
  • system_alloc} realloc=0x000007fefad313f7 {hammer.dll!system_realloc} ...}
    • alloc = 0x000007fefad31410 {hammer.dll!system_alloc}
    • Realloc = 0x000007fefad313f7 {hammer.dll!system_realloc}
    • 免费 = 0x000007fefad310d2 {锤子.dll!system_free}

我尝试在system_allocator的声明和定义上放置断点,VS2013通知我"调试器的目标代码类型没有与此行关联的可执行代码"。这是否意味着system_allocator实际上没有被初始化?(如果是这样,那么那些0x000007fefad31...地址是什么意思?

我从来没有遇到过 gcc 或 clang 的这个问题,这是我第一次使用 VS。我错过了什么?

编辑:根据chux的评论,失败的测试实际上在设置中失败。 system_allocator像这样通过:

HBitWriter *w = h_bit_writer_new(&system_allocator);

失败的代码行是HBitWriter *h_bit_writer_new(HAllocator* mm__)的第一行:

HBitWriter *writer = h_new(HBitWriter, 1);

其中h_new #defined 为

#define h_new(type, count) ((type*)(mm__->alloc(mm__, sizeof(type)*(count))))

我敢打赌它与DLL有关。 您可能必须将可执行文件中的system_allocater成员放在一起,而不是从 DLL 传递包含 DLL 看到的函数地址的结构。

http://msdn.microsoft.com/en-us/library/windows/desktop/ms683212%28v=vs.85%29.aspx

断点的问题很容易解释。Visual C++ 调试器的工作原理是在函数中放置断点。您尝试在函数外部放置断点。这是不支持的。

机器代码级别,全局初始值设定项在可执行文件中main之前运行,对于 DLL,则从DllMain运行。您可能已经注释掉了 MSVC++ 的实际初始值设定项,因为代码C++无效。是的,我知道这个问题被标记为 C,但 MSVC++ 不支持现代 C。

最新更新