C-Fortran互操作代码中派生类型值意外变更问题排查
Fortran调用C库时派生类型tol意外变更的原因分析
问题场景
在以下调用Arb/Flint相关C库的Fortran代码中,派生类型tol的数值在执行facb_set_d(a, 0._c_double)后出现意外变更,程序输出显示tol的值被错误修改。
源代码
PROGRAM ComplexIntegral USE farblib IMPLICIT NONE TYPE(fmag_t) :: tol TYPE(facb_t) :: s, t, a, b INTEGER(c_long) :: prec, goal TYPE(facb_calc_integrate_opt_t) :: options TYPE(c_ptr) :: params CALL facb_calc_integrate_opt_init(options) prec = 64_c_long goal = prec params = c_null_ptr CALL facb_init(a) CALL facb_init(b) CALL facb_init(s) CALL facb_init(t) CALL fmag_init(tol) CALL fmag_set_ui_2exp_si(tol, 1_c_long, -prec) PRINT*, "Initial Value of tol:" CALL facb_print(tol) CALL facb_set_d(a, 0._c_double) PRINT*, "Intermediate Value of tol:" CALL facb_print(tol) CALL facb_set_d(b, 1._c_double) PRINT*, "Final Value of tol:" CALL facb_print(tol) CALL facb_calc_integrate(s, fatanderiv, params, a, b, goal, tol, options, prec) CALL facb_mul_2exp_si(s, s, 2_c_long) CALL facb_printf(s) CALL facb_clear(a) CALL facb_clear(b) CALL facb_clear(s) CALL facb_clear(t) CALL fmag_clear(tol) END PROGRAM ComplexIntegral
程序输出
Initial Value of tol: (536870912 * 2^-93) Intermediate Value of tol: (914731972 * 2^-116) Final Value of tol: (914731972 * 2^-116)
编译命令
ifort farblib.F90 farb.F90 -lflint -larb -lm -g ./a.out
可能的原因分析
错误使用打印函数导致内存越界
代码中调用facb_print(tol)打印tol变量,但tol的类型是fmag_t,而facb_print是专门用于打印facb_t类型变量的函数。传入错误类型会让函数按照facb_t的内存结构解析tol的内存,甚至可能在内部写入错误的内存区域,直接破坏tol的数值。正确做法是调用fmag_print来打印fmag_t类型变量。Fortran与C接口的内存布局不兼容
fmag_t和facb_t作为对应C库的派生类型,内存布局完全不同。将fmag_t类型的tol传给期望facb_t的函数时,函数会错误访问tol的内存空间,覆盖其内部数据,导致值异常变更。栈内存相邻变量被误修改
如果tol和a/b等变量在栈上相邻,facb_print的错误内存操作可能超出参数对象范围,修改栈上相邻的tol变量内存,导致其值被意外改变。
验证方案
将所有CALL facb_print(tol)替换为CALL fmag_print(tol),重新编译运行,即可避免错误的内存访问,tol的值将保持初始设置状态。
内容的提问来源于stack exchange,提问作者Akhil Akkapelli
相关产品推荐
相关产品推荐

