使用虚拟继承的地址未对齐

时间:2017-09-28 16:38:03

标签: c++ clang++ memory-alignment virtual-inheritance sanitizer

以下显然有效的代码使用UndefinedBehaviorSanitizer杀菌器产生错位的地址运行时错误。

#include <memory>
#include <functional>

struct A{
  std::function<void()> data; // seems to occur only if data is a std::function
} ;

struct B{
  char data; // occurs only if B contains a member variable
};

struct C:public virtual A,public B{

};

struct D:public virtual C{

};

void test(){
  std::make_shared<D>();
}

int main(){
  test();
  return 0;
}

在macbook上编译和执行 clang++ -fsanitize=undefined --std=c++11 ./test.cpp && ./a.out 产生输出 runtime error: constructor call on misaligned address 0x7fe584500028 for type 'C', which requires 16 byte alignment [...]

我想了解错误的发生方式和原因。

1 个答案:

答案 0 :(得分:5)

由于std::function<void()>的对齐为16且大小为48,因此可以简化。此代码包含same behavior,但更容易理解:

struct alignas(16) A
{ char data[48]; };

struct B
{ char data; };

struct C : public virtual A, public B
{};

struct D : public virtual C
{};

int main()
{
    D();
}

我们有以下对齐和尺寸:

                     |__A__|__B__|__C__|__D__|
 alignment (bytes):  |  16 |  1  |  16 |  16 |
      size (bytes):  |  48 |  1  |  64 |  80 |

现在让我们看看它在内存中的样子。关于这方面的更多解释可以在this great answer中找到。

  • A: char[48] + no padding == 48B
  • B: char[1] + no padding == 1B
  • C: A* + B + A + 7 bytes of padding (align to 16) == 64B
  • D: C* + C + 8 bytes of padding (align to 16) == 80B

现在很容易看到C DC内的偏移是8字节,但是00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ^ 与16对齐。因此错误,这有助于这个伪 - 图形

D

这里每个零都是1个字节。

<强>更新: 填充的位置和方式取决于C ++编译器。标准没有指定它。它看起来像填充的大小,clang无法对齐if (isset($_POST['submit'])) { $id = $_GET["section"]; $about_me = "../include/about_me.php"; $providers_2 = "../include/2providers.php"; $more_providers = "../include/more_proiders.php"; $section_change = $_POST["section_change"]; $query = "UPDATE sections SET ": $query .= "`File Path` = '{$section_change}' "; $query .= "WHERE id = '{$id}' "; $query .= "LIMIT 1"; $result = mysqli_query($link, $query); if ($result && mysqli_affected_rows($link) == 1) { // Success $_SESSION["message"] = "Section Changed."; redirect_to("../index.php?admin=true"); } else { // Failure echo "System Failure. Please try again later. If problem persists please notify your admin at aqeke.com/powerplaylife-help" } } else { print_r( $_POST); } 中的所有内容。缓解错位的一种方法是仔细设计类,使它们具有相同的对齐方式(例如,8个字节)。