Summary: | array assignment from function writes out of bounds | ||
---|---|---|---|
Product: | gcc | Reporter: | Gavin Salam <salam> |
Component: | fortran | Assignee: | Daniel Kraft <domob> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | d, dfranke, gcc-bugs, salam, tkoenig |
Priority: | P3 | Keywords: | wrong-code |
Version: | 4.4.0 | ||
Target Milestone: | --- | ||
Host: | Target: | ||
Build: | Known to work: | ||
Known to fail: | 4.4.0 4.2.0 4.3.0 | Last reconfirmed: | 2008-09-07 14:04:38 |
Bug Depends on: | |||
Bug Blocks: | 32834 | ||
Attachments: | test case |
Description
Gavin Salam
2008-08-22 10:27:12 UTC
Created attachment 16127 [details]
test case
# to see the issue, type
gfortran -g -Wall bounds_issue.f90
./a.out
# or
valgrind ./a.out
Confirmed on i686-apple-darwin9 (both 32 and 64 bit modes). Compiling the test with -fbounds-check gives at run time: At line 18 of file pr37199.f90 Fortran runtime error: Array bound mismatch for dimension 1 of array 'pxq' The modified test program bounds_issue implicit none integer, parameter :: dp = kind(1.0d0) real(dp), pointer :: pdf0(:,:), dpdf(:,:) allocate(pdf0(0:282,-6:7)) allocate(dpdf(0:282,-6:7)) ! with dpdf(0:283,-6:7) [illegal] error disappears write(*,*) lbound(dpdf), ubound(dpdf) pdf0 = 1.0d0 dpdf = 0.0d0 dpdf = tmp_PConv(pdf0) if (any(dpdf /= pdf0)) call abort() contains function tmp_PConv(q_in) result(Pxq) real(dp), intent(in) :: q_in(0:,-6:) real(dp) :: Pxq(0:ubound(q_in,dim=1),-6:7) Pxq = 0d0 write(*,*) lbound(q_in), ubound(q_in) write(*,*) lbound(Pxq), ubound(Pxq) Pxq = q_in return end function tmp_PConv end program bounds_issue gives at run time 0 -6 282 7 0 -6 282 7 0 -6 282 7 and does not abort, suggesting that the copy has been properly done. It looks like as another "off by one" issue(?). Further reduced: program bounds_issue real, pointer :: pdf0(:) allocate(pdf0(0:282)) pdf0 = f(pdf0) contains function f(x) real, intent(in) :: x(0:) ! x(1:), f(1:...) works real :: f(0:ubound(x,dim=1)) ! x(-1:), f(-1:...) crashes f = 0.0 end function end program bounds_issue If the lower bounds in the function argument and function return value are set to 1 and -1 respectively, then the diff of the respective tree dumps is quite small. Which of the seven changes which can be observed is the significant one, I can not tell. parm.12.dim[0].ubound = D.1541; parm.12.dim[0].stride = NON_LVALUE_EXPR <D.1546>; parm.12.data = (void *) &(*ifm.11)[0]; parm.12.offset = NON_LVALUE_EXPR <D.1545>; D.1547 = MAX_EXPR <(parm.12.dim[0].ubound - parm.12.dim[0].lbound) + 1, 0>; - D.1548 = D.1547 + -1; + D.1548 = D.1547 + -2; atmp.13.dtype = 281; atmp.13.dim[0].stride = 1; atmp.13.dim[0].lbound = 0; atmp.13.dim[0].ubound = D.1548; This one (from the diffs on my machine) is the problematic one. The value subtracted should be -1 independently of the lower bound. D.1548 will later be used in calculating the size of the temporary allocated, and for a lower-bound of 2, for instance, one element will be missing (for lower-bound 3 it would be 2 elements). I'm not yet completely sure what the problem is for a lower bound of 0 or -1, though. There, too much memory is allocated and the atmp's (the result array's) upper bound is too large. But I'll try to locate the problem in gfortran now and fix it and see what this does for all kinds of bounds. program bounds_issue real, pointer :: pdf0(:) allocate(pdf0(0:282)) pdf0 = f(pdf0) contains function f(x) real, intent(in) :: x(0:) ! x(1:), f(1:...) works real :: f(0:ubound(x,dim=1)) ! x(-1:), f(-1:...) crashes f = 0.0 end function end program bounds_issue --- For the temporary array holding the result and the loop assigning back to pdf0, the bounds of f(0:ubound(x,dim=1)) are used. The interface mapping of x in the upper bound however does not supply an array-spec to the symbol, and thus UBOUND(x) returns the number of elements in x rather than the real upper bound matching the fixed lower-bound of 0 as for an entity not being a full array. Thus, the loop starts at 0 because of the constant lower bound but runs one element too far because the upper bound is evaluated as if the lower was 1. This leads to the segfault in any case but when 1 is indeed the lower bound. It seems to be possible to simply copy the array-spec to new_sym in gfc_add_interface_mapping, I'm working this out at the moment. Subject: Bug 37199 Author: domob Date: Mon Sep 8 09:17:27 2008 New Revision: 140102 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=140102 Log: 2008-09-08 Daniel Kraft <d@domob.eu> PR fortran/37199 * trans-expr.c (gfc_add_interface_mapping): Set new_sym->as. (gfc_map_intrinsic_function): Added checks against NULL bounds in array specs. 2008-09-08 Daniel Kraft <d@domob.eu> PR fortran/37199 * gfortran.dg/array_function_2.f90: New test. Added: trunk/gcc/testsuite/gfortran.dg/array_function_2.f90 Modified: trunk/gcc/fortran/ChangeLog trunk/gcc/fortran/trans-expr.c trunk/gcc/testsuite/ChangeLog That's great. I've tested it with the latest binary snapshot and it works very nicely. Thanks a lot for fixing this! Gavin Subject: Bug 37199 Author: domob Date: Thu Sep 11 19:13:59 2008 New Revision: 140296 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=140296 Log: 2008-09-08 Daniel Kraft <d@domob.eu> PR fortran/37199 * trans-expr.c (gfc_add_interface_mapping): Set new_sym->as. (gfc_map_intrinsic_function): Added checks against NULL bounds in array specs. 2008-09-08 Daniel Kraft <d@domob.eu> PR fortran/37199 * gfortran.dg/array_function_2.f90: New test. Added: branches/gcc-4_3-branch/gcc/testsuite/gfortran.dg/array_function_2.f90 Modified: branches/gcc-4_3-branch/gcc/fortran/ChangeLog branches/gcc-4_3-branch/gcc/fortran/trans-expr.c branches/gcc-4_3-branch/gcc/testsuite/ChangeLog Fixed on 4.3 branch. |