【问题标题】:Inconsistent memory layout of c++ struct in XcodeXcode中c ++结构的内存布局不一致
【发布时间】:2018-06-07 09:23:38
【问题描述】:

我在 iPhone 模拟器上执行通过 XCode 版本 9.2 (9C40b) 编译(和调试)的 c++ 代码时遇到问题。

代码sn-p如下;所有涉及的文件都是同一个库的一部分,该库稍后链接到 iPhone 应用程序以供执行。请注意,为了调查目的,已截取发布的代码已被定制和修剪,最初它用于不同的目的,但隔离“违规行”已经足够痛苦了-.-

// HEADER FILE struct_definition.h CONTAINING STRUCT DECLARATION
struct SRowLogBookDescriptor
{
    SRowLogBookDescriptor();

    mutable         u32 key             ;
    std::string     name                ;
    std::string     ui_name             ;
    u32             type                ;
    u32             physical_quantity   ;
    std::string     unit_of_measure     ;
    u32             constraints_size    ;
    u8*             constraints         ;
    std::string     comment             ;
    u64             marker;
};
//---------------------------------------------


// SOURCE FILE struct_definition.cpp CONTAINING STRUCT CONSTRUCTOR DEFINITION
SRowLogBookDescriptor::SRowLogBookDescriptor()
    : key(0xFFFFFFFF)
    , name("name")
    , ui_name("ui_name")
    , type(0xAAAAAAAA)
    , physical_quantity(0x55555555)
    , unit_of_measure("unit")
    , constraints_size(0xB5006BB1)
    , constraints(nullptr)
    , comment("comment")
    , marker(0xBAD00DABBAD00DAB)
{}
//---------------------------------------------


// SOURCE FILE function_call.cpp USING THE MISALIGNED STRUCTURE
void CDefaultLogbookSet::AddDoubleLogBookToSet()
{

    SRowLogBookDescriptor descr;

    int i1 = offsetof(SRowLogBookDescriptor,key)         ;
    int i2 = offsetof(SRowLogBookDescriptor,name)                ;
    int i3 = offsetof(SRowLogBookDescriptor,ui_name)             ;
    int i4 = offsetof(SRowLogBookDescriptor,type)                ;
    int i5 = offsetof(SRowLogBookDescriptor,physical_quantity)   ;
    int i6 = offsetof(SRowLogBookDescriptor,unit_of_measure)     ;
    int i7 = offsetof(SRowLogBookDescriptor,constraints_size)    ;
    int i8 = offsetof(SRowLogBookDescriptor,constraints)         ;
    int i9 = offsetof(SRowLogBookDescriptor,comment)             ;
    int i10 = offsetof(SRowLogBookDescriptor,marker);

    size_t test1 = descr.name.capacity();
    size_t test2 = descr.ui_name.capacity();

    descr.comment = "";
    descr.name = "new_name";
    descr.physical_quantity = 0xaa;
    descr.type = 0x55;
    descr.ui_name = "new_ui_name";
    descr.unit_of_measure = "new_unit";

}
//---------------------------------------------

我有一个包含 32 位整数、字符串和指针的结构。我很清楚结构的对齐布局会由于填充而导致字节浪费。我已经对结构的构造函数进行了检测,以突出显示每个字段映射到内存的位置。

然后在 AddDoubleLogBookToSet 函数中将结构放在堆栈上,我保存结构中字段的所有偏移量,检查字符串容量,填充值,然后函数退出。

当我尝试为 name 字段赋值时,我得到一个 BAD_ACCESS 异常。当我实际遇到异常时,我附上了从 XCode 调试器截取的 2 个屏幕截图。 在那里您可以看到 struct 属性的预期偏移量,并且您可以看到调试器实际上是在实际未存储属性的内存位置访问属性。

我刚刚检查了调试器,当我执行构造函数时,调试器会适当地“看到”结构成员(我没有为此附上屏幕截图)。

现在...在我看来,function_call.cpp 和 struct_definition.cpp 在打包和/或对齐方面存在某种编译差异。 我已经多次检查代码中的每个编译指示包每次都被适当地清除,并且显然审查了代码,一切正常。

让我补充一点,在 Xcode 中编译的相同 c++ 代码正在通过 Visual Studio 2017 编译的不同 Windows 版本(PC)上顺利编译和执行。 调查的开始是因为大量不同的崩溃都与包含违规代码的库相关(该库中有几个不同的结构)。 最后但并非最不重要的一点是,iPhone 应用程序在很长一段时间内一直运行良好,然后在几周前就停止了正常运行。

问题是:有人可以帮我找出为什么这两个源文件的编译方式不同吗?

提前致谢

【问题讨论】:

  • 清理并重建 - 钱说有些东西没有正确重新编译
  • 也许,desc 是否来自函数的 reference 参数,以及来自该函数的 caller 的动态分配,以及所述分配使用 C 语义天真地分配?更糟糕的是,这个结构是否天真地从某个文件或内存支持的缓冲区中作为一个 blob 流式传输,作为一个过渡?一旦你说,具有 C++ 结构的“pragma pack”和非平凡的成员巨大的危险信号就出现了。如果您将其作为流中的 blob 进行字节读取,坏主意
  • @UKMonkey - 清理和重建已执行无数次,包括删除所有 Xcode 的 DerivedData。
  • @WhozCraig - (根据发布的代码)结构实例在没有参数的普通函数堆栈上创建为一个简单变量。这会触发编码的默认构造函数的调用。这种结构不会被任何东西流式传输。上面的结构不应该被打包,其他结构是流式传输和打包的,但这些不是,因为我们通常远离你提到的那些危险信号;)出于未知原因,我们正在努力解决这些问题危险信号,但我们不知道是谁在我们的源文件中植入了这些标记:(

标签: c++ ios xcode pack


【解决方案1】:

嗯,我找到了问题所在。

我创建了一个与有问题的源文件完全相同的新源文件,并进一步缩减了其内容以简化调查。我编译了该文件并开始创建导致问题与未导致问题的类修剪代码的实例。

最终有一个“远程头”文件,其中声明了打包结构,该文件在编译指示包内包含包含指令。将这些包含从特殊包装中取出,使编译在所有文件中再次保持一致。与 Visual Studio 编译过程相比,包含树在 Xcode 编译过程中尤其有害。

只用了几天就知道了-.-'

【讨论】:

  • 你能提供更多关于你所看到的细节吗?我在同样的问题上苦苦挣扎太久了!我不知道您所说的“在编译指示包内包含指令”是什么意思。我将#pragma pack (show) 添加到偏移量不同的两个文件中,并且都显示为 4 作为对齐方式。所以我不认为这是类具有不同包对齐的情况。非常感谢任何帮助!
  • @DaveHaupert 不幸的是,我无法“提供更多关于我所看到的细节”,因为这个问题可以追溯到一年多以前,并且已经解决。就我而言,对齐问题与定义的特定结构并不严格相关,而是因为在包含树中的一个文件中,当 pragma pack 设置为 1 时,有一个 #include 指令,这导致了几个 STL 结构的 1-pack 的应用。我建议遵循一个漫长的调查过程,删除代码并一次包含一个步骤,以查明导致问题的原因。
猜你喜欢
  • 2011-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 2018-08-30
  • 2015-06-30
相关资源
最近更新 更多