Ошибка отладки нарушения доступа: запись в 2071E05A0 вместо 3071E05A0

Окончательное редактирование:

Некоторые пользователи на форумах silverfrost очень помогли мне в упрощении кода и решении.

Проблема может быть воспроизведена с использованием следующего кода:

      PROGRAM ML14ERROR   
        INTEGER :: origzn, destzn
        INTEGER,PARAMETER :: MXZMA = 1713, LXTZN = 1714, MXAV = 182
        INTEGER,PARAMETER :: JTMPREL = 1003, av = 1
        REAL(KIND=2) :: RANDOM@
        REAL,dimension (1:mxav,lxtzn,lxtzn,JTMPREL:JTMPREL):: znzndaav

        DO origzn=1,lxtzn
          DO destzn=1,lxtzn
            znzndaav(av,origzn,destzn,JTMPREL) = RANDOM@()
          END DO
        END DO

        DO origzn=1,mxzma
          DO destzn=1,mxzma
            ! This is where the error occurs
            znzndaav(av,origzn,lxtzn,JTMPREL)=
     $         znzndaav(av,origzn,lxtzn,JTMPREL)+
     $         znzndaav(av,origzn,destzn,JTMPREL)

          ENDDO
        ENDDO

        WRITE(6,*)'No errors'
      END PROGRAM 

Проблема возникает только тогда, когда MXAV>182, что говорит о проблеме с памятью. Действительно, умножение размеров: 183 * 1714 * 1714 * 4 дает>2 ГБ, превышая размер стека.

Решением было бы использовать кучу следующим образом (Фортан 95):

PROGRAM ML14ERROR    
  INTEGER :: origzn, destzn
  INTEGER,PARAMETER :: MXZMA = 1713, LXTZN = 1714, MXAV = 191
  INTEGER,PARAMETER :: JTMPREL = 1003, av = 1
  REAL(KIND=2) :: RANDOM@
  REAL,allocatable :: znzndaav(:,:,:,:)

  ALLOCATE( znzndaav(1:mxav,lxtzn,lxtzn,JTMPREL:JTMPREL) )
  DO origzn=1,lxtzn
    DO destzn=1,lxtzn
      znzndaav(av,origzn,destzn,JTMPREL) = RANDOM@()
    END DO
  END DO

  DO origzn=1,mxzma
    DO destzn=1,mxzma
      ! This is where the error occurs
      znzndaav(av,origzn,lxtzn,JTMPREL)= &
  &         znzndaav(av,origzn,lxtzn,JTMPREL)+ &
  &         znzndaav(av,origzn,destzn,JTMPREL)

    ENDDO
  ENDDO
  DEALLOCATE(znzndaav)

  WRITE(6,*)'No errors'
END PROGRAM

Как только мы это сделаем, мы можем выделить более 2 ГБ, и массив будет работать нормально. Программе, из которой создан этот небольшой фрагмент кода, несколько лет, и мы только сейчас столкнулись с проблемой, потому что построенная нами модель во много раз больше, чем любая другая. Поскольку Fortran 77 не допускает использование массивов ALLOCATABLE, мы должны либо уменьшить использование стека, либо перенести код - либо искать другую оптимизацию.


Отредактировано, чтобы добавить:

Теперь я собрал репозиторий git, который содержит воспроизводимый код.


обзор

У меня есть программа, которая отлично работает при компиляции в 32-битной, но представляет ошибку доступа при компиляции и запуске в 64-битной.

Я использую компилятор Silverfrost Fortran, FTN95 v8.51, хотя эта проблема возникает при использовании v8.40 и v8.50.


Образец кода

! .\relocmon.inc
      INTEGER JTMPREL
      PARAMETER(JTMPREL=1003)
      REAL znda(lxtzn,JTMPREL:JTMPREL)
      REAL zndaav(1:mxav,lxtzn,JTMPREL:JTMPREL)      
      REAL,dimension (lxtzn,lxtzn,JTMPREL:JTMPREL) :: znznda
      REAL mlrlsum(lxtzn,lxtzn)

      REAL,dimension (1:mxav,lxtzn,lxtzn,JTMPREL:JTMPREL):: znzndaav

      COMMON /DDMON/ znda, znznda, mlrlsum,znzndaav, zndaav
! EOF .\relocmon.inc

! .\relocmon.inc with values
      INTEGER JTMPREL
      PARAMETER(JTMPREL=1003)
      REAL znda(1714,JTMPREL:JTMPREL)
      REAL zndaav(1:191,1714,JTMPREL:JTMPREL)      
      REAL,dimension (1714,1714,JTMPREL:JTMPREL) :: znznda
      REAL mlrlsum(1714,1714)

      REAL,dimension (1:191,1714,1714,JTMPREL:JTMPREL):: znzndaav

      COMMON /DDMON/ znda, znznda, mlrlsum,znzndaav, zndaav
! EOF .\relocmon.inc

! .\main.for
        INCLUDE 'relocmon.inc'

        REAL,save,dimension(lxtzn,lxtzn,mxav) :: ddfuncval

        DO origzn=1,mxzma
          IF( zonedef(origzn,JZUSE) )THEN
            DO destzn=1,mxzma
              IF (zonedef(destzn,JZUSE)) THEN
                znznda(origzn,destzn,JTMPREL)=znda(destzn,JTMPREL)*
     $                                       ddfuncval(origzn,destzn,av)            

               znznda(origzn,lxtzn,JTMPREL)=znznda(origzn,lxtzn,JTMPREL)
     $               +znznda(origzn,destzn,JTMPREL)

         znzndaav(av,origzn,destzn,JTMPREL)=zndaav(av,destzn,JTMPREL)*
     $                                    ddfuncval(origzn,destzn,av)           

         ! LINE 309 -- where error occurs
         znzndaav(av,origzn,lxtzn,JTMPREL)=
     $               znzndaav(av,origzn,lxtzn,JTMPREL)
     $             +znzndaav(av,origzn,destzn,JTMPREL)

              ENDIF
            ENDDO
          ENDIF
        ENDDO

! EOF .\main.for

NB функция zonedef просто проверяет, что зона действительна для расчета, который мы хотим провести. Эта функция возвращает logical,


отладка

Как я уже упоминал, 32-разрядная скомпилированная версия этой программы работает нормально. При попытке запустить 64-битную версию вывод первого цикла выглядит так:

от sdbg64.exe:

Error: Access Violation reading address
0x00000002071E05A0

main.for: 309

записать исключение в файл:

Access violation (c0000005) at address 43a1f4

Within file ml14.exe
in main in line 309, at address 2b84

RAX = 0000000000000001   RBX = 000000027fff704c   RCX = 000000000285e6b8   RDX = 00000002802296cc
RBP = 0000000000400000   RSI = 000000029ba3ad6c   RDI = 0000000307695374   RSP = 000000000285be70
R8  = 0000000307695374   R9  = 00000002ffff5040   R10 = 000000029ba3ad6c   R11 = 000000030731f0dc
R12 = 000000027fff5584   R13 = 00000002802296cc   R14 = 000000028169f3ec   R15 = 0000000281660928

43a1f4) addss       XMM11,[85b401b4++R14]

Для всего остального... пожалуйста, потерпите меня. Я ни в коем случае не обученный инженер-программист или фортран-разработчик, поэтому я пытаюсь устранить неполадки в темноте.

Значение для ZNZNDAAV(1,337,337,1003)2.241640, и это добавляется к ZNZNDAAV(1,337,1714,1003), Это соответствует регистру XMM11, как описано в выходных данных исключения. Это значение по адресу 000000029BA3BD60, Другое значение по адресу 00000003071E05A0,

IIUC, в relocmon.inc мы устанавливаем COMMON /DDMON/ содержать размерный массив znzndaavТаким образом, если бы программное обеспечение работало номинально, адрес рассматриваемой стоимости был бы в пределах /DDMON/ блок. Диапазон адресов для /DDMON/ является z'000000027FFF6040' - z'0000000307421150', Если моя логика верна, нарушение происходит за пределами этого блока.

Мне кажется, что программа пытается написать 00000002071E05A0 когда это следует использовать 00000003071E05A0,

Может ли кто-нибудь помочь мне определить, почему это так? Кажется, в этом есть что-то систематическое - может ли это быть простым совпадением?

0 ответов

Другие вопросы по тегам