系统检测到保护异常

The system detected a protection exception

我正在尝试使用 COBOL 的排序功能。

IDENTIFICATION DIVISION.                       
PROGRAM-ID. ******.                          
ENVIRONMENT DIVISION.                          
INPUT-OUTPUT SECTION.                          
FILE-CONTROL.                                  
     SELECT IN-FILE ASSIGN TO IFILE.           
     SELECT OUT-FILE ASSIGN TO OFILE.          
     SELECT SORT-FILE ASSIGN TO SORTWK.        
DATA DIVISION.                                 
FILE SECTION.                                  
SD SORT-FILE.                                  
01 SORT-REC.                                   
   05 S-NAME     PIC X(20).                    
   05 S-ADDRESS  PIC X(20).                    
   05 S-ID       PIC 9(9).                     
   05 S-CREDITS  PIC 99.                       
   05 FILLER     PIC X(29).                    
FD IN-FILE.                                    
01 IN-REC.                                     
   05 IN-NAME    PIC X(20).                    
   05 IN-ADDRESS PIC X(20).                    
   05 IN-ID      PIC 9(9).                     
   05 IN-CREDITS PIC 99.                       
   05 FILLER     PIC X(29).                    
FD OUT-FILE.                                   
01 OUT-REC       PIC X(80).                    
WORKING-STORAGE SECTION.                       
01 WS-WORK-AREA.                               
    05  EOF-SW    PIC X           VALUE SPACES.
01 WS-DETAIL-LINES.                            
   05 RPT-LINE.                                
      10 OUT-NAME    PIC X(20).                
      10 OUT-ADDRESS PIC X(20).                
      10 OUT-ID      PIC 9(9).
      10 OUT-CREDITS PIC 99.                      
      10 FILLER      PIC X(29)       VALUE SPACES.
PROCEDURE DIVISION.                               
MAIN-RTN.                                         
    SORT SORT-FILE                                
            ON ASCENDING KEY S-ID                 
            INPUT PROCEDURE READ-RELEASE          
            OUTPUT PROCEDURE RETURN-WRITE.        
    STOP RUN.                                     
OPEN-FILES-RTN.                                   
    OPEN INPUT IN-FILE.                           
    OPEN OUTPUT OUT-FILE.                         
OPEN-FILES-RTN-EXIT. EXIT.                        

READ-RELEASE.                                     
    PERFORM OPEN-FILES-RTN.                       
    PERFORM READ-INPUT                            
     UNTIL EOF-SW = 'F'.                          
READ-RELEASE-RTN-EXIT. EXIT.                      

READ-INPUT.                                       
    READ IN-FILE                                  
     AT END MOVE 'F' TO EOF-SW.                   
    RELEASE SORT-REC FROM IN-REC.                 

RETURN-WRITE.                                     
    MOVE SPACES TO EOF-SW.                        
    PERFORM WRITE-FL                              
     UNTIL EOF-SW  = 'F'.                         
    PERFORM CLOSE-FILES-RTN.                      
RETURN-WRITE-RTN-EXIT. EXIT.                      

WRITE-FL.                                         
    RETURN SORT-FILE RECORD INTO OUT-REC          
     AT END MOVE 'F' TO EOF-SW.                   
    WRITE OUT-REC.
WRITE-FL-RTN-EXIT. EXIT.   

CLOSE-FILES-RTN.           
    CLOSE IN-FILE OUT-FILE.
CLOSE-FILES-RTN-EXIT. EXIT. 

我可以编译这个程序,但是当它执行时,它给出了以下错误:

CEE3204S The system detected a protection exception (System Completion Code=0C4). From compile unit SU98PGM6 at entry point SU98PGM6 at compile unit offset +0005517A at address 1F45517A.

我已经搜索过这个错误,但我无法弄清楚是什么导致我的程序出现这个问题。

我在注意到评论后进行了一些更改,但我仍然遇到与此更改后的代码相同的问题。

READ-RELEASE.                           
    PERFORM OPEN-FILES-RTN.             
    PERFORM READ-INPUT                  
     UNTIL EOF-SW = 'F'.                
READ-RELEASE-RTN-EXIT. EXIT.            

READ-INPUT.                             
    READ IN-FILE                        
     AT END MOVE 'F' TO EOF-SW          
     NOT AT END PERFORM PROCESS-INPUT.  

PROCESS-INPUT.                          
    MOVE IN-NAME TO S-NAME.             
    MOVE IN-ADDRESS TO S-ADDRESS.       
    MOVE IN-ID TO S-ID.                 
    MOVE IN-CREDITS TO S-CREDITS.       
    RELEASE SORT-REC.                   
PROCESS-INPUT-RTN-EXIT. EXIT.           

RETURN-WRITE.                           
    MOVE SPACES TO EOF-SW.              
    PERFORM WRITE-FL                    
     UNTIL EOF-SW = 'F'.                
    PERFORM CLOSE-FILES-RTN.            
RETURN-WRITE-RTN-EXIT. EXIT.            

WRITE-FL.                               
    RETURN SORT-FILE RECORD INTO OUT-REC
     AT END MOVE 'F' TO EOF-SW          
     NOT AT END PERFORM PROCESS-OUTPUT. 
WRITE-FL-RTN-EXIT. EXIT.                

PROCESS-OUTPUT.                         
    MOVE S-NAME TO OUT-NAME.            
    MOVE S-ADDRESS TO OUT-ADDRESS.      
    MOVE S-ID TO OUT-ID.                
    MOVE S-CREDITS TO OUT-CREDITS.
    WRITE OUT-REC.            
PROCESS-OUTPUT-RTN-EXIT. EXIT.   

这是我的 JCL

//******** JOB 1,'*****',NOTIFY=*******                    
//JOBLIB   DD  DSN=*******.*******.*******,DISP=SHR         
//STEP0    EXEC PGM=SU98PGM6                               
//IFILE    DD DSN=*******.*******.*******.*******(*******),DISP=SHR
//SORTWK   DD DSN=*******.*******.*******.*******,DISP=SHR          
//OFILE    DD DSN=*******.*******.*******.*******,              
//            DISP=(NEW,CATLG,DELETE),                     
//            DCB=(BLKSIZE=0,LRECL=80,RECFM=FB),           
//            SPACE=(CYL,(1,1),RLSE),                      
//            UNIT=SYSDA                                   
/*         

当使用 COBOL、SORT(DFSORT 或 SyncSORT)和语言环境时,//SYSOUT DD 的输出可能会令人困惑,这可能会给您 run-time 消息,因为它们都默认使用 SYSOUT,并且消息将混杂在一起。

幸运的是,您可以更改默认行为,如此处所示的 DFSORT 和语言环境(在 LE 中有很多方法可以指定选项,最灵活的是 JCL 中的 //CEEOPTS DD):https://whosebug.com/a/29521423/1927206

COBOL 本身有一个编译器选项,OUTDD。该值默认为 SYSOUT,但您可以指定任何 OUTDD(xxxx)


好的,在看过您的 JCL 以及您对程序中的 DISPLAY 语句如何影响数据的评论后,我成功地进行了部分重现。

我使用 DFSORT,但我不了解你的确切行为,所以我假设你使用 SYNCSORT。

我从我的 JCL 中删除 //SYSOUT DD 后得到的行为是这条消息:

IGZ0026W The SORT-RETURN special register was never referenced, but the current content indicated the sort or merge operation in program STOB87 on line number 46 was unsuccessful.

当我将 //SYSOUT 添加回 JCL 时,程序 运行 成功。

当我取出 //SYSOUT 并在 SORT 之前添加一个 DISPLAY 时,程序运行。这是因为如果 JCL 中没有 //SYSOUT,则执行的第一个 DISPLAY 将导致动态创建一个(输出将出现在假脱机中,就好像它是一个单独的 JOB,具有相同的名称和作业编号)。

在我的例子中,DFSORT 抱怨缺少 //SYSOUT。使用 DISPLAY,在 DFSORT 启动时不会丢失 //SYSOUT。

我不得不假设 SYNCSORT 面临着类似的问题,但 run-time COBOL 消息并未生成,并且 SYNCSORT 本身在下一个版本中失败。

虽然这看起来是一个简单而常见的问题,但因为我们总是复制一段JCL来制作一段新的JCL,//SYSOUT总是在那里。

请参阅《企业 COBOL 编程指南》第 12 章,了解如何使用 SORT-RETURN 确认 SORT 已成功完成。

我敢肯定,如果您在 JCL 中包含 //SYSOUT,则无论您是否有 DISPLAY,都不会再出现异常终止。

高 "offset" 的原因是异常终止处理器无法识别您的 SORT 产品的 entry-point ,因此不断向后搜索以找到它可以识别的东西,并定位到您的程序entry-point 然后计算出不正确的偏移量。调用某些汇编程序时也会发生这种情况。


首先,对于您的 S0C4,这是一个保护异常,这意味着您正在尝试访问 "belong" 您无法访问的存储。

您在程序 SU98PGM6 中获得了 S0C4。您在此处发帖时狡猾地删除了您的 PROGRAM-ID 姓名,这可能没有帮助。

SU98PGM6 不是您的程序。异常结束(异常结束)位于失败程序中的偏移 X'0005517A' 处。这意味着,从程序的 "start"(入口点)开始,offset/displacement X'0005517A' 处的指令是试图做坏事的指令。该偏移量(十进制形式为 348538)表示一个相当大的程序。你的程序很小。

这可以通过多种方式实现。例如,您可能从其他地方复制了 JCL,但未能更改 EXEC PGM=。您可能有一个与 STEPLIB 串联中较早的程序同名的程序。您可能编译了错误的程序。等等

当您遇到异常终止时,请始终确认您拥有的编译列表是针对异常终止的程序的。一个简单而有用的方法是:

   01  W-WHEN-COMPILED                     PIC X(8)BX(8).

   ...

  * where it can only be executed once:
       MOVE WHEN-COMPILED           TO W-WHEN-COMPILED
       DISPLAY 
               "yourname COMPILED ON " 
               W-WHEN-COMPILED

"yourname" 您替换为 PROGRAM-ID.

之后的文本

输出将是这样的:

yourname COMPILED ON 11/24/15 10.35.26

这将匹配编译列表每页标题中的 date/time。

如果你 运行 一个程序但没有得到那个输出,或者你得到了输出但它不是预期的输出,那么你知道 你的 程序是不是那个 运行ning.

现在开始你的程序。

  1. 您无需使用 input/output 程序即可进行排序
  2. 你应该总是使用SELECT语句的FILE STATUS子句,并且总是检查file-status 您定义的字段(每个文件一个),在每个 IO 操作之后。测试输入文件的 file-status 字段将允许您识别 end-of-file 而无需曲折的 AT END/NOT AT END 构造
  3. 如果您使用排序过程,COBOL 会执行 IO。如果您不这样做,并使用编译器选项 FASTSRT,您的 SORT 产品将执行 IO,这将比 COBOL 更有效。
  4. 除非您正在选择或重新格式化记录,否则不需要排序过程
  5. 由于您使用的是对记录进行隐式移动的 INTO,因此您不需要单独移动数据
  6. COBOL,因为支持 1985 标准的编译器具有 "scope terminators",我很确定您将拥有该标准。在此之前唯一的 scope-terminator 是 full-stop/period。如今,在使用 "imperative statements" 时以及所有条件语句中,都使用明确的、具体的 scope-terminator。在您的情况下,替换使用 READ/END-READ、RETURN/END-RETURN
  7. 只在 PROCEDURE DIVISION 需要的地方使用 full-stops/periods,而不是在代码行上。这有助于 moving/copying 代码从一个位置到另一个位置
  8. 使用 88 级 condition-names 进行测试,而不是文字。您可以使名称完全有意义,因此没有人会想知道 'F' 在特定上下文中的含义

要在 COBOL 程序中对文件进行简单排序,请查看 SORT ... USING ... GIVING... 并使用编译器选项 FASTSRT(如果可能)。

您还没有意识到段落(或 SECTION)和 EXIT 语句的含义。

当使用 PERFORM 或 SORT PROCEDURE 执行时转移到段落中的代码,returns 控制何时到达下一段。

您编写的 "exit" 段落从未被使用过,但是查看代码的人会假设(如果他们很傻,很多人会做出这样的假设)您使用了 THRU 并且他们会留在 GO TO "exit" 段落中。然后他们会惊讶于该程序表现不佳(如果他们幸运的话)并且最终会发现他们已经使用 GO TO 将控制转移到 PERFORM/PROCEDURE.

的范围之外。

如果您当地的标准强制使用 exit-paragraphs,那么您必须在 PERFORM 和 PROCEDURE 语句中使用 THRU。

Exit-paragraphs 完全没用,除了为 GO TO 提供 target-label 之外什么都不做,这意味着将来有人可能会使用 GO TO 为 "convenience"。 =28=]

这是删除了 exit-paragraphs 的原始程序:

IDENTIFICATION DIVISION.                       
PROGRAM-ID. ******.                          
ENVIRONMENT DIVISION.                          
INPUT-OUTPUT SECTION.                          
FILE-CONTROL.                                  
     SELECT IN-FILE ASSIGN TO IFILE.           
     SELECT OUT-FILE ASSIGN TO OFILE.          
     SELECT SORT-FILE ASSIGN TO SORTWK.        
DATA DIVISION.                                 
FILE SECTION.                                  
SD SORT-FILE.                                  
01 SORT-REC.                                   
   05 S-NAME     PIC X(20).                    
   05 S-ADDRESS  PIC X(20).                    
   05 S-ID       PIC 9(9).                     
   05 S-CREDITS  PIC 99.                       
   05 FILLER     PIC X(29).                    
FD IN-FILE.                                    
01 IN-REC.                                     
   05 IN-NAME    PIC X(20).                    
   05 IN-ADDRESS PIC X(20).                    
   05 IN-ID      PIC 9(9).                     
   05 IN-CREDITS PIC 99.                       
   05 FILLER     PIC X(29).                    
FD OUT-FILE.                                   
01 OUT-REC       PIC X(80).                    
WORKING-STORAGE SECTION.                       
01 WS-WORK-AREA.                               
    05  EOF-SW    PIC X           VALUE SPACES.
01 WS-DETAIL-LINES.                            
   05 RPT-LINE.                                
      10 OUT-NAME    PIC X(20).                
      10 OUT-ADDRESS PIC X(20).                
      10 OUT-ID      PIC 9(9).
      10 OUT-CREDITS PIC 99.                      
      10 FILLER      PIC X(29)       VALUE SPACES.
PROCEDURE DIVISION.                               
    SORT SORT-FILE                                
            ON ASCENDING KEY S-ID                 
            INPUT PROCEDURE READ-RELEASE          
            OUTPUT PROCEDURE RETURN-WRITE        
    GOBACK
    .                                     
OPEN-FILES-RTN.                                   
    OPEN INPUT IN-FILE                           
    OPEN OUTPUT OUT-FILE
    .                         

READ-RELEASE.                                     
    PERFORM OPEN-FILES-RTN
    PERFORM READ-INPUT                            
     UNTIL EOF-SW = 'F'                          
    .

READ-INPUT.                                       
    READ IN-FILE                                  
     AT END MOVE 'F' TO EOF-SW
    END-READ                   
    RELEASE SORT-REC FROM IN-REC
    .

RETURN-WRITE.                                     
    MOVE SPACES TO EOF-SW
    PERFORM WRITE-FL                              
     UNTIL EOF-SW  = 'F'                         
    PERFORM CLOSE-FILES-RTN                      
    .

WRITE-FL.                                         
    RETURN SORT-FILE RECORD INTO OUT-REC          
     AT END MOVE 'F' TO EOF-SW
    END-RETURN
    WRITE OUT-REC
    .

CLOSE-FILES-RTN.           
    CLOSE IN-FILE OUT-FILE
    .

我还将 STOP RUN 更改为更灵活的 GOBACK,并删除了您的第一个 paragraph-name,因为它是不必要的并且对于 COBOL 新手来说意味着太多(COBOL本身没有 "main" 的概念,因为它可能与您可能知道的其他语言相关。