Issue 87046
Summary [Flang] Segmentation fault on MAX/MIN
Labels flang
Assignees
Reporter JumpMasterJJ
    In the process of trying to solve #78089, I found that besides `ishftc`, `max/min` may cause segment fault when passing the parameter with optional attribute.

```fortran
! max/min
module m
  implicit none
contains

  function maxTest1 (a, b, c) result(r)
 integer(4)           :: a
    integer(4)             :: b
 integer(2),    optional :: c
    integer(4)                       :: r
 r = max(a, b, c)
  end

end module m

program p
  use m
  implicit none
  integer(4) :: num

  num = maxTest1(1, 2)

end program p
```

```shell
$ flang-new max.f90 -o max
$ ./max
Segmentation fault (core dumped)
```



By debugging flang, it appears that the problem lies here: `Fortran::evaluate::MayBePassedAsAbsentOptional`.
https://github.com/llvm/llvm-project/blob/abfc5efb55267689f1852fd7ce3e0a38876aa259/flang/lib/Evaluate/tools.cpp#L1254-L1262

This function seems to incorrectly determine the optional attribute of parameters other than `integer(4)`. And Causing the generated IR to directly load a `None` variable without determining `Some/None`.
Generated IR details:
```mlir
module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<f16, dense<16> : vector<2xi64>>, #dlti.dl_entry<f64, dense<64> : vector<2xi64>>, #dlti.dl_entry<i32, dense<32> : vector<2xi64>>, #dlti.dl_entry<i16, dense<16> : vector<2xi64>>, #dlti.dl_entry<i8, dense<8> : vector<2xi64>>, #dlti.dl_entry<i1, dense<8> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi64>>, #dlti.dl_entry<f80, dense<128> : vector<2xi64>>, #dlti.dl_entry<i128, dense<128> : vector<2xi64>>, #dlti.dl_entry<i64, dense<64> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<272>, dense<64> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<271>, dense<32> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<270>, dense<32> : vector<4xi64>>, #dlti.dl_entry<f128, dense<128> : vector<2xi64>>, #dlti.dl_entry<"dlti.endianness", "little">, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>>, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.target_triple = "x86_64-unknown-linux-gnu"} {
  func.func @_QMmPmaxtest1(%arg0: !fir.ref<i32> {fir.bindc_name = "a"}, %arg1: !fir.ref<i32> {fir.bindc_name = "b"}, %arg2: !fir.ref<i16> {fir.bindc_name = "c", fir.optional}) -> i32 {
    %0 = fir.declare %arg0 {uniq_name = "_QMmFmaxtest1Ea"} : (!fir.ref<i32>) -> !fir.ref<i32>
    %1 = fir.declare %arg1 {uniq_name = "_QMmFmaxtest1Eb"} : (!fir.ref<i32>) -> !fir.ref<i32>
    %2 = fir.declare %arg2 {fortran_attrs = #fir.var_attrs<optional>, uniq_name = "_QMmFmaxtest1Ec"} : (!fir.ref<i16>) -> !fir.ref<i16>
    %3 = fir.alloca i32 {bindc_name = "r", uniq_name = "_QMmFmaxtest1Er"}
    %4 = fir.declare %3 {uniq_name = "_QMmFmaxtest1Er"} : (!fir.ref<i32>) -> !fir.ref<i32>

    // it should be "%7 = fir.is_present %2 : (!fir.ref<i32>) -> i1",
    // just like "integer(4)", but it directly load the None.
    %5 = fir.load %2 : !fir.ref<i16>
    %6 = fir.convert %5 : (i16) -> i32
    %7 = fir.load %0 : !fir.ref<i32>
    %8 = fir.load %1 : !fir.ref<i32>
    %9 = arith.cmpi sgt, %7, %8 : i32
    %10 = arith.select %9, %7, %8 : i32
 %11 = arith.cmpi sgt, %10, %6 : i32
    %12 = arith.select %11, %10, %6 : i32
    fir.store %12 to %4 : !fir.ref<i32>
    %13 = fir.load %4 : !fir.ref<i32>
    return %13 : i32
  }
  func.func @_QQmain() attributes {fir.bindc_name = "p"} {
    %0 = fir.alloca i32 {adapt.valuebyref}
    %1 = fir.alloca i32 {adapt.valuebyref}
 %c2_i32 = arith.constant 2 : i32
    %c1_i32 = arith.constant 1 : i32
 %2 = fir.alloca i32 {bindc_name = "num", uniq_name = "_QFEnum"}
 %3 = fir.declare %2 {uniq_name = "_QFEnum"} : (!fir.ref<i32>) -> !fir.ref<i32>
    fir.store %c1_i32 to %1 : !fir.ref<i32>
    %false = arith.constant false
    fir.store %c2_i32 to %0 : !fir.ref<i32>
 %false_0 = arith.constant false
    %4 = fir.absent !fir.ref<i16>
 %5 = fir.call @_QMmPmaxtest1(%1, %0, %4) fastmath<contract> : (!fir.ref<i32>, !fir.ref<i32>, !fir.ref<i16>) -> i32
    fir.store %5 to %3 : !fir.ref<i32>
    return
  }
  fir.global @_QQEnvironmentDefaults constant : !fir.ref<tuple<i32, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>> {
    %0 = fir.zero_bits !fir.ref<tuple<i32, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>
 fir.has_value %0 : !fir.ref<tuple<i32, !fir.ref<!fir.array<0xtuple<!fir.ref<i8>, !fir.ref<i8>>>>>>
 }
}

```




It appears that `associated` will also have similar issues after implementation, as it also uses `Fortran::evaluate::MayBePassedAsAbsentOptional`.


```fortran
module m
  implicit none
contains

  function associatedTest1 (ptr, tar) result(r)
    integer, pointer  :: ptr
    integer, target, optional :: tar
    logical(4)            :: r

    r = associated(ptr, tar)
  end

end module m


program p
  use m
 implicit none
  logical :: b
  integer, pointer :: ptr

  b = associatedTest1(ptr)

end program p
```

```shell
$ flang-new max.f90 -o associated
$ ./associated
error: loc("/home/jump/llvm-project/flang/reproduced/associated.f90":10:5): /home/jump/llvm-project/flang/lib/Lower/ConvertCall.cpp:2434: not yet implemented: Inquired non-optional arg to intrinsic with custom handling
LLVM ERROR: aborting
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to