Hi Chris!

Am 10.11.25 um 00:45 schrieb Christopher Albert:
Thanks, Harald!

On Sun, 9 Nov 2025 22:57:29 +0100
Harald Anlauf <[email protected]> wrote:

Am 08.11.25 um 18:03 schrieb Jerry D:
On 11/7/25 8:30 PM, Christopher Albert wrote:
Derived types with recursive allocatable components and FINAL
procedures trigger an ICE in gimplify_call_expr because the
finalizer wrapper's result
symbol references itself (final->result = final), creating a
cycle. This patch creates a separate __result_<typename> symbol to
break the cycle.

Self-assignment (a = a) with such types causes use-after-free
because the left-hand side is finalized before copying, destroying
the source. The patch
adds detection using gfc_dep_compare_expr at compile time and
pointer comparison at runtime to skip finalization when lhs == rhs.

Test pr112459.f90 now expects 6 _final calls instead of 12 because
separate
result symbols eliminate double-counting in tree dumps.

--- snip ---

Applies and test OK here. I want to see if any one else has any
comments.

Jerry

Albert,

I did see the patch with commit messages inlined, not attached.
Hope this did not lead me to wrong observations.

I attach now an updated patch (still not used to the process).

The commit message is not properly formed here; there should not
be <TAB><SPACE><SPACE> for continuation lines, just <TAB>.
Trying to push would lead to a rejection by the filters.

Thanks for pointing that out, this is fixed.

Regarding the run-time testcases: while writing to stdout and
checking the output with a pattern works, also please consider
the alternative
    "if (result /= expected) stop n"
where you think it is appropriate (e.g. the total finalization count)
and where it may make the testcase easier to read for others.
(Not critical, though).

I modified testcase finalizer_self_assign.f90 slightly by replacing
the self-assignment

      a = a

by

      a = (a)

and get a runtime failure:

   ERROR: a%next deallocated
ERROR STOP 1

with a traceback from the ERROR STOP.  That case might need a
different treatment, maybe a temporary, to be able keep the nested
components.  Can you have a further look?

If you do not find a simple fix, we might proceed and track this
issue either in the existing PR or move it to a different one.
(NAG and Intel seem to get this variant right.)

Found a simple fix, should work now. Hope this is clean enough.

Hmm, this works for scalar instances, but does not get the bounds
right for arrays.

Example: add to test_self_assign of finalizer_self_assign.f90:

  block
    type(node_t), allocatable :: b(:), c(:)
    allocate (b(5:5))
    b = (b)
    print *, lbound (b)             ! Should print: 1
  end block

This now prints:

           5

Interestingly, NAG prints the same!
Only Intel (ifx) gets it right:

           1

This is because lbound (b,1) = 5, but lbound ((b),1) = 1;
see F2023:10.2.1.3 and the description of LBOUND.
(The parentheses enforce the resetting of the bounds).

@Jerry: we could proceed with the current patch, maybe add a TODO
for the array assignment case and let Chris check if he finds a
separate solution for the rank /= 0 version.

Thanks,
Harald

Thanks,
Harald



Best,
Chris

Reply via email to