[flang-commits] [flang] [Flang] Allow Intrinsic simpification with min/maxloc dim and scalar result (PR #76194)

via flang-commits flang-commits at lists.llvm.org
Tue Jan 9 03:18:22 PST 2024


jeanPerier wrote:

Hi @davemgreen, I was able to reproduce the issue and this is indeed a bug with this patch.

For the following program, the simplified maxloc function stores into the result descriptor as if the result descriptor is a rank 1 array descriptor, but it is provided a scalar descriptor. This causes some memory that do not belong to the result descriptor to be written with bounds and stride values. The end-to-end bug is hard to reproduce because it depends on how the stack is laid out and if inlining occurs in LLVM it may "fix" the bug.

```
! src.f90
module test
contains
subroutine bug(a)
  real :: a (:)
  i = maxloc(a,dim=1)
  ! Memory bug around result descriptor of the simplified intrinsic function
  ! overwrites A descriptor and leads
  ! to an invalid a(i) address to be read inside crash.
  call crash(a(i))
end subroutine
end module

subroutine crash(x)
 real :: x
 print *, x
end subroutine

  use test
  real :: a(10) = 0.
  call bug(a)
end
```

Here is the following flow that expose the bug end-to-end (on X86-64 at least). The executable segfaults.
```
flang-new -fc1 -emit-fir src.f90 -o ok.fir
fir-opt --simplify-intrinsics ok.fir -o bad.fir
flang-new -fc1 -emit-llvm bad.fir && /proj/nv/llvm/Linux_x86_64/llvm-2409/bin/flang-new bad.ll
./a.out
```

In bad.fir, you can see that the bug is caused by the descriptor type mismatch between the `@_FortranAMaxlocDimx1_i32_f32_contract_simplified` and its call site:

```
 func.func @_QMtestPbug(%arg0: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "a"}) {
    %0 = fir.alloca !fir.box<!fir.heap<i32>>
    // ...
    %9 = fir.convert %0 : (!fir.ref<!fir.box<!fir.heap<i32>>>) -> !fir.ref<!fir.box<none>>
    // ...
    fir.call @_FortranAMaxlocDimx1_i32_f32_contract_simplified(%9, %10, %12)
   // ...
  }
 func.func private @_FortranAMaxlocDimx1_i32_f32_contract_simplified(%arg0: !fir.ref<!fir.box<none>>, %arg1: !fir.box<none>, %arg2: !fir.box<none>) {
    // ... computing maxloc
    // inconsistent cast given the scalar descriptor passed on the call site.
    %11 = fir.convert %arg0 : (!fir.ref<!fir.box<none>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<1xi32>>>>
    fir.store %3 to %11 : !fir.ref<!fir.box<!fir.heap<!fir.array<1xi32>>>>
 }
```

Also, please beware that MAXLOC/MINLOC current runtime implementation is incorrect with regards to NANs and is being fixed in https://github.com/llvm/llvm-project/pull/76999. The inlined version should also behave correctly with NANs (I did not check if this is the case or not).

https://github.com/llvm/llvm-project/pull/76194


More information about the flang-commits mailing list