llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.63k stars 11.83k forks source link

strange C++ unwind behavior on ppc64le with LTO program and -ftrivial-auto-var-init=zero libunwind #76771

Open q66 opened 9 months ago

q66 commented 9 months ago

Clang 17.0.6, ppc64le, musl libc, compiler-rt/libunwind/libc++, Chimera Linux.

Given the following program C++:

#include <cstdio>
#include <stdexcept>
#include <string>

using str = std::string;

int main(void) {
    printf("iter 1\n");
    if (true) {
        str foo1{"some random string"};
        try {
            throw std::runtime_error{"some random string"};
        } catch (std::runtime_error const &e) {
            if (foo1 != e.what()) {
                printf("BOO! '%s' '%s' %p\n", e.what(), foo1.data(), foo1.data());
            }
            printf("OK %p\n", foo1.data());
        }
    }
    printf("iter 2\n");
    if (true) {
        str foo2{"some random string"};
        try {
            throw std::runtime_error{"some random string"};
        } catch (std::runtime_error const &e) {
            if (foo2 != e.what()) {
                printf("BOO! '%s' '%s' %p\n", e.what(), foo2.data(), foo2.data());
            }
            printf("OK %p\n", foo2.data());
        }
    }
}

I get the following output:

iter 1
OK 0x3fffc2943891
iter 2
BOO! 'some random string' 'dom strisome ranng' 0x3fffc2943891
OK 0x3fffc2943891

When compiled with the following flags: -O2 -flto=thin, but particularly only when libunwind is compiled with -ftrivial-auto-var-init=zero. The prerequisite is always this combo; if I either compile the test program without LTO, or if I compile libunwind without any special flags, the test program works. It's always the second iteration that breaks. I am not sure whether this is a miscompilation problem of the test program, or of libunwind itself.

This was originally found by running the test suite of the fmt library, where the ostream tests fail like this. It's always every second throw, i.e. in a program with 4 iterations, two of them fail.

Other architectures seem to work okay in all cases.

llvmbot commented 9 months ago

@llvm/issue-subscribers-backend-powerpc

Author: q66 (q66)

Clang 17.0.6, ppc64le, musl libc, compiler-rt/libunwind/libc++, Chimera Linux. Given the following program C++: ``` #include <cstdio> #include <stdexcept> #include <string> using str = std::string; int main(void) { printf("iter 1\n"); if (true) { str foo1{"some random string"}; try { throw std::runtime_error{"some random string"}; } catch (std::runtime_error const &e) { if (foo1 != e.what()) { printf("BOO! '%s' '%s' %p\n", e.what(), foo1.data(), foo1.data()); } printf("OK %p\n", foo1.data()); } } printf("iter 2\n"); if (true) { str foo2{"some random string"}; try { throw std::runtime_error{"some random string"}; } catch (std::runtime_error const &e) { if (foo2 != e.what()) { printf("BOO! '%s' '%s' %p\n", e.what(), foo2.data(), foo2.data()); } printf("OK %p\n", foo2.data()); } } } ``` I get the following output: ``` iter 1 OK 0x3fffc2943891 iter 2 BOO! 'some random string' 'dom strisome ranng' 0x3fffc2943891 OK 0x3fffc2943891 ``` When compiled with the following flags: `-O2 -flto=thin`, but particularly only when libunwind is compiled with `-ftrivial-auto-var-init=zero`. The prerequisite is always this combo; if I either compile the test program without LTO, or if I compile libunwind without any special flags, the test program works. It's always the second iteration that breaks. I am not sure whether this is a miscompilation problem of the test program, or of libunwind itself. This was originally found by running the test suite of the `fmt` library, where the `ostream` tests fail like this. It's always every second throw, i.e. in a program with 4 iterations, two of them fail. Other architectures seem to work okay in all cases.
q66 commented 9 months ago

I have also verified this on Alpine Linux. The test program does not need recompiling; simply replacing the libunwind shared library is enough to reproduce it (a non-LTO binary still works everywhere, though, regardless of the libunwind build). There is a good chance it's reproducible on glibc distros as well, but I haven't had a chance to verify this yet.