Message ID | trinity-44c88958-25da-4d91-a3a5-09dbff59d448-1639080318194@3c-app-gmx-bs60 |
---|---|
State | New |
Headers | show |
Series | PR libfortran/103634 - Runtime crash with PACK on zero-sized arrays | expand |
Hello, On 09/12/2021 21:05, Harald Anlauf via Fortran wrote: > 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). If there is a vector argument, aren’t we supposed to copy it to the result ? There is something else to pay attention for, the early return should come at least after the return array bounds have been set. In the testcase an array with the correct bounds has been allocated beforehand to hold the return value, but it’s not always the case. For what it’s worth, the non-generic variant in pack.m4 (or in pack_{i,f,c}{1,2,4,8,10,16}.c) has a zero extent check and it clears the source ptr in that case, which makes it setup the return array and then jump to the vector copy at the end of the function.
Hi Mikael, Am 09.12.21 um 21:37 schrieb Mikael Morin: > Hello, > > On 09/12/2021 21:05, Harald Anlauf via Fortran wrote: >> 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). > > If there is a vector argument, aren’t we supposed to copy it to the > result ? > There is something else to pay attention for, the early return should > come at least after the return array bounds have been set. In the > testcase an array with the correct bounds has been allocated beforehand > to hold the return value, but it’s not always the case. you are absolutely right, I had gotten that wrong. > For what it’s worth, the non-generic variant in pack.m4 (or in > pack_{i,f,c}{1,2,4,8,10,16}.c) has a zero extent check and it clears the > source ptr in that case, which makes it setup the return array and then > jump to the vector copy at the end of the function. > The code is so similar (for good reason) that it makes sense to keep it synchronous. I added code for 'zero_sized' array with the minor difference that I made it boolean instead of integer. I also extended the testcase so that it exercises PACK/pack_internal a little, for argument 'vector' present as well as not. (There are existing tests for intrinsic types, but not for the issue at hand). Regtested again, and checked the testcase (against other compilers and also with valgrind). OK now? Thanks, Harald
Works better with patch attached... Am 13.12.21 um 21:25 schrieb Harald Anlauf via Gcc-patches: > Hi Mikael, > > Am 09.12.21 um 21:37 schrieb Mikael Morin: >> Hello, >> >> On 09/12/2021 21:05, Harald Anlauf via Fortran wrote: >>> 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). >> >> If there is a vector argument, aren’t we supposed to copy it to the >> result ? >> There is something else to pay attention for, the early return should >> come at least after the return array bounds have been set. In the >> testcase an array with the correct bounds has been allocated beforehand >> to hold the return value, but it’s not always the case. > > you are absolutely right, I had gotten that wrong. > >> For what it’s worth, the non-generic variant in pack.m4 (or in >> pack_{i,f,c}{1,2,4,8,10,16}.c) has a zero extent check and it clears the >> source ptr in that case, which makes it setup the return array and then >> jump to the vector copy at the end of the function. >> > > The code is so similar (for good reason) that it makes sense to keep > it synchronous. I added code for 'zero_sized' array with the minor > difference that I made it boolean instead of integer. > > I also extended the testcase so that it exercises PACK/pack_internal > a little, for argument 'vector' present as well as not. (There are > existing tests for intrinsic types, but not for the issue at hand). > > Regtested again, and checked the testcase (against other compilers > and also with valgrind). > > OK now? > > Thanks, > Harald >
Le 13/12/2021 à 21:27, Harald Anlauf via Fortran a écrit : > Works better with patch attached... > > Am 13.12.21 um 21:25 schrieb Harald Anlauf via Gcc-patches: >> >> The code is so similar (for good reason) that it makes sense to keep >> it synchronous. I added code for 'zero_sized' array with the minor >> difference that I made it boolean instead of integer. >> >> I also extended the testcase so that it exercises PACK/pack_internal >> a little, for argument 'vector' present as well as not. (There are >> existing tests for intrinsic types, but not for the issue at hand). >> >> Regtested again, and checked the testcase (against other compilers >> and also with valgrind). >> >> OK now? >> Yes, thanks.
From dfa1e1ac5d8e43f1ca8f13b64330825581174f36 Mon Sep 17 00:00:00 2001 From: Harald Anlauf <anlauf@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