ヒープ破損の検出

ヒープ破損の検出に役立つ Micro Focus のツールについて説明します。

Micro Focus 製品を使用してメモリを割り当てるときは、割り当てられたメモリ ブロックの前後にガード バイトと呼ばれる追加のバイトが割り当てられます。意図しない上書きを検出できるように、これらのガード バイトには既知の値が設定されています。

CBL_MEM_VALIDATE API (または同一の API PLI_MEM_VALIDATE) を呼び出すことで、ヒープ メモリの破損をチェックできます。現在割り当てられているメモリとフリー チェーン (該当する場合) の両方がチェックされ、上書きされているガード バイトがないかどうかが確認されます。

オプションで、次の COBOL ランタイム チューナーを使用できます。

重要: オンにするチェックの数が増えるほど、パフォーマンスへの影響も大きくなります。Open PL/I では、文字列連結の構築などに動的メモリを大量に使用するため、これらのすべてのチェックを常に実行すると負荷が高くなる可能性があります。

さらに、Open PL/I では各メモリ割り当てにタイプが割り当てられます。割り当てられたタイプを使用して、どのタイプのメモリが破損しているかを判断できます。Open PL/I ランタイム システムによって割り当てられるメモリのタイプは 65350 から 65399 までです。最も一般的なタイプは 65398 です(65350 から 65397 までは使用されません)。

ヒープ破損が発生すると、次のように報告されます。

デフォルト
デフォルトでは、COBOL memory_strategy ランタイム チューナーは設定されず、Enterprise Server で実行されるプログラムに対して限定的なヒープ破損検出が有効になります。ただし、Open PL/I では常に CBL_MEM_VALIDATE API をトリガーし、その結果を PLIDUMP の残りの部分を処理する前に報告するため、PLIDUMP のレポートの先頭でヒープ破損の発生が報告されます。次に、ヒープ破損が報告された PLIDUMP の先頭のスニペットを示します。
Memory Strategy: 00000001
Corruption at: 0E2A776C Flags:0000000F Type: 0 Size: 0

このメッセージは、破損したメモリがアドレス 0E2A776C (32 ビット プログラム) にあり、メモリに割り当てられたタイプが 0 であること、つまり破損したメモリは PL/I によって割り当てられたものでないことを示しています。Flags の値は、検出されたメモリ破損のタイプ (割り当てられたタイプではなく) や検出元などを示します。詳細については、「CBL_MEM_VALIDATE」を参照してください。

COBOL ランタイム システム (RTS) のエラーとイベント
JCL ジョブ ログでは、メモリ破損は COBOL RTS 252 エラーとして報告されます。

CTF トレースでは、メモリ破損は COBOL RTS 249 および 252 イベントとして報告されます。この情報は、破損のアドレス、タイプ、サイズなどを示す PLIDUMP で表示される内容と似ています。次に、CTF トレースの RTS 249 イベントの例を示します。

21:59:33.009 5892 MF.RTS 249 3 : 0X14025F10 65398 1 0X140362A2

このメッセージには、いくつかの役立つ情報が含まれています。

65398 破損したメモリは PL/I によって割り当てられたものです。原因として、CONTROLLED 変数または BASED 変数、あるいは中間結果を処理するために PL/I によって作成された一時変数が考えられます。
1 問題はユーザー データの不足です。割り当てられたブロックの終わりを超えて書き込みが行われたことを示しています。
0X140362A2 書き込まれたチェック バイトのアドレスです。

%ProgramFiles(x86)%\Micro Focus\Enterprise Developer\etc\mftrace\annotations(Windows) または /etc/mftrace/annotations(UNIX) ディレクトリにある mf.rts.xml で、249 イベントに関する次の追加情報が提供されます。

      <Event Id="249" Description="Memory Stomp">
        <Arguments>
          <Argument Index="0" Description="Data Address" />
          <Argument Index="1" Description="Memory Type" />
          <Argument Index="2" Description="">
            <ArgumentCase Index="2" Value="0" Description="Run-In (Header)"/>
            <ArgumentCase Index="2" Value="1" Description="Run-Out (User Data)"/>
            <ArgumentCase Index="2" Value="2" Description="Bad Header"/>
            <ArgumentCase Index="2" Value="3" Description="Freed Overwrite"/>
            <ArgumentCase Index="2" Value="4" Description="Bad Header User"/>
            <ArgumentCase Index="2" Value="5" Description="Failed OS Check"/>
            <ArgumentCase Index="2" Value="6" Description="Run-In (User Data)"/>
            <ArgumentCase Index="2" Value="7" Description="Bad Track Data"/>
            <ArgumentCase Index="2" Value="8" Description="Bad Link"/>
          </Argument>
          <Argument Index="3" Description="">
            <ArgumentCase Index="2" Value="0" Description="Check Bytes Address"/>
            <ArgumentCase Index="2" Value="1" Description="Check Bytes Address"/>
            <ArgumentCase Index="2" Value="2" Description="Header Address"/>
            <ArgumentCase Index="2" Value="3" Description="Overwrite Address"/>
            <ArgumentCase Index="2" Value="6" Description="Check Bytes Address"/>
            <ArgumentCase Index="2" Value="7" Description="Track Data Address"/>
            <ArgumentCase Index="2" Value="8" Description="Header Address"/>
          </Argument>
        </Arguments>
      </Event>