On 22 July 2024 20:53:18 CEST, Mikael Morin <morin-mik...@orange.fr> wrote:
>From: Mikael Morin <mik...@gcc.gnu.org>
>
>Hello,
>
>this fixes a null pointer dereference with absent optional dummy passed
>as BACK argument of MINLOC/MAXLOC.
>
>Tested for regression on x86_64-linux.
>OK for master?
>
>-- >8 --
>
>Protect the evaluation of BACK with a check that the reference is non-null
>in case the expression is an optional dummy, in the inline code generated
>for MINLOC and MAXLOC.
>
>This change contains a revert of the non-testsuite part of commit
>r15-1994-ga55d24b3cf7f4d07492bb8e6fcee557175b47ea3, which factored the
>evaluation of BACK out of the loop using the scalarizer.  It was a bad idea,
>because delegating the argument evaluation to the scalarizer makes it
>cumbersome to add a null pointer check next to the evaluation.
>
>Instead, evaluate BACK at the beginning, before scalarization, add a check
>that the argument is present if necessary, and evaluate the resulting
>expression to a variable, before using the variable in the inline code.
>
>gcc/fortran/ChangeLog:
>
>       * trans-intrinsic.cc (maybe_absent_optional_variable): New function.
>       (gfc_conv_intrinsic_minmaxloc): Remove BACK from scalarization and
>       evaluate it before.  Add a check that BACK is not null if the
>       expression is an optional dummy.  Save the resulting expression to a
>       variable.  Use the variable in the generated inline code.
>
>gcc/testsuite/ChangeLog:
>
>       * gfortran.dg/maxloc_6.f90: New test.
>       * gfortran.dg/minloc_7.f90: New test.
>---
> gcc/fortran/trans-intrinsic.cc         |  81 +++++-
> gcc/testsuite/gfortran.dg/maxloc_6.f90 | 366 +++++++++++++++++++++++++
> gcc/testsuite/gfortran.dg/minloc_7.f90 | 366 +++++++++++++++++++++++++
> 3 files changed, 799 insertions(+), 14 deletions(-)
> create mode 100644 gcc/testsuite/gfortran.dg/maxloc_6.f90
> create mode 100644 gcc/testsuite/gfortran.dg/minloc_7.f90
>
>diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
>index 180d0d7a88c..9f3c3ce47bc 100644
>--- a/gcc/fortran/trans-intrinsic.cc
>+++ b/gcc/fortran/trans-intrinsic.cc
>@@ -5209,6 +5209,50 @@ gfc_conv_intrinsic_dot_product (gfc_se * se, gfc_expr * 
>expr)
> }
> 
> 
>+/* Tells whether the expression E is a reference to an optional variable whose
>+   presence is not known at compile time.  Those are variable references 
>without
>+   subreference; if there is a subreference, we can assume the variable is
>+   present.  We have to special case full arrays, which we represent with a 
>fake
>+   "full" reference, and class descriptors for which a reference to data is 
>not
>+   really a subreference.  */
>+
>+bool
>+maybe_absent_optional_variable (gfc_expr *e)
>+{
>+  if (!(e && e->expr_type == EXPR_VARIABLE))
>+    return false;

[]

>+}
>+
>+
> /* Remove unneeded kind= argument from actual argument list when the
>    result conversion is dealt with in a different place.  */
> 
>@@ -5321,11 +5365,11 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * 
>expr, enum tree_code op)
>   tree nonempty;
>   tree lab1, lab2;
>   tree b_if, b_else;
>+  tree back;
>   gfc_loopinfo loop;
>   gfc_actual_arglist *actual;
>   gfc_ss *arrayss;
>   gfc_ss *maskss;
>-  gfc_ss *backss;
>   gfc_se arrayse;
>   gfc_se maskse;
>   gfc_expr *arrayexpr;
>@@ -5391,10 +5435,27 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * 
>expr, enum tree_code op)
>     && maskexpr->symtree->n.sym->attr.dummy
>     && maskexpr->symtree->n.sym->attr.optional;
>   backexpr = actual->next->next->expr;
>-  if (backexpr)
>-    backss = gfc_get_scalar_ss (gfc_ss_terminator, backexpr);
>+
>+  gfc_init_se (&backse, NULL);
>+  if (backexpr == nullptr)
>+    back = logical_false_node;
>+  else if (maybe_absent_optional_variable (backexpr))
>+    {

/* if this fires, some wonky race is going on.. */

>+      gcc_assert (backexpr->expr_type == EXPR_VARIABLE);

drop it, downgrade to checking, or is it worth?

>+
>+      gfc_conv_expr (&backse, backexpr);
>+      tree present = gfc_conv_expr_present (backexpr->symtree->n.sym, false);
>+      back = fold_build2_loc (input_location, TRUTH_ANDIF_EXPR,
>+                            logical_type_node, present, backse.expr);
>+    }
>   else
>-    backss = nullptr;
>+    {
>+      gfc_conv_expr (&backse, backexpr);
>+      back = backse.expr;
>+    }
>+  gfc_add_block_to_block (&se->pre, &backse.pre);
>+  back = gfc_evaluate_now_loc (input_location, back, &se->pre);
>+  gfc_add_block_to_block (&se->pre, &backse.post);
> 
>   nonempty = NULL

[]
thanks

Reply via email to