[Bug c++/96121] Uninitialized variable copying in member initialized list not diagnosed

cvs-commit at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Fri Nov 19 03:38:31 GMT 2021


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

--- Comment #7 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The trunk branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>:

https://gcc.gnu.org/g:0790c8aacdfb4fd096aa580dae0fe49172c43ab2

commit r12-5391-g0790c8aacdfb4fd096aa580dae0fe49172c43ab2
Author: Marek Polacek <polacek@redhat.com>
Date:   Tue Nov 10 20:07:24 2020 -0500

    c++: Implement -Wuninitialized for mem-initializers (redux) [PR19808]

    2021 update: Last year I posted a version of this patch:
    <https://gcc.gnu.org/pipermail/gcc-patches/2020-November/559162.html>
    but it didn't make it in.  The main objection seemed to be that the
    patch tried to do too much, and overlapped with the ME uninitialized
    warnings.  Since the patch used walk_tree without any data flow info,
    it issued false positives for things like a(0 ? b : 42) and similar.

    I'll admit I've been dreading resurrecting this because of the lack
    of clarity about where we should warn about what.  On the other hand,
    I think we really should do something about this.  So I've simplified
    the original patch as much as it seemed reasonable.  For instance, it
    doesn't even attempt to handle cases like "a((b = 42)), c(b)" -- for
    these I simply give up for the whole mem-initializer (but who writes
    code like that, anyway?).  I also give up when a member is initialized
    with a function call, because we don't know what the call could do.
    See Wuninitialized-17.C, for which clang emits a false positive but
    we don't.  I remember having a hard time dealing with initializer lists
    in my previous patch, so now I only handle simple a{b} cases, but no
    more.  It turned out that this abridged version still warns about 90%
    cases where users would expect a warning.

    More complicated cases are left for the ME, which, for unused inline
    functions, will only warn with -fkeep-inline-functions, but so be it.
    (This is bug 21678.)

    This patch implements the long-desired -Wuninitialized warning for
    member initializer lists, so that the front end can detect bugs like

      struct A {
        int a;
        int b;
        A() : b(1), a(b) { }
      };

    where the field 'b' is used uninitialized because the order of member
    initializers in the member initializer list is irrelevant; what matters
    is the order of declarations in the class definition.

    I've implemented this by keeping a hash set holding fields that are not
    initialized yet, so at first it will be {a, b}, and after initializing
    'a' it will be {b} and so on.  Then I use walk_tree to walk the
    initializer and if we see that an uninitialized object is used, we warn.
    Of course, when we use the address of the object, we may not warn:

      struct B {
        int &r;
        int *p;
        int a;
        B() : r(a), p(&a), a(1) { } // ok
      };

    Likewise, don't warn in unevaluated contexts such as sizeof.  Classes
    without an explicit initializer may still be initialized by their
    default constructors; whether or not something is considered initialized
    is handled in perform_member_init, see member_initialized_p.

            PR c++/19808
            PR c++/96121

    gcc/cp/ChangeLog:

            * init.c (perform_member_init): Remove a forward declaration.
            Walk the initializer using find_uninit_fields_r.  New parameter
            to track uninitialized fields.  If a member is initialized,
            remove it from the hash set.
            (perform_target_ctor): Return the initializer.
            (struct find_uninit_data): New class.
            (find_uninit_fields_r): New function.
            (find_uninit_fields): New function.
            (emit_mem_initializers): Keep and initialize a set holding fields
            that are not initialized.  When handling delegating constructors,
            walk the constructor tree using find_uninit_fields_r.  Also when
            initializing base clases.  Pass uninitialized down to
            perform_member_init.

    gcc/ChangeLog:

            * doc/invoke.texi: Update documentation for -Wuninitialized.
            * tree.c (stabilize_reference): Set location.

    gcc/testsuite/ChangeLog:

            * g++.dg/warn/Wuninitialized-14.C: New test.
            * g++.dg/warn/Wuninitialized-15.C: New test.
            * g++.dg/warn/Wuninitialized-16.C: New test.
            * g++.dg/warn/Wuninitialized-17.C: New test.
            * g++.dg/warn/Wuninitialized-18.C: New test.
            * g++.dg/warn/Wuninitialized-19.C: New test.
            * g++.dg/warn/Wuninitialized-20.C: New test.
            * g++.dg/warn/Wuninitialized-21.C: New test.
            * g++.dg/warn/Wuninitialized-22.C: New test.
            * g++.dg/warn/Wuninitialized-23.C: New test.
            * g++.dg/warn/Wuninitialized-24.C: New test.
            * g++.dg/warn/Wuninitialized-25.C: New test.
            * g++.dg/warn/Wuninitialized-26.C: New test.
            * g++.dg/warn/Wuninitialized-27.C: New test.
            * g++.dg/warn/Wuninitialized-28.C: New test.
            * g++.dg/warn/Wuninitialized-29.C: New test.
            * g++.dg/warn/Wuninitialized-30.C: New test.


More information about the Gcc-bugs mailing list