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

            Bug ID: 122080
           Summary: Optional array argument reads uninitialized values
                    from stack
           Product: gcc
           Version: 15.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: fortran
          Assignee: unassigned at gcc dot gnu.org
          Reporter: henri at henrimenke dot de
  Target Milestone: ---

Consider the following code

    subroutine outer(optarr)
      real, optional, intent(in) :: optarr(:,:)
      call inner(optarr)
    end subroutine outer

The generated assembly is very hard to follow which is why I look at the dumped
trees.

    gfortran -O0 -fsanitize=undefined -c test.F90 -fdump-tree-original
-fdump-tree-ubsan

In the original tree I would like to direct your attention to the computation
of parm.6.offset (line 59) which uses strides that are uninitialized when the
argument optarr is not present, i.e. the computation will subtract two garbage
values. This is not a problem at runtime, because the garbage will only be
computed if optarr was not present but in this case parm.6 also remains unused,
so no problem there.

    D.4676 = ubound.0;
    D.4677 = ubound.2;
    parm.6.span = 4;
    parm.6.dtype = {.elem_len=4, .version=0, .rank=2, .type=3};
    D.4684 = stride.1;
    parm.6.dim[0].lbound = 1;
    parm.6.dim[0].ubound = D.4676;
    parm.6.dim[0].stride = NON_LVALUE_EXPR <D.4684>;
    D.4685 = stride.3;
    parm.6.dim[1].lbound = 1;
    parm.6.dim[1].ubound = D.4677;
    parm.6.dim[1].stride = NON_LVALUE_EXPR <D.4685>;
    parm.6.data = (void *) optarr.0;
    parm.6.offset = -NON_LVALUE_EXPR <D.4684> - NON_LVALUE_EXPR <D.4685>;
    D.4686 = _gfortran_internal_pack (&parm.6);
    D.4687 = optarr.0 != 0B ? D.4686 : 0B;
    inner (D.4687);

However, this can become a problem if the code is compiled with UBSan or with
-ftrapv, because in this case overflow checks will be introduced in the
computation of parm.6.offset and if we are unlucky due to ASLR, the garbage
values lead to an overflow which crashes the program. Note the .UBSAN_CHECK_SUB
calls in the UBSan tree below.

    _42 = ubound.0_16;
    _43 = ubound.2_19;
    parm.6.span = 4;
    parm.6.dtype = {};
    parm.6.dtype.elem_len = 4;
    parm.6.dtype.rank = 2;
    parm.6.dtype.type = 3;
    _49 = stride.1_18;
    parm.6.dim[0].lbound = 1;
    parm.6.dim[0].ubound = _42;
    parm.6.dim[0].stride = _49;
    _53 = stride.3_20;
    parm.6.dim[1].lbound = 1;
    parm.6.dim[1].ubound = _43;
    parm.6.dim[1].stride = _53;
    parm.6.data = optarr.0_15;
    _12 = .UBSAN_CHECK_SUB (0, _49);
    _13 = .UBSAN_CHECK_SUB (_12, _53);
    parm.6.offset = _13;

I have tested the following version of gfortran and all of them are affected:

- GNU Fortran (GCC) 13.3.0
- GNU Fortran (GCC) 14.1.0
- GNU Fortran (GCC) 15.1.0

Possibly related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101135

Reply via email to