aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarald Anlauf <anlauf@gmx.de>2021-12-13 20:50:19 +0100
committerHarald Anlauf <anlauf@gmx.de>2021-12-14 16:56:50 +0100
commit1c613165a55b212c59a83796b20a1d555e096504 (patch)
treeba8584c09200fc8eb9c7fa31566987e6e3a62264
parent3305135c29e1c3e988bd9bad40aefc01d138aaca (diff)
downloadgcc-1c613165a55b212c59a83796b20a1d555e096504.zip
gcc-1c613165a55b212c59a83796b20a1d555e096504.tar.gz
gcc-1c613165a55b212c59a83796b20a1d555e096504.tar.bz2
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 or more extents of size zero to avoid invalid reads. gcc/testsuite/ChangeLog: PR libfortran/103634 * gfortran.dg/intrinsic_pack_6.f90: New test.
-rw-r--r--gcc/testsuite/gfortran.dg/intrinsic_pack_6.f9057
-rw-r--r--libgfortran/intrinsics/pack_generic.c9
2 files changed, 66 insertions, 0 deletions
diff --git a/gcc/testsuite/gfortran.dg/intrinsic_pack_6.f90 b/gcc/testsuite/gfortran.dg/intrinsic_pack_6.f90
new file mode 100644
index 0000000..917944d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/intrinsic_pack_6.f90
@@ -0,0 +1,57 @@
+! { dg-do run }
+! PR libfortran/103634 - Runtime crash with PACK on zero-sized arrays
+! Exercise PACK intrinsic for cases when it calls pack_internal
+
+program p
+ implicit none
+ type t
+ real :: r(24) = -99.
+ end type
+ type(t), allocatable :: new(:), old(:), vec(:)
+ logical, allocatable :: mask(:)
+ integer :: n, m
+! m = 1 ! works
+ m = 0 ! failed with SIGSEGV in pack_internal
+ do m = 0, 2
+ print *, m
+ allocate (old(m), mask(m), vec(m))
+ if (m > 0) vec(m)% r(1) = 42
+ mask(:) = .true.
+ n = count (mask)
+ allocate (new(n))
+
+ mask(:) = .false.
+ if (size (pack (old, mask)) /= 0) stop 1
+ mask(:) = .true.
+ if (size (pack (old, mask)) /= m) stop 2
+ new(:) = pack (old, mask) ! this used to segfault for m=0
+
+ mask(:) = .false.
+ if (size (pack (old, mask, vector=vec)) /= m) stop 3
+ new(:) = t()
+ new(:) = pack (old, mask, vector=vec) ! this used to segfault for m=0
+ if (m > 0) then
+ if ( new( m )% r(1) /= 42) stop 4
+ if (any (new(:m-1)% r(1) /= -99)) stop 5
+ end if
+
+ if (m > 0) mask(m) = .true.
+ if (size (pack (old, mask, vector=vec)) /= m) stop 6
+ new(:) = t()
+ new(:) = pack (old, mask, vector=vec) ! this used to segfault for m=0
+ if (m > 0) then
+ if (new(1)% r(1) /= -99) stop 7
+ end if
+ if (m > 1) then
+ if (new(m)% r(1) /= 42) stop 8
+ end if
+
+ if (size (pack (old(:0), mask(:0), vector=vec)) /= m) stop 9
+ new(:) = t()
+ new(:) = pack (old(:0), mask(:0), vector=vec) ! did segfault for m=0
+ if (m > 0) then
+ if (new(m)% r(1) /= 42) stop 10
+ end if
+ deallocate (old, mask, new, vec)
+ end do
+end
diff --git a/libgfortran/intrinsics/pack_generic.c b/libgfortran/intrinsics/pack_generic.c
index cad2fbb..15880e7 100644
--- a/libgfortran/intrinsics/pack_generic.c
+++ b/libgfortran/intrinsics/pack_generic.c
@@ -85,6 +85,7 @@ pack_internal (gfc_array_char *ret, const gfc_array_char *array,
index_type count[GFC_MAX_DIMENSIONS];
index_type extent[GFC_MAX_DIMENSIONS];
+ bool zero_sized;
index_type n;
index_type dim;
index_type nelem;
@@ -114,10 +115,13 @@ pack_internal (gfc_array_char *ret, const gfc_array_char *array,
else
runtime_error ("Funny sized logical array");
+ zero_sized = false;
for (n = 0; n < dim; n++)
{
count[n] = 0;
extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
+ if (extent[n] <= 0)
+ zero_sized = true;
sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,n);
mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
}
@@ -126,6 +130,11 @@ pack_internal (gfc_array_char *ret, const gfc_array_char *array,
if (mstride[0] == 0)
mstride[0] = mask_kind;
+ if (zero_sized)
+ sptr = NULL;
+ else
+ sptr = array->base_addr;
+
if (ret->base_addr == NULL || unlikely (compile_options.bounds_check))
{
/* Count the elements, either for allocating memory or