为什么valgrind在我的多态类型中报告未初始化的值?

时间:2016-10-28 02:29:05

标签: arrays memory fortran polymorphism gfortran

我最近偶然发现了我的代码中的奇怪行为,当修改多态用户定义类型的数据成员时,其他数据成员的值发生了变化。我尝试应用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功能?

1 个答案:

答案 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尝试此程序可能很有用。