Dear all, I had thought that we had fixed this in the past (see PR31001), but it did fail for me with all gcc versions I have tried (7-12) for a slightly more elaborate case as in the old testcase.
The loop in pack_internal did try to access the first element of the array argument to PACK even if one (or more) extents were zero. This is not good. Solution: check the extents and return early. (We already do a related check for the vector argument if present). Regtested on x86_64-pc-linux-gnu. OK for mainline? As this segfaults on valid code at runtime: I am considering backporting this, if there are no objections. Thanks, Harald
From dfa1e1ac5d8e43f1ca8f13b64330825581174f36 Mon Sep 17 00:00:00 2001 From: Harald Anlauf <anl...@gmx.de> Date: Thu, 9 Dec 2021 20:55:08 +0100 Subject: [PATCH] Fortran: PACK intrinsic should not try to read from zero-sized array libgfortran/ChangeLog: PR libfortran/103634 * intrinsics/pack_generic.c (pack_internal): Handle case when the array argument of PACK has one extent of size zero to avoid invalid reads. gcc/testsuite/ChangeLog: PR libfortran/103634 * gfortran.dg/zero_sized_13.f90: New test. --- gcc/testsuite/gfortran.dg/zero_sized_13.f90 | 20 ++++++++++++++++++++ libgfortran/intrinsics/pack_generic.c | 4 ++++ 2 files changed, 24 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/zero_sized_13.f90 diff --git a/gcc/testsuite/gfortran.dg/zero_sized_13.f90 b/gcc/testsuite/gfortran.dg/zero_sized_13.f90 new file mode 100644 index 00000000000..5620514334c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/zero_sized_13.f90 @@ -0,0 +1,20 @@ +! { dg-do run } +! PR libfortran/103634 - Runtime crash with PACK on zero-sized arrays + +program p + implicit none + type t + real :: r(24) = -99. + end type + type(t), allocatable :: new(:), old(:) + logical, allocatable :: mask(:) + integer :: n, m +! m = 1 ! works + m = 0 ! failed with SIGSEGV in pack_internal + allocate (old(m), mask(m)) + mask(:) = .false. + n = count (mask) + allocate (new(n)) + new(:) = pack (old, mask) + print *, size (new) +end diff --git a/libgfortran/intrinsics/pack_generic.c b/libgfortran/intrinsics/pack_generic.c index cad2fbbfbcd..f629e0e8469 100644 --- a/libgfortran/intrinsics/pack_generic.c +++ b/libgfortran/intrinsics/pack_generic.c @@ -126,6 +126,10 @@ pack_internal (gfc_array_char *ret, const gfc_array_char *array, if (mstride[0] == 0) mstride[0] = mask_kind; + for (n = 0; n < dim; n++) + if (extent[n] == 0) + return; + if (ret->base_addr == NULL || unlikely (compile_options.bounds_check)) { /* Count the elements, either for allocating memory or -- 2.26.2