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

--- Comment #15 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The releases/gcc-12 branch has been updated by Iain Buclaw
<ibuc...@gcc.gnu.org>:

https://gcc.gnu.org/g:f6be26657c8b974a5caf39350e4965cfb2c4b936

commit r12-10972-gf6be26657c8b974a5caf39350e4965cfb2c4b936
Author: Iain Buclaw <ibuc...@gdcproject.org>
Date:   Fri Feb 28 19:22:36 2025 +0100

    d: Fix comparing uninitialized memory in dstruct.d [PR116961]

    Floating-point emulation in the D front-end is done via a type named
    `struct longdouble`, which in GDC is a small interface around the
    real_value type. Because the D code cannot include gcc/real.h directly,
    a big enough buffer is used for the data instead.

    On x86_64, this buffer is actually bigger than real_value itself, so
    when a new longdouble object is created with

        longdouble r;
        real_from_string3 (&r.rv (), buffer, mode);
        return r;

    there is uninitialized padding at the end of `r`.  This was never a
    problem when D was implemented in C++ (until GCC 12) as comparing two
    longdouble objects with `==' would be forwarded to the relevant
    operator== overload that extracted the underlying real_value.

    However when the front-end was translated to D, such conditions were
    instead rewritten into identity comparisons

        return exp.toReal() is CTFloat.zero

    The `is` operator gets lowered as a call to `memcmp() == 0', which is
    where the read of uninitialized memory occurs, as seen by valgrind.

    ==26778== Conditional jump or move depends on uninitialised value(s)
    ==26778==    at 0x911F41:
dmd.dstruct._isZeroInit(dmd.expression.Expression) (dstruct.d:635)
    ==26778==    by 0x9123BE: StructDeclaration::finalizeSize() (dstruct.d:373)
    ==26778==    by 0x86747C:
dmd.aggregate.AggregateDeclaration.determineSize(ref const(dmd.location.Loc))
(aggregate.d:226)
    [...]

    To avoid accidentally reading uninitialized data, explicitly initialize
    all `longdouble` variables with an empty constructor on C++ side of the
    implementation before initializing underlying real_value type it holds.

            PR d/116961

    gcc/d/ChangeLog:

            * d-codegen.cc (build_float_cst): Change new_value type from real_t
to
            real_value.
            * d-ctfloat.cc (CTFloat::fabs): Default initialize the return
value.
            (CTFloat::ldexp): Likewise.
            (CTFloat::parse): Likewise.
            * d-longdouble.cc (longdouble::add): Likewise.
            (longdouble::sub): Likewise.
            (longdouble::mul): Likewise.
            (longdouble::div): Likewise.
            (longdouble::mod): Likewise.
            (longdouble::neg): Likewise.
            * d-port.cc (Port::isFloat32LiteralOutOfRange): Likewise.
            (Port::isFloat64LiteralOutOfRange): Likewise.

    gcc/testsuite/ChangeLog:

            * gdc.dg/pr116961.d: New test.

    (cherry picked from commit f7bc17ebc9ef89700672ed7125da719f3558f3b7)

Reply via email to