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

            Bug ID: 116388
           Summary: [13/14/15 regression] Finalizer called on
                    uninitialized components of intent(out) argument
           Product: gcc
           Version: 13.3.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: fortran
          Assignee: unassigned at gcc dot gnu.org
          Reporter: trnka at scm dot com
  Target Milestone: ---

Created attachment 58935
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=58935&action=edit
testcase illustrating this issue

This feels potentially related to PR115070 but it is probably not an exact
duplicate; the proposed fix in PR115070 comment 9 does not fix this issue on
current master branch.

The attached testcase contains a type like this:

   type, public :: AType
      type(C_ptr) :: cptr = C_null_ptr
      logical     :: cptr_invalid = .true.
      integer, allocatable :: x(:)
   contains
      final              :: FinalizerA
   end type
…
   impure elemental subroutine FinalizerA(self)
      type(AType), intent(inout) :: self

      if (.not. self%cptr_invalid) write(*,*) "A:", self%cptr
   end subroutine

Nothing in the program ever sets "cptr_invalid" to .false., so "A:" should
never be printed. However, compiling the testcase with gfortran 13.x and up
produces a program which often prints "A: somerandomvalue" once. Looking at the
tree dump, this is because the __final for CType creates a temporary
"comp_byte_stride", which is only partially initialized (so the components of
AType apart from x aren't initialized) but then calls FinalizerA on the whole a
component.

integer(kind=4) __final_finalizertestmodule_Ctype (struct array15_ctype &
restrict array, integer(kind=8) byte_stride, logical(kind=1) fini_coarray)
{
  struct btype comp_byte_stride;
…
  try
    {
      comp_byte_stride.a.x.data = 0B;
      // no other components of comp_byte_stride are initialized here
…
  finally
    {
      __builtin_free ((void *) strides);
      __builtin_free ((void *) sizes);
      desc.6.dtype = {.elem_len=80, .version=0, .rank=0, .type=5};
      desc.6.data = (void * restrict) &comp_byte_stride.a;
      desc.6.span = (integer(kind=8)) desc.6.dtype.elem_len;
      __final_finalizertestmodule_Atype (&desc.6, 80, 1);

Accessing uninitialized data at runtime is also confirmed using valgrind
--tool=memcheck.

"comp_byte_stride" was introduced by the following commit which went into 13.x.
GCC 12 and older seems to be unaffected by this issue.

commit d7caf313525a46f200d7f5db1ba893f853774aee
Author: Paul Thomas <pa...@gcc.gnu.org>
Date:   Sat Mar 18 07:56:23 2023 +0000

    Fortran: Fix bugs and missing features in finalization [PR37336]

    2023-03-18  Paul Thomas  <pa...@gcc.gnu.org>

(BType in the testcase seems to be superfluous but removing it and putting
AType straight into CType masks the issue somewhat, because the uninitialized
data then happens to have the right value so that A: is never printed. However,
the bug still seems to be there in the tree dump even without BType.)

Reply via email to