Почему нет ошибки времени выполнения при четкой записи за границы массива? - PullRequest
5 голосов
/ 23 марта 2012

У меня есть программа, которая назначает массив за его пределами, и я ожидал, что будет выдана ошибка во время выполнения. Тем не менее, никаких ошибок не возникает, и программа переходит к записи в необъявленную память. Есть ли какая-то опция компилятора, чтобы защититься от этого? С показанным дампом памяти ясно, что это превышение границ реально. Есть ли способ объявить переменные или спецификации аргумента, чтобы поймать это? Очевидно, что это очевидный случай, но когда ему поручено поддерживать тысячи строк кода, производного от F77, не всегда ясно (для меня), может ли это происходить.

PROGRAM TEST_CODE
IMPLICIT NONE

INTEGER*4 :: R(5)           ! Array of 5

    CALL R_TEST(R, 10)

END PROGRAM

SUBROUTINE R_TEST(R, J)
IMPLICIT NONE

INTEGER*4, INTENT(INOUT) :: R(1)    ! Dummy is array of 1
INTEGER*4, INTENT(IN) :: J
INTEGER*4 :: K

DO K=J-5,J+5            ! K=5..15
    R(K) = K            ! No Runtime Error
END DO

END SUBROUTINE

Компилятор - Intel Fortran 2011 XE, и да, я использую спецификацию байта INTEGER*4, потому что я знаю, что получаю с ним.

Вот параметры компилятора для проверки во время выполнения. Compiler Options

imageR variable">

Ответы [ 2 ]

4 голосов
/ 27 марта 2012

Компилятор intel отлично справляется с проверкой границ для указателя и выделяемых массивов. Если вы немного измените свой код (ниже) и скомпилируете что-то вроде:

$ ifort -O0 -debug -traceback -check -ftrapuv TEST_CODE.f90

вы получите ошибку во время выполнения. Но для массивов предполагаемого размера компилятор Intel не может проверить границы. Особенно для кодов F77 с неявной типизацией и т. Д. Будет нелегко обнаружить утечки памяти. Еще одна крошечная вещь: в Фортране ваша программа должна делать что-то значимое; в противном случае компилятор пропустит ваш код, потому что он просто ничего не делает! Вот почему я добавил отпечаток в конце.

Существует небольшая проблема с R (:), которая заключается в том, что компилятор не может предположить, что он непрерывен в памяти; следовательно, он не может оптимизировать компилятор. Тогда было бы лучше использовать размещаемые массивы или использовать непрерывный атрибут (стандарт F2008).

PROGRAM TEST_CODE
IMPLICIT NONE

INTEGER*4 :: R(5)           ! Array of 5

    CALL R_TEST(R, 10)
    print *,R

END PROGRAM

SUBROUTINE R_TEST(R, J)
IMPLICIT NONE

INTEGER*4, INTENT(INOUT) :: R(:)    ! Dummy is array of 1
INTEGER*4, INTENT(IN) :: J
INTEGER*4 :: K

DO K=J-5,J+5            ! K=5..15
    R(K) = K            ! No Runtime Error
END DO

END SUBROUTINE
3 голосов
/ 23 марта 2012

Интересно.gfortran 4.6 находит ошибку индекса времени выполнения:

At line 18 of file test_code.f90
Fortran runtime error: Index '5' of dimension 1 of array 'r' above upper bound of 1 

, а ifort XE 12.1.1.246 - нет.

РЕДАКТИРОВАТЬ: вот ответ из документации компилятора Intel: «Для массивов, которые являются фиктивными аргументами, проверяется только нижняя граница для измерения, верхняя граница которого указана как * или где верхняя и нижняя границы являютсяоба 1. "И когда объявление изменяется на R (2), ifort также обнаруживает ошибку индекса.

Причина этого в том, что во многих старых кодах значение «1» использовалось для размера массива фиктивного аргумента, чтобы указатьнеизвестный размер.Это работает, если вы просто рассматриваете аргумент как адрес, но, конечно, делаете невозможной любую проверку нижнего индекса, потому что компилятор не знает размер фиктивного аргумента.Эта техника не должна использоваться в новом коде.Fortran 90 предоставляет лучшие варианты, например, массивы предполагаемой формы (объявление двоеточия).

Таким образом, ответ на вопрос «не всегда ясно (для меня), может ли это происходить», т. Е. Когда ваш устаревший код не 't проверяется ifort - ищет аргументы процедуры, объявленные как (1) или (*) или одинаковые для одного или нескольких измерений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...