https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116098

--- Comment #15 from Laria Chabowski <laria at laria dot me> ---
(In reply to Andrew Pinski from comment #14)
> Fixed so far on the trunk.

Thank you! That fixed the test cases I provided.

However, when I tested it against the code where I stumbled upon this, I still
got an unexpected result.

Essentially the same idea: A function truthy() that switches over the type
enum,
returns the bool value if it's bool or always false if the type is nil or true
in all other cases. Then, inverting it and saving and reading it as a value
struct again, some garbage comes out and when using the resulting bool in a
ternary, the opposite of the expected happens.

I've reduced that code to this:

======= BEGIN test.c =======
int puts(const char *);

struct Value {
    enum value_type {
        VALUE_NIL,
        VALUE_BOOLEAN,
        VALUE_MAGIC,
    } type;
    union {
        _Bool boolean;
        void *p[2];
    };
};

static struct Value s_item_mem;

static void
set_bool(_Bool b)
{
    s_item_mem = (struct Value) {
        .type = VALUE_BOOLEAN,
        .boolean = b,
    };
}

static void
set_magic(void)
{
    s_item_mem = (struct Value) {
        .type = VALUE_MAGIC,
        .p[0] = (void *)0x7fff0123456789a0, // just something that vaguely
looks
                                            // like a pointer. In the original,
                                            // this was a valid pointer
returned
                                            // from malloc. But since this
                                            // reduced code never reads from
                                            // here it shouldn't matter that
                                            // it's not an actual address.
    };
}

static struct Value
val_get(void)
{
    // returning s_item_mem immediately makes the bug go away
    struct Value value = s_item_mem;
    return value;
}

static _Bool
truthy(void)
{
    // Inlinig val_get makes the bug go away
    struct Value value = val_get();
    switch (value.type) {
    case VALUE_NIL: // Removing this case makes the bug go away
        return 0;
    case VALUE_BOOLEAN:
        return value.boolean;
    default:
        return 1;
    }
}

int
main(void)
{
    set_magic(); // sets type to VALUE_MAGIC
    set_bool(!truthy()); // truthy should take default case, so
                         // set_bool(!1) -> set_bool(0)

    _Bool b = truthy(); // Should be 0 now
    puts(b ? "true" : "false"); // Should print false, prints true
    return b ? 0 : 1; // Exit code should be 1, is 161
}
======= END test.c =======

I built it with:

gcc -Wall -Werror -Wextra -pedantic -O2 -fno-strict-aliasing -fwrapv \
    -fno-aggressive-loop-optimizations test.c

Happens both with the GCC installed on my Fedora 40 machine:

    $ gcc -v
    Using built-in specs.
    COLLECT_GCC=/usr/bin/gcc
    COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/14/lto-wrapper
    OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
    OFFLOAD_TARGET_DEFAULT=1
    Target: x86_64-redhat-linux
    Configured with: ../configure --enable-bootstrap
--enable-languages=c,c++,fortran,objc,obj-c++,ada,go,d,m2,lto --prefix=/usr
--mandir=/usr/share/man --infodir=/usr/share/info
--with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared
--enable-threads=posix --enable-checking=release --enable-multilib
--with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions
--enable-gnu-unique-object --enable-linker-build-id
--with-gcc-major-version-only --enable-libstdcxx-backtrace
--with-libstdcxx-zoneinfo=/usr/share/zoneinfo --with-linker-hash-style=gnu
--enable-plugin --enable-initfini-array
--with-isl=/builddir/build/BUILD/gcc-14.2.1-20240801/obj-x86_64-redhat-linux/isl-install
--enable-offload-targets=nvptx-none,amdgcn-amdhsa --enable-offload-defaulted
--without-cuda-driver --enable-gnu-indirect-function --enable-cet
--with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
--with-build-config=bootstrap-lto --enable-link-serialization=1
    Thread model: posix
    Supported LTO compression algorithms: zlib zstd
    gcc version 14.2.1 20240801 (Red Hat 14.2.1-1) (GCC)

And with the one I built a couple of days ago from the git trunk, that includes
the fix (HEAD was at ce5f2dc45038c9806088132cc923b13719f48732 when I built it.
git log from here includes the commit ceda727dafba6 with the fix):

    $ ~/local/gcc/usr/local/bin/x86_64-linux-gcc -v
    Using built-in specs.
    COLLECT_GCC=/home/laria/local/gcc/usr/local/bin/x86_64-linux-gcc
   
COLLECT_LTO_WRAPPER=/home/laria/local/gcc/usr/local/bin/../libexec/gcc/x86_64-linux/15.0.0/lto-wrapper
    Target: x86_64-linux
    Configured with: ../configure --target=x86_64-linux --disable-multilib
    Thread model: posix
    Supported LTO compression algorithms: zlib zstd
    gcc version 15.0.0 20240903 (experimental) (GCC)

Also reproducible on godbolt.org, which apparently uses this version for trunk:

    g++
(Compiler-Explorer-Build-gcc-1735917cee41fe680d9dd3c0c26b45520c17413a-binutils-2.42)
15.0.0 20240906 (experimental)

Please let me know if I can provide any more info.

Reply via email to