如何调试 Fortran 代码中的意外跳转

How do I debug an unexpected jump in a Fortran code

我正在 ODE 求解器套件中实现事件检测。以下是我目前正在调试并注意到 st运行ge 行为的实现中的一段代码。一旦根查找例程 returns 成功找到根,第一个 if 块将被执行(ROOTFINDING_ERR == 0)——第 1 到 14 行——这是预期的行为。但是,一旦该块执行完毕,执行就会意外跳转到对应于 (ROOTFINDING_ERR == 0) 的 ELSE 块的最后一条语句——第 20 行——以及语句 EVENT_OUT(j) = 。错误的。在第 21 行执行 ENDIF 之前执行。

               1  IF (ROOTFINDING_ERR == 0) THEN
               2     IF ((ABS(EVENT_TIMES(1, j) - T_STAR) > &
               3          NEARBY_ROOTS_ABSTOL)  &
               4          .AND. (EVENT_ITER < EVENT_ITER_MAX)) THEN
               5        EVENT_TIMES(1, j) = T_STAR
               6        EVENT_TIMES(2, j) = DBLE(j)
               7        EVENT_TEST(j)     = .TRUE.
               8        EVENT_OUT(j)      = .TRUE.
               9     ELSE
              10        EVENT_TIMES(1, j) = T_STAR
              11        EVENT_TIMES(2, j) = DBLE(j)
              12        EVENT_TEST(j) = .FALSE.
              13        EVENT_OUT(j)  = .TRUE.
              14     ENDIF
              15  ELSE
              16     EVENT_TIMES(1, j) = T_STAR
              17     EVENT_TIMES(2, j) = DBLE(j)
              18     ! Dont test this event further
              19     EVENT_TEST(j)     = .FALSE.
              20     EVENT_OUT(j)      = .FALSE.
              21  ENDIF

我认为这与可执行文件上的一些内存 access/allocation 问题和 运行 DrMemory(类似 Valgrind 的工具)有关。 DrMemory 确实指定一些读取未初始化,我将进一步研究。

我想知道从这里到哪里去。我确实使用 gdb 逐步执行了代码,但在隔离 DrMemory 抱怨的 "uninitialized read" 时遇到了一些困难。我打开 -Wall, -Wextra, -fbounds-check 等来确定编译器是否能够捕获它。我也尝试用 x32dbg 反汇编 exe,但是调试符号没有被读取,因为 x32dbg 不支持 DWARF 符号。

从显示的代码中我看不出错误的原因。因此我推测错误是由我们看不到的东西引起的。

现在,下面的内容并没有解决这个难题,而是试图绕过它...

...显示的代码可以简化为

EVENT_TIMES(1, j) = T_STAR
EVENT_TIMES(2, j) = DBLE(j)
IF (ROOTFINDING_ERR == 0) THEN
   EVENT_OUT(j)      = .TRUE.
   IF ((ABS(EVENT_TIMES(1, j) - T_STAR) > &
        NEARBY_ROOTS_ABSTOL)  &
        .AND. (EVENT_ITER < EVENT_ITER_MAX)) THEN
      EVENT_TEST(j)     = .TRUE.
   ELSE
      EVENT_TEST(j) = .FALSE.
   ENDIF
ELSE
   ! Dont test this event further
   EVENT_TEST(j)     = .FALSE.
   EVENT_OUT(j)      = .FALSE.
ENDIF

...甚至更进一步...

EVENT_TIMES(1, j) = T_STAR
EVENT_TIMES(2, j) = DBLE(j)
EVENT_OUT(j) = ROOTFINDING_ERR == 0
EVENT_TEST(j)     = ((ROOTFINDING_ERR == 0) .AND. &
                    (ABS(EVENT_TIMES(1, j) - T_STAR) > &
                    NEARBY_ROOTS_ABSTOL)  &
                    .AND. (EVENT_ITER < EVENT_ITER_MAX))