Dear All,

the attached patch fixes the problem that UBSAN did generate a check
of the passed stride of an optional array dummy argument even in the
case the actual was not present, as seen by the reporter when compiling
with -O0.  Wrapping the setup of the descriptor by a test of presence
of the argument eliminates this path.

Regarding the testcase, as I could not find a simple failing
reproducer, I chose to verify the new test in the tree-dump
and the reduced UBSAN count in the optimized dump.

Regtested on x86_64-pc-linux-gnu.  OK for mainline?

Thanks,
Harald

From 803f7967df2103eae7764bbe280854574d0c1076 Mon Sep 17 00:00:00 2001
From: Harald Anlauf <[email protected]>
Date: Tue, 30 Sep 2025 21:14:12 +0200
Subject: [PATCH] Fortran: UBSAN uninitialized stride for missing optional
 argument [PR122080]

	PR fortran/122080

gcc/fortran/ChangeLog:

	* trans-array.cc (gfc_conv_array_parameter): Wrap the derivation of
	bounds and strides for the descriptor of an optional dummy array
	argument by a test on argument presence when it is supposed to be
	passed to an optional argument.

gcc/testsuite/ChangeLog:

	* gfortran.dg/ubsan/missing_optional_dummy_9.f90: New test.
---
 gcc/fortran/trans-array.cc                    |  9 ++++++++
 .../ubsan/missing_optional_dummy_9.f90        | 22 +++++++++++++++++++
 2 files changed, 31 insertions(+)
 create mode 100644 gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_9.f90

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 0111c9566f4..db34de44401 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9446,6 +9446,15 @@ gfc_conv_array_parameter (gfc_se *se, gfc_expr *expr, bool g77,
 
 	  gfc_add_expr_to_block (&se->pre, tmp);
 	}
+      else if (pass_optional && full_array_var && sym->as && sym->as->rank != 0)
+	{
+	  /* Perform calculation of bounds and strides of optional array dummy
+	     only if the argument is present.  */
+	  tmp = build3_v (COND_EXPR, gfc_conv_expr_present (sym),
+			  gfc_finish_block (&se->pre),
+			  build_empty_stmt (input_location));
+	  gfc_add_expr_to_block (&se->pre, tmp);
+	}
     }
 
   /* Deallocate the allocatable components of structures that are
diff --git a/gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_9.f90 b/gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_9.f90
new file mode 100644
index 00000000000..06b0004d573
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/ubsan/missing_optional_dummy_9.f90
@@ -0,0 +1,22 @@
+! { dg-do compile }
+! { dg-options "-O2 -fdump-tree-original -fdump-tree-optimized -fsanitize=undefined" }
+!
+! PR fortran/122080 - UBSAN: uninitialized stride for missing actual argument
+!
+! Contributed by Henri Menke
+
+subroutine outer (optarr)
+  real, optional, intent(in) :: optarr(:,:)
+  interface
+     subroutine inner (optarr)
+       real, optional, intent(in) :: optarr(:,:)
+     end subroutine inner
+  end interface
+  call inner (optarr)
+end subroutine outer
+
+! There will be 2 remaining UBSAN checks of stride wrapped by a check
+! for argument presence:
+!
+! { dg-final { scan-tree-dump-times "if \\(optarr.0 != 0B\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "UBSAN_CHECK_SUB (.)* stride" 2 "optimized" } }
-- 
2.51.0

Reply via email to