This code: REAL X(2,3), Y(2) Y=[1.,2.] CALL SUB(X,Y) DO I = 1, 3 PRINT*,X(:,I) ENDDO END SUBROUTINE SUB(A,B) REAL A(:,:), B(:) A(:,:) = SPREAD(B(:),2,SIZE(A,2)) END results in: 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 using: /usr/snp/bin/gfortran -static -v -g -O2 -fbacktrace spread.f Driving: /usr/snp/bin/gfortran -static -v -g -O2 -fbacktrace spread.f -lgfortranbegin -lgfortran -lm Using built-in specs. Target: x86_64-unknown-linux-gnu Configured with: ../trunk/configure --prefix=/usr/snp/ --disable-multilib --disable-nls --enable-languages=fortran Thread model: posix gcc version 4.3.0 20070903 (experimental) (GCC) /usr/snp/bin/../libexec/gcc/x86_64-unknown-linux-gnu/4.3.0/f951 spread.f -ffixed-form -quiet -dumpbase spread.f -mtune=generic -auxbase spread -g -O2 -version -fbacktrace -fintrinsic-modules-path /usr/snp/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.3.0/finclude -o /tmp/ccjGK59d.s GNU F95 (GCC) version 4.3.0 20070903 (experimental) (x86_64-unknown-linux-gnu) compiled by GNU C version 4.3.0 20070903 (experimental), GMP version 4.2.1, MPFR version 2.3.0-rc1. GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 as -V -Qy -o /tmp/cc53anSf.o /tmp/ccjGK59d.s GNU assembler version 2.17.90 (x86_64-linux-gnu) using BFD version (GNU Binutils for Debian) 2.17.90.20070812 /usr/snp/bin/../libexec/gcc/x86_64-unknown-linux-gnu/4.3.0/collect2 -m elf_x86_64 -static /usr/lib/../lib64/crt1.o /usr/lib/../lib64/crti.o /usr/snp/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.3.0/crtbeginT.o -L/usr/snp/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.3.0 -L/usr/snp/bin/../lib/gcc -L/usr/snp/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.3.0/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/snp/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.3.0/../../.. /tmp/cc53anSf.o -lgfortranbegin -lgfortran -lm --start-group -lgcc -lgcc_eh -lc --end-group /usr/snp/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.3.0/crtend.o /usr/lib/../lib64/crtn.o Debian's testing gfortran-4.2 gave me another bunch of nonsense: -4.5149084E-10 4.5916347E-41 -4.5151327E-10 4.5916347E-41 -4.5151283E-10 4.5916347E-41 Trying to print the SPREAD expression directly gave me a segmentation fault using the above gfortran 4.2 and an empty line using 4.3.
The code is invalid without explicit interface to SUB(). Modified code: REAL X(2,3), Y(2) Y=[1.,2.] CALL SUB(X,Y) DO I = 1, 3 PRINT*,X(:,I) ENDDO CONTAINS SUBROUTINE SUB(A,B) REAL A(:,:), B(:) A(:,:) = SPREAD(B(:),2,SIZE(A,2)) END SUBROUTINE SUB END works just fine. Alternatively REAL X(2,3), Y(2) Y=[1.,2.] CALL SUB(X,Y,size(y,1),size(y,2)) DO I = 1, 3 PRINT*,X(:,I) ENDDO END SUBROUTINE SUB(A,B,n,m) INTEGER n,m REAL A(n,m), B(n) A(:,:) = SPREAD(B(:),2,SIZE(A,2)) END also works as expected. If the main program and SUB are compiled together, the compiler could of course diagnose this, as e.g. pathscale does: SUBROUTINE SUB(A,B) ^ pathf95-1277 pathf90: ERROR SUB, File = t.f90, Line = 9, Column = 18 Procedure "SUB" is referenced at line 3 (t.f90). It must have an explicit interface specified. Regards, Juha
CLOSE as invalid as subroutines with assumed-shaped dummy arguments require an explicit interface. The whole-file checking - which would diagnose this as error - is planned for GCC 4.4.0. See http://gcc.gnu.org/wiki/GFortran43 and, e.g., PR 26227.
Yeah, I have to come up with a better example. In the original code that I reduced, the interface came from a module file.
Second try, now with interface and using zero sized arrays: $ cat spread.f INTERFACE SUB SUBROUTINE SUB(P,Q) REAL, INTENT(OUT) :: P(:,:) REAL, INTENT(IN) :: Q(:) END SUBROUTINE END INTERFACE REAL, ALLOCATABLE :: X(:,:), Y(:) ALLOCATE(X(0,3)) ALLOCATE(Y(0)) ! Y=[1.,2.] CALL SUB(X,Y) DO I = 1, 3 PRINT*,X(:,I) ENDDO END SUBROUTINE SUB(A,B) REAL, INTENT(OUT) :: A(:,:) REAL, INTENT(IN) :: B(:) A(:,:) = SPREAD(B(:),2,SIZE(A,2)) END $ /usr/snp/bin/gfortran -g -O2 -static -fbacktrace spread.f $ ./a.out Program received signal 11 (SIGSEGV): Segmentation fault. Backtrace for this error: + function __restore_rt (0x4185D0) from file libgcc2.c + function memcpy (0x432D85) + function spread_internal (0x40A50F) at line 145 of file spread_generic.c + function sub_ (0x400404) at line 16 of file spread.f + in the main program at line 11 of file spread.f + function __libc_start_main (0x4138E7)
Reduced testcase: real :: x(0,3), y(0) x = spread(y,2,3) end Backtrace: #0 0x0000000000431600 in memcpy () #1 0x000000000040400f in spread_internal (ret=<value optimized out>, source=<value optimized out>, along=<value optimized out>, pncopies=<value optimized out>, size=4) at ../../../../trunk2/libgfortran/intrinsics/spread_generic.c:148 #2 0x0000000000400342 in MAIN__ () at a.f90:2
Quoting spread_generic.c: 145 for (n = 0; n < ncopies; n++) 146 { 147 memcpy (dest, sptr, size); 148 dest += rdelta; 149 } The C 99 Standard has the following to say about the mem* functions (7.21.2.1 ff): Where an argument declared as size_t n specifies the length of the array for a function, n can have the value zero on a call to that function. Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values, as described in 7.1.4. So "size" can be zero, *but the the pointer arguments on such a call shall still have valid values.*
This one should be fairly straightforward. Mine :-)
Wouldn't it be an option to simply bail out early (i.e., after the error checks) in case of size == 0 ? E.g., like this: 62 63 rrank = srank + 1; 64 if (rrank > GFC_MAX_DIMENSIONS) 65 runtime_error ("return rank too large in spread()"); 66 67 if (*along > rrank) 68 runtime_error ("dim outside of rank in spread()"); if (size == 0) return Or do we actually have to set something on return ?
Subject: Bug number PR 33298 A patch for this bug has been added to the patch tracker. The mailing list url for the patch is http://gcc.gnu.org/ml/gcc-patches/2007-09/msg00394.html
Subject: Bug 33298 Author: tkoenig Date: Thu Sep 6 19:25:30 2007 New Revision: 128206 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=128206 Log: 2007-09-06 Thomas Koenig <tkoenig@gcc.gnu.org> PR fortran/33298 * intrinsics/spread_generic.c(spread_internal): Enable bounds checking by comparing extents if the bounds_check option has been set. If any extent is <=0, return early. 2007-09-06 Thomas Koenig <tkoenig@gcc.gnu.org> PR fortran/33298 * spread_zerosize_1.f90: New test case. * spread_bounds_1.f90: New test case. Added: trunk/gcc/testsuite/gfortran.dg/spread_bounds_1.f90 trunk/gcc/testsuite/gfortran.dg/spread_zerosize_1.f90 Modified: trunk/gcc/testsuite/ChangeLog trunk/libgfortran/ChangeLog trunk/libgfortran/intrinsics/spread_generic.c
Subject: Re: Wrong code for SPREAD on zero-sized arrays Hi Toon, > > ------- Comment #8 from toon at moene dot indiv dot nluug dot nl 2007-09-06 08:56 ------- > Wouldn't it be an option to simply bail out early (i.e., after the error > checks) in case of size == 0 ? > I think size is the size of an element in the array (in bytes), so this wouldn't really help. Thomas
Fixed on trunk. Closing.