Message ID | a63d9ea1-aa49-482c-b858-bfb31a7598a6@gmx.de |
---|---|
State | New |
Headers | show |
Series | [v2] Fortran: fix for absent array argument passed to optional dummy [PR101135] | expand |
Le 15/03/2024 à 20:32, Harald Anlauf a écrit : > Dear all, > > as there has been some good progress in the handling of optional dummy > arguments, I looked again at this PR and a patch for it that I withdrew > as it turned out incomplete. > > It turned out that it now needs only a minor adjustment for optional > dummy arguments of procedures with bind(c) attribute so that ubsan > checking does not trigger. > > Along this way I extended the previous testcase to exercise to some > extent combinations of bind(c) and non-bind(c) procedures and found > one failure (since at least gcc-9) that is genuine: passing a missing > optional from a bind(c) procedure to an assumed-rank dummy, see > PR114355. The corresponding test is commented in the testcase. > > Regtested on x86_64-pc-linux-gnu. OK for mainline? > > Thanks, > Harald > (...) > > From b3079a82a220477704f8156207239e4af4103ea9 Mon Sep 17 00:00:00 2001 > From: Harald Anlauf <anlauf@gmx.de> > Date: Fri, 15 Mar 2024 20:14:07 +0100 > Subject: [PATCH] Fortran: fix for absent array argument passed to optional > dummy [PR101135] > > gcc/fortran/ChangeLog: > > PR fortran/101135 > * trans-array.cc (gfc_get_dataptr_offset): Check for optional > arguments being present before dereferencing data pointer. > > gcc/testsuite/ChangeLog: > > PR fortran/101135 > * gfortran.dg/missing_optional_dummy_6a.f90: Adjust diagnostic pattern. > * gfortran.dg/ubsan/missing_optional_dummy_8.f90: New test. > --- > gcc/fortran/trans-array.cc | 11 ++ > .../gfortran.dg/missing_optional_dummy_6a.f90 | 2 +- > .../ubsan/missing_optional_dummy_8.f90 | 108 ++++++++++++++++++ > 3 files changed, 120 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_8.f90 > > diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc > index 3673fa40720..a7717a8107e 100644 > --- a/gcc/fortran/trans-array.cc > +++ b/gcc/fortran/trans-array.cc > @@ -7526,6 +7526,17 @@ gfc_get_dataptr_offset (stmtblock_t *block, tree parm, tree desc, tree offset, > > /* Set the target data pointer. */ > offset = gfc_build_addr_expr (gfc_array_dataptr_type (desc), tmp); > + > + /* Check for optional dummy argument being present. Arguments of BIND(C) > + procedures are excepted here since they are handled differently. */ > + if (expr->expr_type == EXPR_VARIABLE > + && expr->symtree->n.sym->attr.dummy > + && expr->symtree->n.sym->attr.optional > + && !is_CFI_desc (NULL, expr)) I think the condition could additionally check the lack of subreferences. But it's maybe not worth the trouble, and the patch is conservatively correct as is, so OK. Thanks for the patch. > + offset = build3_loc (input_location, COND_EXPR, TREE_TYPE (offset), > + gfc_conv_expr_present (expr->symtree->n.sym), offset, > + fold_convert (TREE_TYPE (offset), gfc_index_zero_node)); > + > gfc_conv_descriptor_data_set (block, parm, offset); > } >
Hi Mikael, On 3/17/24 22:04, Mikael Morin wrote: >> diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc >> index 3673fa40720..a7717a8107e 100644 >> --- a/gcc/fortran/trans-array.cc >> +++ b/gcc/fortran/trans-array.cc >> @@ -7526,6 +7526,17 @@ gfc_get_dataptr_offset (stmtblock_t *block, >> tree parm, tree desc, tree offset, >> >> /* Set the target data pointer. */ >> offset = gfc_build_addr_expr (gfc_array_dataptr_type (desc), tmp); >> + >> + /* Check for optional dummy argument being present. Arguments of >> BIND(C) >> + procedures are excepted here since they are handled >> differently. */ >> + if (expr->expr_type == EXPR_VARIABLE >> + && expr->symtree->n.sym->attr.dummy >> + && expr->symtree->n.sym->attr.optional >> + && !is_CFI_desc (NULL, expr)) > > I think the condition could additionally check the lack of subreferences. > But it's maybe not worth the trouble, and the patch is conservatively > correct as is, so OK. I have thought about the conditions here for some time and did not find better ones. They need to be broad enough to catch the case in gfortran.dg/missing_optional_dummy_6a.f90 that (according to the tree-dump) was not properly handled previously and would have triggered ubsan at some point in the future when someone tried to change that testcase from currently dg-do compile to dg-do run... (After the patch it would pass, but I didn't dare to change the dg-do). I have pushed the patch as-is, but feel free to post testcases not covered (or improperly covered) to narrow this down further... > Thanks for the patch. Thanks for the review! Harald >> + offset = build3_loc (input_location, COND_EXPR, TREE_TYPE (offset), >> + gfc_conv_expr_present (expr->symtree->n.sym), offset, >> + fold_convert (TREE_TYPE (offset), gfc_index_zero_node)); >> + >> gfc_conv_descriptor_data_set (block, parm, offset); >> } >> > >
Le 17/03/2024 à 23:10, Harald Anlauf a écrit : > Hi Mikael, > > On 3/17/24 22:04, Mikael Morin wrote: >>> diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc >>> index 3673fa40720..a7717a8107e 100644 >>> --- a/gcc/fortran/trans-array.cc >>> +++ b/gcc/fortran/trans-array.cc >>> @@ -7526,6 +7526,17 @@ gfc_get_dataptr_offset (stmtblock_t *block, >>> tree parm, tree desc, tree offset, >>> >>> /* Set the target data pointer. */ >>> offset = gfc_build_addr_expr (gfc_array_dataptr_type (desc), tmp); >>> + >>> + /* Check for optional dummy argument being present. Arguments of >>> BIND(C) >>> + procedures are excepted here since they are handled >>> differently. */ >>> + if (expr->expr_type == EXPR_VARIABLE >>> + && expr->symtree->n.sym->attr.dummy >>> + && expr->symtree->n.sym->attr.optional >>> + && !is_CFI_desc (NULL, expr)) >> >> I think the condition could additionally check the lack of subreferences. >> But it's maybe not worth the trouble, and the patch is conservatively >> correct as is, so OK. > > I have thought about the conditions here for some time and did not > find better ones. They need to be broad enough to catch the case > in gfortran.dg/missing_optional_dummy_6a.f90 that (according to the > tree-dump) was not properly handled previously and would have triggered > ubsan at some point in the future when someone tried to change that > testcase from currently dg-do compile to dg-do run... No problem, as said it is conservatively correct. > (After the patch it would pass, but I didn't dare to change the dg-do). > Did it include cases not covered by the new testcase (which was quite complete already)? > I have pushed the patch as-is, but feel free to post testcases > not covered (or improperly covered) to narrow this down further... > The case I had in mind would only be a missed optimization, and probably not that important, so let's move on.
From b3079a82a220477704f8156207239e4af4103ea9 Mon Sep 17 00:00:00 2001 From: Harald Anlauf <anlauf@gmx.de> Date: Fri, 15 Mar 2024 20:14:07 +0100 Subject: [PATCH] Fortran: fix for absent array argument passed to optional dummy [PR101135] gcc/fortran/ChangeLog: PR fortran/101135 * trans-array.cc (gfc_get_dataptr_offset): Check for optional arguments being present before dereferencing data pointer. gcc/testsuite/ChangeLog: PR fortran/101135 * gfortran.dg/missing_optional_dummy_6a.f90: Adjust diagnostic pattern. * gfortran.dg/ubsan/missing_optional_dummy_8.f90: New test. --- gcc/fortran/trans-array.cc | 11 ++ .../gfortran.dg/missing_optional_dummy_6a.f90 | 2 +- .../ubsan/missing_optional_dummy_8.f90 | 108 ++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_8.f90 diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc index 3673fa40720..a7717a8107e 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -7526,6 +7526,17 @@ gfc_get_dataptr_offset (stmtblock_t *block, tree parm, tree desc, tree offset, /* Set the target data pointer. */ offset = gfc_build_addr_expr (gfc_array_dataptr_type (desc), tmp); + + /* Check for optional dummy argument being present. Arguments of BIND(C) + procedures are excepted here since they are handled differently. */ + if (expr->expr_type == EXPR_VARIABLE + && expr->symtree->n.sym->attr.dummy + && expr->symtree->n.sym->attr.optional + && !is_CFI_desc (NULL, expr)) + offset = build3_loc (input_location, COND_EXPR, TREE_TYPE (offset), + gfc_conv_expr_present (expr->symtree->n.sym), offset, + fold_convert (TREE_TYPE (offset), gfc_index_zero_node)); + gfc_conv_descriptor_data_set (block, parm, offset); } diff --git a/gcc/testsuite/gfortran.dg/missing_optional_dummy_6a.f90 b/gcc/testsuite/gfortran.dg/missing_optional_dummy_6a.f90 index c6a79059a91..b5e1726d74d 100644 --- a/gcc/testsuite/gfortran.dg/missing_optional_dummy_6a.f90 +++ b/gcc/testsuite/gfortran.dg/missing_optional_dummy_6a.f90 @@ -49,7 +49,7 @@ end program test ! { dg-final { scan-tree-dump-times "scalar2 \\(.* slr1" 1 "original" } } -! { dg-final { scan-tree-dump-times "= es1 != 0B" 1 "original" } } +! { dg-final { scan-tree-dump-times "= es1 != 0B" 2 "original" } } ! { dg-final { scan-tree-dump-times "assumed_shape2 \\(es1" 0 "original" } } ! { dg-final { scan-tree-dump-times "explicit_shape2 \\(es1" 1 "original" } } diff --git a/gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_8.f90 b/gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_8.f90 new file mode 100644 index 00000000000..fd3914934aa --- /dev/null +++ b/gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_8.f90 @@ -0,0 +1,108 @@ +! { dg-do run } +! { dg-additional-options "-fdump-tree-original -fsanitize=undefined" } +! +! PR fortran/101135 - Load of null pointer when passing absent +! assumed-shape array argument for an optional dummy argument +! +! Based on testcase by Marcel Jacobse + +program main + implicit none + character(len=3) :: a(6) = ['abc', 'def', 'ghi', 'jlm', 'nop', 'qrs'] + call as () + call as (a(::2)) + call as_c () + call as_c (a(2::2)) + call test_wrapper + call test_wrapper_c + call test_ar_wrapper + call test_ar_wrapper_c +contains + subroutine as (xx) + character(len=*), optional, intent(in) :: xx(*) + if (.not. present (xx)) return + print *, xx(1:3) + end subroutine as + + subroutine as_c (zz) bind(c) + character(len=*), optional, intent(in) :: zz(*) + if (.not. present (zz)) return + print *, zz(1:3) + end subroutine as_c + + subroutine test_wrapper (x) + real, dimension(1), intent(out), optional :: x + call test (x) + call test1 (x) + call test_c (x) + call test1_c (x) + end subroutine test_wrapper + + subroutine test_wrapper_c (w) bind(c) + real, dimension(1), intent(out), optional :: w + call test (w) + call test1 (w) + call test_c (w) + call test1_c (w) + end subroutine test_wrapper_c + + subroutine test (y) + real, dimension(:), intent(out), optional :: y + if (present (y)) y=0. + end subroutine test + + subroutine test_c (y) bind(c) + real, dimension(:), intent(out), optional :: y + if (present (y)) y=0. + end subroutine test_c + + subroutine test1 (y) + real, dimension(1), intent(out), optional :: y + if (present (y)) y=0. + end subroutine test1 + + subroutine test1_c (y) bind(c) + real, dimension(1), intent(out), optional :: y + if (present (y)) y=0. + end subroutine test1_c + + subroutine test_ar_wrapper (p, q, r) + real, intent(out), optional :: p + real, dimension(1), intent(out), optional :: q + real, dimension(:), intent(out), optional :: r + call test_ar (p) + call test_ar (q) + call test_ar (r) + call test_ar_c (p) + call test_ar_c (q) + call test_ar_c (r) + end subroutine test_ar_wrapper + + subroutine test_ar_wrapper_c (u, v, s) bind(c) + real, intent(out), optional :: u + real, dimension(1), intent(out), optional :: v + real, dimension(:), intent(out), optional :: s + call test_ar (u) + call test_ar (v) +! call test_ar (s) ! Disabled due to runtime segfault, see pr114355 + call test_ar_c (u) + call test_ar_c (v) + call test_ar_c (s) + end subroutine test_ar_wrapper_c + + subroutine test_ar (z) + real, dimension(..), intent(out), optional :: z + end subroutine test_ar + + subroutine test_ar_c (z) bind(c) + real, dimension(..), intent(out), optional :: z + end subroutine test_ar_c +end program + +! { dg-final { scan-tree-dump-times "data = v != 0B " 2 "original" } } +! { dg-final { scan-tree-dump-times "data = w != 0B " 2 "original" } } +! { dg-final { scan-tree-dump-times "data = q != 0B " 2 "original" } } +! { dg-final { scan-tree-dump-times "data = x != 0B " 2 "original" } } +! { dg-final { scan-tree-dump-times "data = xx.0 != 0B " 1 "original" } } +! { dg-output " abcghinop(\n|\r\n|\r)" }" +! { dg-output " defjlmqrs(\n|\r\n|\r)" }" -- 2.35.3