我最近偶然发现了我的代码中的奇怪行为,当修改多态用户定义类型的数据成员时,其他数据成员的值发生了变化。我尝试应用Valgrind解开看起来与内存相关的错误,并发现了几个错误:Conditional jump or move depends on uninitialized value(s)
经过进一步调查,多态数据成员返回此错误,即使它们之前已经显式初始化。当我在分配的数组var(1)
的开头引用索引,或者用var(:)
隐式索引数组时,没有问题,但显式引用数组末尾附近的元素会返回Valgrind错误。例如:
module particles
implicit none
private
public :: particleArray,initParticles,&
FULLY_KINETIC,DRIFT_KINETIC
integer,parameter :: &
FULLY_KINETIC=1,&
DRIFT_KINETIC=2
type particle
real :: x ! position
end type particle
type, extends (particle) :: particle_dk
real :: vpara ! parallel velocity
end type particle_dk
type, extends (particle) :: particle_fk
real :: vx,vy ! x,y velocity
end type particle_fk
type particleArray
private
class(particle),dimension(:),allocatable :: p
end type
contains
subroutine initParticles(pArray,iParticleType)
type(particleArray),intent(out),target :: pArray
integer,intent(in) :: iParticleType ! flag for FK vs. DK particles
integer :: i,nparticles
nparticles=10
select case (iParticleType)
case (FULLY_KINETIC)
write(*,*)' Particles are FULLY KINETIC.'
allocate(particle_fk::pArray%p(nparticles))
case (DRIFT_KINETIC)
write(*,*)' Particles are DRIFT KINETIC.'
allocate(particle_dk::pArray%p(nparticles))
case default
write(*,*)'ERROR: Requested iParticleType not found.'
stop
end select
! initialize ALL particle array values
pArray%p(:)%x = 0.0
select type (pa => pArray%p)
class is (particle_dk)
pa(:)%vpara = 0.0
class is (particle_fk)
pa(:)%vx = 0.0
pa(:)%vy = 0.0
end select
! modify initialized value
! low indices are fine
pArray%p(1:4)%x = max(pArray%p(1:4)%x,1.0e-6)
! so is this!
pArray%p(:)%x = max(pArray%p(:)%x,1.0e-6)
! ERROR HERE
! but explicit indices near end of allocated array cause
! 'uninitialized' error in valgrind
pArray%p(nparticles)%x = max(pArray%p(nparticles)%x,1.0e-6)
end subroutine initParticles
end module particles
program test
use particles
type(particleArray) :: ions_dk,ions_fk
call initParticles(ions_dk,DRIFT_KINETIC)
call initParticles(ions_fk,FULLY_KINETIC)
end program test
Valgrind回归......
oghma@laptop:~/memory_bug> valgrind ./test
==16108== Memcheck, a memory error detector
==16108== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==16108== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==16108== Command: ./test
==16108==
--16108-- run: /usr/bin/dsymutil "./test"
Particles are DRIFT KINETIC.
==16108== Conditional jump or move depends on uninitialised value(s)
==16108== at 0x100001B8B: __particles_MOD_initparticles (particles.F90:69)
==16108== by 0x100000FE9: MAIN__ (main.F90:6)
==16108== by 0x100001035: main (main.F90:2)
==16108==
Particles are FULLY KINETIC.
==16108== Conditional jump or move depends on uninitialised value(s)
==16108== at 0x100001B8B: __particles_MOD_initparticles (particles.F90:69)
==16108== by 0x100000FFC: MAIN__ (main.F90:7)
==16108== by 0x100001035: main (main.F90:2)
==16108==
==16108==
==16108== HEAP SUMMARY:
==16108== in use at exit: 22,223 bytes in 191 blocks
==16108== total heap usage: 280 allocs, 89 frees, 34,316 bytes allocated
==16108==
==16108== LEAK SUMMARY:
==16108== definitely lost: 0 bytes in 0 blocks
==16108== indirectly lost: 0 bytes in 0 blocks
==16108== possibly lost: 2,064 bytes in 1 blocks
==16108== still reachable: 200 bytes in 2 blocks
==16108== suppressed: 19,959 bytes in 188 blocks
==16108== Rerun with --leak-check=full to see details of leaked memory
==16108==
==16108== For counts of detected and suppressed errors, rerun with: -v
==16108== Use --track-origins=yes to see where uninitialised values come from
==16108== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
在pArray%p
分配nparticles
时,以及nparticles
引用后,每个项目的预期大小似乎存在某种不匹配。我allocate(particle_fk::pArray%p(nparticles))
形式的分配语句基于IBM compiler documentation,因为我无法找到gfortran,我用来编译。我是否错误地分配/引用,或者这是否是在GCC中未正确实现的Fortran 2003功能?
答案 0 :(得分:0)
我尝试了一个更简单的OP程序版本,它有不同的x等初始值(1,2,3,4)。
module particle_mod
implicit none
type particle
real :: x
endtype
type, extends(particle) :: particle_1
real :: vp
endtype
type, extends(particle) :: particle_2
real :: vx,vy
endtype
type particleArray
class(particle), allocatable :: p(:)
endtype
contains
subroutine initParticles( pArray, itype )
type(particleArray), intent(out) :: pArray
integer, intent(in) :: itype
integer :: nparticles
character(20) :: fmt
nparticles = 6
select case ( itype )
case ( 1 )
print "(/,a)", "allocating type 1"
allocate( particle_1 :: pArray % p( nparticles ) )
case ( 2 )
print "(/,a)", "allocating type 2"
allocate( particle_2 :: pArray % p( nparticles ) )
end select
! initialize all values
pArray % p(:) % x = 1.0
select type ( pa => pArray % p )
class is ( particle_1 )
pa(:) % vp = 2.0
class is ( particle_2 )
pa(:) % vx = 3.0
pa(:) % vy = 4.0
end select
! print the values
fmt = "(a, *(f5.1, x))"
print fmt, "x = ", pArray % p(:) % x
select type ( pa => pArray % p )
class is ( particle_1 )
print fmt, "type1 : x = ", pa(:) % x
print fmt, "type1 : vp = ", pa(:) % vp
class is ( particle_2 )
print fmt, "type2 : x = ", pa(:) % x
print fmt, "type2 : vx = ", pa(:) % vx
print fmt, "type2 : vy = ", pa(:) % vy
end select
end subroutine
end module
program test
use particle_mod
implicit none
type(particleArray) :: ions_1, ions_2
call initParticles( ions_1, 1 )
call initParticles( ions_2, 2 )
end program
然后,如果使用gfortran-6.1编译该程序,则会得到以下结果:
allocating type 1
x = 1.0 2.0 1.0 2.0 1.0 2.0
type1 : x = 1.0 1.0 1.0 0.0 0.0 0.0
type1 : vp = 2.0 2.0 2.0 2.0 2.0 2.0
allocating type 2
x = 1.0 3.0 4.0 1.0 3.0 4.0
type2 : x = 1.0 1.0 0.0 0.0 0.0 0.0
type2 : vx = 3.0 3.0 3.0 3.0 3.0 3.0
type2 : vy = 4.0 4.0 4.0 4.0 4.0 4.0
但x(:)的输出似乎很奇怪......(我希望它能给1.0 1.0 ... 1.0
)。我现在无法访问ifort,因此使用ifort尝试此程序可能很有用。