llvm / llvm/llvm-project

[flang] VALUE array dummy receives a scalar-sized copy when the actual argument is an array element

Open
#224,636 1 comment 0 reactions 1 assignee Claimed by @eugeneepshteyn View on GitHub
flang
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

When a scalar array element actual argument is associated with an array VALUE dummy argument (storage sequence association), the temporary that VALUE requires is created from the scalar element alone. The one-element allocation is then presented to the callee as a multi-element array: reads beyond the first element return garbage, and the callee's assignments to the dummy (legal for VALUE) write out of bounds.

This is conforming code: F2023 15.5.2.5 p14 permits the array element actual argument, 15.5.2.12 p1-p3 supply the element sequence from the remaining elements of the base array, and 15.5.2.4 p4 requires a definable anonymous VALUE object covering that sequence.

**Reproducer (static dummy shape):**

```fortran
program value_static
integer :: v(4) = [11,22,33,44]
call sub(v(2))
contains
subroutine sub(x)
integer, value :: x(3)
print *, x ! expected: 22 33 44; actual: 22 followed by garbage
if (any(x /= [22,33,44])) stop 1
x = 0 ! legal for VALUE; writes beyond the scalar temporary
end subroutine
end program
```

**Reproducer (runtime dummy shape):**

```fortran
program value_dynamic
integer :: v(4) = [11,22,33,44]
call sub(3, v(2))
contains
subroutine sub(n, x)
integer, intent(in) :: n
integer, value :: x(n)
print *, x ! expected: 22 33 44; garbage or segfault
if (any(x /= [22,33,44])) stop 1
x = 0
end subroutine
end program
```

Both print `22` followed by junk values (or crash) and stop with code 1 at `-O0` and higher. The generated HLFIR shows the defect directly: the element address is copied as a scalar and the temporary is cast to an array reference:

```mlir
%elt = hlfir.designate ... -> !fir.ref
%copy = hlfir.as_expr %elt : (!fir.ref) -> !hlfir.expr
%tmp:3 = hlfir.associate %copy {adapt.valuebyref}
: (!hlfir.expr) -> (!fir.ref, !fir.ref, i1)
%arg = fir.convert %tmp#0 : (!fir.ref) -> !fir.ref>
fir.call @_QFPsub(%arg) ...
```

The same scalar-sized copy affects, additionally:

- polymorphic array VALUE dummies (`class(t), value :: x(2)` with a `type(t)` element actual): the scalar copy is packaged through a rank-changing descriptor cast, so beyond the missing elements, type-bound dispatch on the dummy can crash;
- extension-type and unlimited-polymorphic associations (`type(child)` element to `class(parent)`, intrinsic element to `class(*)`);
- elements of array components (`v(2)%a(0)` passed to an array dummy).

CHARACTER VALUE sequence association is additionally affected, but character storage sequences are counted in characters with possible length remapping, which is a separate problem; this issue covers the non-character shapes.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.