Skip to content

MSVC on x86-32 Windows fails to align variables to their required alignment #112480

Open
@glandium

Description

This is a regression from #98112. I suppose it's not possible to disable this specific check only while preserving debug assertions...

The core problem is that the x86 ABI on Windows doesn't guarantee the stack alignment above 4. See for example https://developercommunity.visualstudio.com/t/vs2017-64-bit-int-alignment-problem/294259

And while some types have an alignment reported of 8 (e.g. UINT64), in practice, the C compiler will happily not align them on the stack.

So for example, this C code, compiled by MSVC for 32-bits:

#include <cinttypes>
extern void hoge(uint64_t*);
void foo() {
    uint64_t a;
    hoge(&a);
}

will produce this assembly:

_a$ = -8                                                ; size = 8
void foo(void) PROC                                        ; foo
        push    ebp
        mov     ebp, esp
        sub     esp, 8
        lea     eax, DWORD PTR _a$[ebp]
        push    eax
        call    void hoge(unsigned __int64 *)                        ; hoge
        add     esp, 4
        mov     esp, ebp
        pop     ebp
        ret     0
void foo(void) ENDP

(on godbolt)

If the stack pointer is not 8-bytes aligned when entering the function, the pointer passed to hoge is not going to be 8-bytes aligned.

As mentioned in the linked community post above, adding alignas(8) to the type definition makes the compiler align the stack:

#include <cinttypes>
extern void hoge(uint64_t*);
void foo() {
    alignas(8) uint64_t a;
    hoge(&a);
}

becomes

_a$ = -8                                                ; size = 8
void foo(void) PROC                                        ; foo
        push    ebx
        mov     ebx, esp
        sub     esp, 8
        and     esp, -8                             ; fffffff8H
        add     esp, 4
        push    ebp
        mov     ebp, DWORD PTR [ebx+4]
        mov     DWORD PTR [esp+4], ebp
        mov     ebp, esp
        sub     esp, 8
        lea     eax, DWORD PTR _a$[ebp]
        push    eax
        call    void hoge(unsigned __int64 *)                        ; hoge
        add     esp, 4
        mov     esp, ebp
        pop     ebp
        mov     esp, ebx
        pop     ebx
        ret     0
void foo(void) ENDP

(on godbolt)

Now, what this means is that if that hoge function is a rust FFI function, and it uses that pointer, the "misaligned pointer dereference" check is hit and panic ensues.

Real life case, for the curious:
https://github.com/servo/dwrote-rs/blob/master/src/font_file_loader_impl.rs#L116-L123

That function is called from dwrite.dll (which comes with Windows).

t-opsem FCP comment

Summary of the MSVC alignment rules

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    A-ABIArea: Concerning the application binary interface (ABI)A-FFIArea: Foreign function interface (FFI)C-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessO-windows-msvcToolchain: MSVC, Operating system: WindowsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.disposition-closeThis PR / issue is in PFCP or FCP with a disposition to close it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.regression-untriagedUntriaged performance or correctness regression.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions