简体   繁体   English

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

[英]Why is this struct literal getting corrupted when passed by address in VS2013 but not gcc/clang?

I'm putting together a Visual Studio 2013 solution for a library I maintain . 我正在为我维护的库组装一个Visual Studio 2013解决方案。 The library primarily uses arena allocation, so we have an allocator interface: 该库主要使用竞技场分配,因此我们有一个分配器接口:

allocator.h 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

We also implement a wrapper around malloc , realloc and free : 我们还实现了mallocreallocfree的包装器:

system_allocator.c 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,
};

The system_allocator global is declared as extern in internal.h (which #include s allocator.h ), and it is exported as a symbol (in the .def file). system_allocator全局在internal.h#include s allocator.h )中声明为extern ,并作为符号导出(在.def文件中)。 However, apparently the struct is never initialized, because when my unit tests try to pass system_allocator by address to a function that dereferences the alloc member, they segfault with "Unhandled exception at 0x000007FEFAD3EB6D (hammer.dll) in hammer-test.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF." 然而,显然该结构是永远不会被初始化,因为当我的单元测试尝试通过system_allocator按地址到其提领操作的功能alloc成员,他们与以“0x000007FEFAD3EB6D(hammer.dll)在锤test.exe的未处理的异常段错误:0000005 :访问冲突读取位置0xFFFFFFFFFFFFFFFF。“

Inspecting the passed-in pointer in the debugger suggests that something is definitely not right: 检查调试器中的传入指针表明某些东西绝对不对:

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

Particularly since, when I inspect the original struct literal, everything looks reasonable: 特别是因为当我检查原始struct literal时,一切看起来都很合理:

  • system_allocator = {alloc=0x000007fefad31410 {hammer.dll!system_alloc} realloc=0x000007fefad313f7 {hammer.dll!system_realloc} ...} system_allocator = {alloc = 0x000007fefad31410 {hammer.dll!system_alloc} realloc = 0x000007fefad313f7 {hammer.dll!system_realloc} ...}
    • alloc = 0x000007fefad31410 {hammer.dll!system_alloc} alloc = 0x000007fefad31410 {hammer.dll!system_alloc}
    • realloc = 0x000007fefad313f7 {hammer.dll!system_realloc} realloc = 0x000007fefad313f7 {hammer.dll!system_realloc}
    • free = 0x000007fefad310d2 {hammer.dll!system_free} free = 0x000007fefad310d2 {hammer.dll!system_free}

I tried putting breakpoints on both the declaration and definition of system_allocator , and VS2013 informs me that "no executable code of the debugger's target code type is associated with this line." 我试图把断点在声明和定义都system_allocator和VS2013告诉我,“调试器的目标代码类型的无可执行代码与该行相关联。” Does that imply that system_allocator isn't actually being initialised? 这是否意味着system_allocator实际上没有被初始化? (If so, then what do those 0x000007fefad31... addresses mean?) (如果是这样,那么那些0x000007fefad31 ...地址是什么意思?)

I've never encountered this problem with gcc or clang, and this is my first time using VS. 我从来没有遇到过gcc或clang这个问题,这是我第一次使用VS. What am I missing? 我错过了什么?

EDIT: per chux's comment, the test which is failing is actually failing in setup. 编辑:每chux的评论,失败的测试实际上是在设置失败。 system_allocator gets passed like this: system_allocator像这样传递:

HBitWriter *w = h_bit_writer_new(&system_allocator);

The line of code that's failing is the first line of HBitWriter *h_bit_writer_new(HAllocator* mm__) : 失败的代码行是HBitWriter *h_bit_writer_new(HAllocator* mm__)的第一行HBitWriter *h_bit_writer_new(HAllocator* mm__)

HBitWriter *writer = h_new(HBitWriter, 1);

where h_new is #defined as 其中h_new是#defined as

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

I bet it is DLL related. 我敢打赌它与DLL有关。 You might have to put together the system_allocater member in the executable instead of passing a structure from the DLL containing the function addresses as the DLL sees them. 您可能必须将system_allocater成员放在可执行文件中,而不是在DLL看到它时从包含函数地址的DLL传递结构。

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

The problem with breakpoints is fairly easily explained. 断点的问题很容易解释。 The Visual C++ debugger works by putting breakpoints in functions. Visual C ++调试器通过在函数中放置断点来工作。 You're trying to put a breakpoint outside a function. 你试图在函数外面放置一个断点。 That's not supported. 这不受支持。

At machine code level, global initializers are run before main in an executable, and from DllMain in case of a DLL. 在机器代码级别,全局初始化器在main之前在可执行文件中运行,而在DllMain在DLL的情况下运行。 You've probably commented out the actual initializers for MSVC++, as the code is not valid C++. 您可能已经注释掉了MSVC ++的实际初始化程序,因为代码不是有效的C ++。 Yes, I know the question is tagged C, but MSVC++ doesn't support modern C. 是的,我知道问题标记为C,但MSVC ++不支持现代C.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM