Почему ошибка сегментации возникает в fortran при вызове подпрограммы, постепенно вложенной в две функции с двойной точностью?

#fortran #gfortran

#fortran #gfortran

Вопрос:

Я пытаюсь вызвать подпрограмму SPLEV библиотеки FITPACK с помощью двух функций (‘wer’ и ‘qwe’), вложенных одна в другую (код приведен ниже).

Следующее сообщение появляется при выполнении скомпилированной программы:

QWE

Программа получила сигнал SIGSEGV: ошибка сегментации — недопустимая ссылка на память.

Обратная трассировка для этой ошибки:

0 0x7F3EE4BF3E08

1 0x7F3EE4BF2F90

2 0x7F3EE453A4AF

3 0x4041B6 в splev_

4 0x400BD0 в значении.3386 при pr.f90:?

5 0x400A6B в MAIN__ по адресу pr.f90:?

Ошибка сегментирования (сделан дамп памяти)

Если я скомпилирую свою программу с флагами -g -fbacktrace -fsanitize=address,zero,undefined , появится следующее выходное сообщение:

QWE

0.37051690837706980

Программа получила сигнал SIGSEGV: ошибка сегментации — недопустимая ссылка на память.

Обратная трассировка для этой ошибки:

0 0x7FAB5F45CE08

1 0x7FAB5F45BF90

2 0x7FAB5EDA34AF

3 0x4075F0 в splev_ в splev.f:73 (дискриминатор 2)

4 0x400DDE в значении.3386 на pr.f90:87

5 0x400FFA в qwe.3406 на pr.f90:43

6 0x400F88 в версии 3403 на pr.f90:48

7 0x400D08 в MAIN__ на стр.f90:38

Ошибка сегментирования (сделан дамп памяти)

Если я скомпилирую свою программу с флагами -g -fbacktrace -Wall -fcheck=all , появится следующее выходное сообщение:

QWE

Программа получила сигнал SIGSEGV: ошибка сегментации — недопустимая ссылка на память.

Обратная трассировка для этой ошибки:

0 0x7F2BE6F0FE08

1 0x7F2BE6F0EF90

2 0x7F2BE68564AF

3 0x4075F0 в splev_ в splev.f:73 (дискриминатор 2)

4 0x400DDE в значении.3386 на pr.f90:87

5 0x400C46 в MAIN__ на стр.f90:35

Ошибка сегментирования (сделан дамп памяти)

Если я скомпилирую свою программу с флагами -g -fbacktrace -fsanitize=address , появится следующее выходное сообщение:

QWE

ASAN:SIGSEGV

=================================================================

==4796==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000408f67 bp 0x7ffe7a134440 sp 0x7ffe7a1341e0 T0)

0 0x408f66 in splev_ /home/yurchvlad/Science/Coll_Int/F90/f90DP/1/splev.f:73

1 0x40145d in value.3386 (/home/yurchvlad/Science/Coll_Int/F90/f90DP/1/curfit 0x40145d)

2 0x4011a3 in intcoll /home/yurchvlad/Science/Coll_Int/F90/f90DP/1/pr.f90:35

3 0x401849 in main /home/yurchvlad/Science/Coll_Int/F90/f90DP/1/pr.f90:2

4 0x7fcad9b3282f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6 0x2082f)

5 0x400d38 in _start (/home/yurchvlad/Science/Coll_Int/F90/f90DP/1/curfit 0x400d38)

AddressSanitizer can not provide additional info.

SUMMARY: AddressSanitizer: SEGV /home/yurchvlad/Science/Coll_Int/F90/f90DP/1/splev.f:73 splev_

==4796==ABORTING

Firstly I will show the code and then I will give some information about subroutines CURFIT and SPLEV of library FITPACK which are playing there a principal role.

Here is my code. This is just a test program, i.e. it is not confusion, that I interpolate there array of values of analytical function.

 PROGRAM IntColl
    USE Constants
    IMPLICIT NONE

    INTEGER  :: i, nen                    ! i = counter
                                          ! nen, nmn, ne is sirvice variables, which
                                          ! appear on exit of CURFIT and needed on entry
                                          ! of SPLEV and SPLINT

    REAL(DP) :: foo
    REAL(DP) :: MOM1                      ! dimensionless neutrino momentum

    REAL(DP) :: dmg ( 1 : 2 * NG)         ! dimensionless momentum grid
    REAL(DP) :: endf( 1 : 2 * NG)         ! electron neutrino     distribution function
                                          ! muon     neutrino     distribution function
                                          ! electron and positron distribution function

    REAL(DP) :: ten ( 1 : 2 * NG   k   1) ! service arrays:
                                          ! ten is array arising on exit of working of CURFIT
                                          ! and contain knots of the spline (for endf, mndf and edf correspondingly).
    REAL(DP) :: cen ( 1 : 2 * NG   k   1) ! needed on entry of SPLEV and SPLINT
                                          ! cen appear on exit of CURFIT, contain coefficients of spline
                                          ! (for endf, mndf and edf correspondingly) and needed on entry of SPLEV and SPLINT.
    REAL(DP) :: w   ( 1 : 2 * NG   k   1) ! w is array of weights for points on entry of CURFIT.

    DO i = 1, 2 * NG
        dmg(i)  = i / 10.D 00             ! filling arrays to give their
        endf(i) = eq_nu_di_fu(dmg(i))     ! on entry into subroutine
        w(i)    = 1.d 00                  ! CURFIT
    END DO

    MOM1 = .53D 00
    PRINT *, 'QWE'
    CALL spline(dmg, endf, nen, ten, cen)
    foo  = value(MOM1, ten, nen, cen)
    PRINT *, foo

    PRINT *, wer(MOM1)
CONTAINS

REAL(DP) FUNCTION qwe(q)           ! qwe and wer is "wrappers" for using
    REAL(DP) :: q                  ! of subroutines spline > curfit
    qwe = value(q, ten, nen, cen)  ! in main program
END FUNCTION qwe

REAL(DP) FUNCTION wer(q)
    REAL(DP) :: q
    wer = qwe(q)
END FUNCTION wer

SUBROUTINE spline(x, y, n, t, c)  ! spline is "hand-made wrapper" for 
    IMPLICIT NONE                 ! more convenient using of subroutine
                                  ! CURFIT in main program
    INTEGER             :: m, nest, n, lwrk, ier
    INTEGER,  PARAMETER :: iopt = 0
    INTEGER             :: iwrk( 1 : 10 * NG )

    REAL(DP)            :: xb, xe, fp
    REAL(DP)            :: wrk( 1 : 2 * NG * (k   1)   (2 * NG   k   1) * (7   3 * k) )
    REAL(DP)            :: x( 1 : 2 * NG), y(1: 2 * NG )
    REAL(DP)            :: t( 1 : 2 * NG   k   1 )
    REAL(DP)            :: c( 1 : 2 * NG   k   1 )

    xb = 0.d 00
    xe = x(2 * NG)
    m  = 2 * NG
    nest = m   k   1
    lwrk = 2 * NG * (k   1)   nest * (7   3 * k)

    CALL curfit(iopt, m, x, y, w, xb, xe, k, s, nest, n, t, c, fp, wrk, lwrk, iwrk, ier)

END SUBROUTINE spline

REAL(DP) FUNCTION value(q, t, n, c) ! value is "hand-made wrapper" for 
    IMPLICIT NONE                   ! more convenient using of subroutine
                                    ! SPLEV in main program
    INTEGER            :: n, ier    ! SPLEV should work only after
    INTEGER, PARAMETER :: m = 1     ! CURFIT edned its working

    REAL(DP)           :: q
    REAL(DP)           :: t( 1 : 2 * NG   k   1 )
    REAL(DP)           :: c( 1 : 2 * NG   k   1 )
    REAL(DP)           :: ddmg(1), sddmg(1)

    ddmg(1) = q

    CALL splev(t, n, c, k, ddmg, sddmg, m, ier)

    value = sddmg(1)

END FUNCTION value

REAL(DP) FUNCTION eq_nu_di_fu(y)     ! eq_nu_di_fy givev values for array
    IMPLICIT NONE                    ! to interpolate
    REAL(DP) :: y
    eq_nu_di_fu = 1 / (EXP(y)   1)
END FUNCTION eq_nu_di_fu

END PROGRAM IntColl
  

Константы модуля есть:

 MODULE CONSTANTS
    INTEGER, PARAMETER  :: DP = SELECTED_REAL_KIND(15, 307)
    INTEGER, PARAMETER  :: NG = 200                   ! NUMBER OF KNOTS OF GRID
    INTEGER , PARAMETER :: K  = 3                     ! THE ORDER OF SPLINE
    REAL(DP), PARAMETER :: S  = 0.D 00                ! CUBIC SPLINE SMOOTHING FACTOR
END MODULE
  

Теперь подпрограммы CURFIT и SPLEV, появляющиеся в приведенном выше коде со всеми их зависимостями, находятся в следующих источниках:

https://github.com/jbaayen/fitpackpp/tree/master/fitpack

где эти подпрограммы имеют двойную точность

и

http://www.netlib.org/dierckx/

где эти подпрограммы имеют одинарную точность.

Очень важно упомянуть, что с одинарной точностью вышеуказанная схема работает!

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

Что еще я наблюдал:

  1. прямое использование значения ФУНКЦИИ работает.

  2. Если строка PRINT *, ‘QWE’ основной программы прокомментирована, значение ‘foo’ также не печатается.

Комментарии:

1. Используйте проверки компилятора для выявления ошибок. Вы можете найти многие сами. Попробуйте: gfortran -g -fbacktrace -Wall -fcheck=all а также gfortran -g -fbacktrace -fsanitize=address,zero,undefined . Скомпилируйте свой код с этими параметрами, повторно запустите его и сообщите о результатах.

2. @Vladimir F -g -fbacktrace -Wall -fcheck=all возвращает fpcurf.f:186:35: if(fpold-fp.gt.acc) npl1 = rn*fpms/(fpold-fp) 1 Warning: Possible change of value in conversion from REAL(8) to INTEGER(4) at (1) [-Wconversion] и -g -fbacktrace -fsanitize=address,zero,undefined возвращает gfortran: error: unrecognized argument to -fsanitize= option: ‘zero’

3. Что произойдет, если вы запустите программу, скомпилированную с этими флагами?

4. @Ian Bush если я запускаю программу, скомпилированную с этими флагами, возвращается тот же результат

5. Я серьезно сомневаюсь, что результат был точно одинаковым, в обратном пути должны быть, по крайней мере, номера строк. Попробуйте удалить «ноль» из флага очистки. При необходимости удалите также «неопределенный» и перезапустите.