Search code examples
c++compiler-errorsformatalignmentc++20

Why does `std::format` require its arguments are aligned?


Consider the following code (godbolt link):

#include <format>
#include <iostream>

#pragma pack(push)
#pragma pack(1)
struct A {
    long l;
    int  n;
    char c;
};
#pragma pack(pop)

int main() {
    A arr[] = {{42, 42, 42}, {42, 42, 42}};
    std::cout << std::format("{} {} {}", arr[0].l, arr[0].n, arr[0].c); // ok
    std::cout << std::format("{} {} {}", arr[1].l, arr[1].n, arr[1].c); // error
}

The compile command is as follows:

clang-19 -std=c++23 -stdlib=libc++ -O3 -fsanitize=undefined

The runtime error is as follows:

runtime error: reference binding to misaligned address 0x7ffc995b2f3d for type 'long', which requires 8 byte alignment.

Why does std::format require its arguments are aligned?


Solution

  • std::format takes its arguments by reference, and UB sanitizer detects it as UB because it will crash on platforms where the CPU cannot automatically fix unaligned loads and stores. see Load of misaligned address and UBsan finding

    to fix the code you can pass temporaries to std::format instead

    std::cout << std::format("{} {} {}", long{arr[0].l}, int{arr[0].n}, char{arr[0].c}); // ok
    std::cout << std::format("{} {} {}", long{arr[1].l}, int{arr[1].n}, char{arr[1].c}); // ok
    

    this is telling the compiler to create a temporary before passing it to the function, and this temporary should be aligned.