C/400

68. MCH3601 を assert でやっつける !!

MCH3601 は C言語だけでなく RPG や CLP でも発生するポインター・エラーである。
特に i5/OS が C言語で書かれるようになってから CLP のパラメータのエラーであっても
MCH3601 が頻出するようになってきた。

   MCH3601 : ポインターが参照された位置に設定されていない

とのこの訳の不明なメッセージは端的に表現すると実体の無いポインターが使用されようとした、ということである。
例えばある変数としてのポインターを定義したが malloc によってメモリ確保していないポインターを
使用しようとした場合に発生する。
また全く変数として確保されていない場所を使用しようとした場合にも発生するエラーである。

   MCH3601 : ポインターが参照された位置に設定されていない
             原因−−ポインターが直接にかまたは基底ポインターとして使用されましたが,アド
             レスに対して設定されていません。  

このメッセージは頻出する割りには、どの場所でどのステートメントで、さらにどの変数が
エラーと解釈されているのかが一切、情報として含まれていない厄介なメッセージである。
MCH3601 が発生したときのメッセージ・データ等の情報も克明に調べてみたが具体的な情報は見つからなかった。
IBM も、もう少し情報を公開するようにして欲しいものである。
幸い、「66. C400のエラー・ステートメントを取得する方法」で紹介した MONMSG を使うとエラー行は
特定することができる。そこで MCH3601 が発生した場合、

     #include <assert.h>
             :
            assert(ポインター変数名);        

を実行すると assert で指定したポインター変数が正常であれば assert は何もせずに通過するが
変数ポインターが NULL であれば assert はエラーを表示して、プログラムはそこで異常終了する。
このことを利用すれば assert によって、どの変数が MCH3601 を引き起こしているかを特定することができる。

【 C/400 : LR処理 】
-------------------------------------------------------------------------
0001.00 #include <stdio.h>                                               
0002.00 #include <stdlib.h>                                              
0003.00 #include <string.h>                                              
0004.00 #include <assert.h>                                              
0005.00 #include <signal.h>                                              
0006.00 #include <errno.h>                                               
0007.00                                                                  
0008.00 #define TRUE         0                                           
0009.00 #define FALSE       -1                                           
0010.00 #define NDEBUG       1                                           
0011.00 char buff_a[10], buff_b[10];                                     
0012.00   volatile _INTRPT_Hndlr_Parms_T ca;                             
0013.00 void MonitorMSG(_INTRPT_Hndlr_Parms_T ca);                       
0014.00 #pragma linkage(MonitorMSG, OS)                                  
0015.00 #pragma map(MonitorMSG, "ASNET.COM/MONMSG")                      
0016.00                                                                  
0017.00 void main(void){                                                 
0018.00   char* str;                                                     
0019.00                                                                  
0020.00    #pragma exception_handler(MONMSG, ca, 0, _C2_MH_ESCAPE,       
0021.00                                             _CTLA_HANDLE)        
0022.00   printf("** TESTPTR **n");                                      
0023.00   getchar();                                                     
0024.00   strcpy(buff_a, "123456789ABC");                               
0025.00   memcpy(buff_b, "99999", 5);                                   
0026.00 /*str = (char*)malloc(10); */                                   
0027.00   strcpy(str, "ABC");                                           
0028.00   assert(str);                                                  
0029.00   printf("buff_a = %s, buff_b = %sn", buff_a, buff_b);         
0030.00   getchar();                                                    
0031.00   free(str);                                                    
0032.00   exit(0);                                                      
0033.00                                                                 
0034.00 MONMSG:                                                         
0035.00    #pragma disable_handler                                      
0036.00 /* MonitorMSG(ca); */                                           
0037.00    assert(buff_a);                                              
0038.00    assert(buff_b);                                              
0039.00    assert(str);                                                 
0040.00    getchar();                                                   
0041.00   exit(0);                                                      
0042.00 }                                                               
-------------------------------------------------------------------------
【 解説 】

このプログラムは意図的に ポインター変数 strmalloc で初期化せずに実行して
MCH3601 を引き起こすようにしている。
MCH3601 が発生すると制御は MONMSG に移されるが
assert(buff_a)assert(buff_b) はエラーにはならずに通過するだけだが、
assrt(str) がエラーとして停止することによって str がポインター・エラーとなっていることを
発見することができる。