現場のエンジニアへ:PL/Iの「ADDR」は諸刃の剣。ポインタ操作の深淵を覗く
現場で長年PL/Iコードを眺めていると、時折「なぜこんな書き方をしてしまったのか」と頭を抱えたくなるコードに出くわすことがある。特に、`ADDR`組み込み関数を用いたポインタ操作は、その最たるものだ。
PL/Iには、C言語のような厳密な「予約語」という概念が極めて希薄だ。変数名に `IF` や `THEN` といった名前を付けてもコンパイラは文脈で判断してくれる。この言語の柔軟性は魅力だが、裏を返せば、一歩間違えればコンパイラが警告すら出さずにメモリを破壊する「地雷」を埋め込むことにも繋がる。
今日は、そんなポインタ操作の危険性と、現場で生き残るためのデバッグの極意を伝授しよう。
—
ADDR組み込み関数の「内側」で起きていること
`ADDR`関数は、変数のストレージ上の先頭アドレスを返す。単純にアドレスを得るだけなら問題はないが、そのポインタを使って「領域外」へアクセスし始めた瞬間、悲劇は始まる。
メインフレームのバッチ処理において、`ADDR`によるポインタ操作が最も威力を発揮(そして悪用)するのは、可変長レコードの解析や、VSAMファイルのレコード構造を動的にマップする際だ。
/i
/ ポインタ操作を用いたVSAMレコードの動的マッピング例 /
DCL VSAM_BUFFER CHAR(4096) BASED(PTR_VAR);
DCL PTR_VAR PTR;
DCL ADDR_VAL PTR;
/ レコードの先頭アドレスを取得 /
ADDR_VAL = ADDR(VSAM_BUFFER);
/ 危険なポインタ演算のシミュレーション /
/ 構造体のサイズを考慮せず、オフセットを直接加算する行為は禁忌 /
PTR_VAR = ADDR_VAL + 1024;
/ この時点でPTR_VARが指し示す先は、本来のデータ領域の外かもしれない /
/ 意図せぬメモリ書き込みが発生すると、ABEND S0C4が待っている /
なぜメモリ破壊は防げないのか
PL/Iのコンパイラは、`BASED`変数を使う際、その変数が指す領域の妥当性を完全にはチェックしない。これは、コンパイラが「プログラマは今、何をしようとしているか完全に理解しているはずだ」という性善説に基づいているからだ。
特に、`ON-UNIT`(条件制御)で `ON ANYCONDITION` を仕掛けてデバッグしようとする若手もいるが、メモリ破壊が起きた時点ですでにスタックや制御ブロックが汚染されている場合、ハンドラが起動する前にシステムがフリーズすることもある。
実践:安全なポインタ操作のためのコーディング標準
もし実務でポインタ演算を避けられない場合(レガシーな共通モジュールなど)、以下のルールを徹底してほしい。
1. `DEFINED` 属性の活用: `BASED`ポインタで無理やりメモリをオフセットするよりも、`DEFINED`(位置付け)を使って構造体同士を重ねる方が、コンパイラによる境界チェックが効きやすい。
2. `OFFSET`と`POINTER`の使い分け: メインフレームの31ビット/64ビットアドレッシングを意識し、`POINTER`型を正しく定義すること。
3. 境界チェックの意識: 常に「今、自分はどの構造体のどのメンバーを指しているか」をコメントに残すこと。
/i
/ 安全なマッピングの実践例 /
DCL 1 HEADER_REC BASED(PTR_H),
2 RECTYPE CHAR(4),
2 DATA_LEN BIN FIXED(15);
DCL 1 BODY_REC BASED(PTR_B),
2 FIELD_A CHAR(10),
2 FIELD_B CHAR(20);
/ ADDRで取得したアドレスを明示的に構造体にキャストする /
PTR_H = ADDR(RAW_BUFFER);
/ ヘッダの情報を元に、ボディのアドレスを計算する(安全なロジック) /
PTR_B = ADDR(RAW_BUFFER) + HEADER_REC.DATA_LEN;
—
デバッグのコツ:ABEND S0C4を恐れるな
もし本番稼働中に `S0C4`(ストレージ保護例外)が出たら、まずは「どこで書き込みが起きたか」ではなく、「どのポインタが壊れたか」を疑え。
- ダンプの活用: `SYSUDUMP`を出力させ、該当するポインタ変数の値が、ベースとなるストレージ範囲内にあるか確認する。
- CEEHDLRの利用: `ON-UNIT`よりも強力な `Language Environment (LE)` のエラーハンドリングライブラリを使い、例外発生時のスタックトレースを詳細に追跡する。
最後に:諸君へのアドバイス
PL/Iという言語は、古臭いようでいて、実はハードウェアに近い場所でギリギリの最適化を追求できる、極めてプロフェッショナルなツールだ。ポインタ操作は強力だが、その分、バグが混入した際の代償は大きい。
「動いたからOK」ではなく、「なぜそのアドレスで正しいと言えるのか」を数式のように説明できるコードを書くこと。それが、次の大規模改修でも生き残る、真のメインフレームエンジニアの流儀だ。
何か詰まったら、いつでも相談してくれ。バッチのログは、常に真実を語っているからな。
