为什么这个struct literal在VS2013中通过地址而不是gcc / clang传递时会被破坏?

时间:2014-11-14 14:57:30

标签: c struct visual-studio-2013 access-violation

我正在为a library I maintain整合Visual Studio 2013解决方案。该库主要使用竞技场分配,因此我们有一个分配器接口:

allocator.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_allocator全局在externinternal.h s #include)中声明为allocator.h,并将其导出为符号(在{。 def文件)。但是,显然结构从未初始化,因为当我的单元测试试图通过地址将system_allocator传递给取消引用alloc成员的函数时,它们会出现“0x000007FEFAD3EB6D处的未处理异常(hammer.dll)在hammer-test.exe中:0xC0000005:访问冲突读取位置0xFFFFFFFFFFFFFFFF。“

检查调试器中的传入指针表明某些事情肯定是不对的:

  • mm__ 0x000000013fb0a094 {hammer-test.exe!HAllocator_ system_allocator} {alloc = 0x25ff00019ff625ff realloc = ...} HAllocator_ *
    • alloc 0x25ff00019ff625ff void *(HAllocator_ *,unsigned __int64)*
    • realloc 0x9ffa25ff00019ff8 void *(HAllocator_ *,void *,unsigned __int64)*
    • free 0x00019ffc25ff0001 void(HAllocator_ *,void *)*

特别是因为,当我检查原始struct literal时,一切看起来都合理:

  • 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}
    • free = 0x000007fefad310d2 {hammer.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))))

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

断点的问题很容易解释。 Visual C ++调试器通过在函数中放置断点来工作。你试图在函数外面放置一个断点。那是不受支持的。

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