microsoft / microsoft/STL

<type_traits>: std::aligned_storage<8, 8> doesn't force stack realignment on MSVC x86

Open
#1,533 4 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug vNext
Dominant language
C++
Stars
11.1k
Forks
1.7k
Avg merge
4d 15h
Merged PRs (30d)
22

Description

If a user declares a local variable with the type std::aligned_union_t<1, double> or std::aligned_storage<8, 8>, the local variable may not in practice be 8-byte aligned. While accessing the memory will not cause crashes, it can lead to issues if the program assumes that the low bits of the variable's address are zero. LLVM does this often, and that is where I encountered the issue:
https://reviews.llvm.org/D92509#2452929

The MSVC x86 compiler only maintains 4 byte stack alignment. If a user declares a variable with 8 byte alignment, such as a double or __int64, it will not realign the stack. If the user explicitly requests 8 byte alignment with alignas or __declspec(align), then MSVC will realign the stack.

Arguably, this is a Visual C++ compiler bug: the compiler should realign the stack for doubles or any other type with 8 byte alignment. However, the STL could help the user out here. If the user is bothering to use a std::aligned* type, they probably care about the alignment more than any old double local variable, and the STL should go the extra mile to satisfy that alignment by applying the alignas attribute to the double specialization of the _Aligned template.

Consider the assembly generated for the test case on godbolt:
https://gcc.godbolt.org/z/TxEo7b

Command-line test case

C:\Temp>type repro.cpp
#include <type_traits>
struct Foo {
  std::aligned_union_t<1, double> data;
};
void escape(Foo*);
void declareAndEscape() {
#ifdef REALIGN
  alignas(double)
#endif
  Foo o;
  escape(&o);
}

C:\Temp>cl -c -GS- repro.cpp -Facl.asm
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29334 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

repro.cpp

C:\Temp>type cl.asm
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.28.29334.0

        TITLE   C:\src\llvm-project\build\repro.cpp
        .686P
        .XMM
        include listing.inc
        .model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  ?declareAndEscape@@YAXXZ                        ; declareAndEscape
EXTRN   ?escape@@YAXPAUFoo@@@Z:PROC                     ; escape
; Function compile flags: /Odtp
_TEXT   SEGMENT
_o$ = -8                                                ; size = 8
?declareAndEscape@@YAXXZ PROC                           ; declareAndEscape
; File C:\src\llvm-project\build\repro.cpp
; Line 6
        push    ebp
        mov     ebp, esp
        sub     esp, 8
; Line 11
        lea     eax, DWORD PTR _o$[ebp]
        push    eax
        call    ?escape@@YAXPAUFoo@@@Z                  ; escape
        add     esp, 4
; Line 12
        mov     esp, ebp
        pop     ebp
        ret     0
?declareAndEscape@@YAXXZ ENDP                           ; declareAndEscape
_TEXT   ENDS
END

Expected behavior

Note the lack of AND instructions to realign ESP. Recompile with -DREALIGN to see the desired stack realignment prologue.

STL version
19.28

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in <type_traits> at the _Aligned implementation, then reproduce the aligned_union_t/aligned_storage_t case with the provided MSVC x86 command and inspect the generated assembly. Done means the local object receives the requested 8-byte alignment and the compiler output shows stack realignment, while the existing behavior remains unchanged for other targets.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.