gfortranのバグ-コンパイルオプション -fbounds-check とIF文中の論理演算子の処理系依存挙動

2016/02/11

以下の、配列 a の添え字 b が有効範囲にない場合には処理をスキップすることを意図した条件分岐(複合条件文)を含むプログラム例を考えます。古いプログラムの保守でFORTRANを使わざるを得ないシチュエーションを想定し、古風な書き方をしています。ファイル名は gfortran_if_bug.for であると仮定します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
      implicit NONE
      
      integer a
      dimension a(3)
      integer b
      
      b = 0
      write(*,*) 'b=', b
      
      if(b .gt. 0 .and. a(b) .eq. a(b)) then
        write(*,*) 'evaluated'
        write(*,*) 'a(b)=', a(b)
      else
        write(*,*) 'not evaluated'
        write(*,*) 'a(b)=', a(b) ! may be overrun
      endif
      
      end

このように、IF文の中で .and. 論理演算子を使い(複合条件文)、配列の添字に変数(または関数)を用い、配列境界チェックを行うコンパイルオプション -fbounds-check が併用されると、結果が処理系依存になります。

g77の場合

※gcc version 3.4.5 (mingw-vista special r3)

コンパイラオプション -fbounds-check の指定有無を比べていますが、どちらも文字列 not evaluated がコンソールに表示されており、本来期待されるべき動作をしています。
-fbounds-check を指定しない場合は a(0) のゴミ値(この例では偶然ゼロですが)を出力。
指定するとオーバーランを検出して abort() していますが、検出場所は15行目に意図的に書いたWRITE文での添字指定となっています。

gfortranの場合

※gcc version 4.8.1 (MinGW本家)、gcc version 5.3.0 (x86_64-win32-seh-rev0, Built by MinGW-W64 project) とも同じ結果

コンパイラオプション -fbounds-check を指定しない場合はg77と同じ(C言語風の挙動)。
一方、指定したときに、文字列 not evaluated がコンソールに表示されていません。10行目すなわちIF文の中で配列の添字オーバーランが検出され、15行目まで実行されない。言い換えると、第一条件式が偽であるにもかかわらず、第二条件式が評価される(Visual Basic風の挙動)ように、スタンスが変わってしまっています。

すなわち、-fbounds-check を指定した場合、.and. 論理演算子は、配列境界チェックよりも優先順位が低くなっています。

これは、ちょっと、よろしくありません。コンパイルオプションの違いによってIF文の挙動がC言語風になるかVisual Basic風になるか変わるのは、とてもおかしなことです。
もし、IF文の中の添え字指定として、変数 b でなく何某かの関数 (function) の戻り値を用いている場合、-fbounds-check の有無によって当該の関数が呼び出されるか否かが変わり、その結果、当該の関数によって他箇所にも変化を生じさせることもあり、収拾がつきません。

10行目を、添え字を定数で指定

10
      if(b .gt. 0 .and. a(1) .eq. a(1)) then
に書き換えると、 -fbounds-check 有無にかかわらずg77と同じ(C言語風の挙動)です。でも、これでは何の役にも立ちません。

この処理系依存は、ものすごくわかりにくいバグを生む可能性が高く、危険ですらあります
結局、.and. 論理演算子を使わずにブロックIF文で分離して

  
      if(b .gt. 0) then
        if(a(b) .eq. a(b)) then
          ...
        endif
      endif
のように書くしかありません。

結論

こういう基本的な事がおかしいなんて、gfortran というコンパイラは生まれながらにその正当性をチェックされていないんだなー。もう誰も面倒見ないのでしょうし。人間が作るものだからミスがあって当然ですが、しかし、いくらなんでも gfortran のこの実装は、ちょっと、酷過ぎる。糞コンパイラだ!

個人的には、古い g77 の実装を支持します。欲しい機能が無くて色々と不便だけど、そのぶんよく枯れていて、安心して使えます。
科学技術計算を gfortran でやっている皆さん、IF文の中で配列添字に変数を使っていないか、今すぐチェック!


略歴


トップページ / 計算機関係の雑多なこと / gfortranのバグ-IF文中の論理演算子の処理系依存挙動
このサイトについて・著者連絡先