スタックの破損はさまざまな理由で発生する可能性があります。それらが発生する理由と仕組みを理解するには、z/OS と移行先の分散プラットフォームの違いを理解する必要があります。
パラメーターの受け渡し:z/OS と Open PL/I
z/OS では、パラメーターは明確に定義された規則に従って渡されます。長年にわたり、熟練のプログラマーがこの規則に完全に依存するコードを記述してきました。つまり、このコードは変更を加えなければ Open PL/I などの分散環境では実行できません。
- z/OS
- z/OS コンパイラは、使用される言語に関係なく、CALL または関数の呼び出しを生成するときに標準の呼び出し規則を使用します。この呼び出し規則の一部であるメカニズムの 1 つは、呼び出し先のプログラムまたは関数に必要なパラメーターのアドレスとパラメーターの説明を含むメモリ位置を指すように
R1 (レジスタ 1) を設定するというものです。パラメーターと説明のリストの終わりは、「上位ビット」がオンになっている (1 に設定されている) 32 ビット レジスタの最後のパラメーターによって区切られます。残念ながら、この規則には、呼び出し元のプログラムですべてのパラメーターが渡されない、あるいは呼び出し元のコードと呼び出し先のコードが一致しない場合に発生する可能性がある問題を回避するために従順なアセンブラーまたは
C のルーチンによって最後のパラメーターが動的に検出されるなど、ずさんな点がいくつかあります。
注: 同じ問題が PL/I や COBOL などの間にも存在する可能性があります。
- Open PL/I
- Open PL/I は、移行先のプラットフォームまたはオペレーティング システムに固有のパラメーター受け渡し規則に従います。これは、コンピューター サイエンスの文献では一般に ABI (アプリケーション バイナリ インターフェイス) と呼ばれています。どのレジスタがどのような目的に使用されるかや、パラメーターがスタックにプッシュされるか別の方法で渡されるかなどが規定されています。
スタックの破損の一般的な原因
- 呼び出されるプロシージャの ENTRY 宣言と呼び出される PROC 内の PROCEDURE 定義が一致していない
- スタックの破損は、パラメーターの数またはパラメーターの属性 (あるいはその両方) の違いが原因で発生することがあります。たとえば、呼び出し元では 10 個の項目を含む配列を渡すように求めているのに対し、呼び出されるプロシージャでは 20 個の項目を含む配列を受け取るように求めている場合、スタックの破損が発生する可能性があります。これがどのように問題になるかについては、上記の「パラメーターの受け渡し:z/OS と Open PL/I」を参照してください。
解決方法:渡す配列と受け取る配列が一致していることを確認してください。この問題をコードベース全体にわたって解消するためのフィールド開発ソリューションが Micro Focus カスタマー ケア から提供されています。このシナリオの特定には Enterprise Analyzer 製品も役立ちます。
- AUTOMATIC 変数のポインターがルーチンから別のルーチンに一致しないポインターを使用して渡されている
- このシナリオでは、このポインターに基づく呼び出し先ルーチン内の変数が呼び出し元の変数よりも大きいと宣言されている場合にスタックの破損が発生します。その変数への代入により、その変数の後の位置にあるスタックが破損します。問題の重大度は、何がどこで破損しているかに全面的に依存します。
解決方法:呼び出し元と呼び出し先のルーチンで対応する変数のサイズが一致していることを確認してください。
- 2 つのプロシージャ間でポインターが受け渡される配列について、その配列が 2 つのプロシージャ間で異なる配列境界で宣言されている
- 解決方法:適切なコーディング手法は、呼び出し先のプログラムまたは関数で * (アスタリスク) を使用して配列境界を宣言することです。これにより、渡される配列記述子に従って、呼び出し先のプログラムまたは関数で正しいコードが生成されるようになります。
スタック サイズの拡張
Windows プラットフォームでは、スタック サイズを増やすことで、スタック サイズの制限に達することによる問題の発生を減らすことができます。次の構文を使用します。
LINK /EDIT /STACK:stack-size[,commit] cassi.exe
stack-size はバイト数です。たとえば、次のコマンドはスタック サイズを 8 MB に増やします。
LINK /EDIT /STACK:8000000,8000000 cassi.exe