What it means
Every piece of storage in z/OS carries a storage key, and an ordinary program can only change storage whose key matches its own. When a program stores into storage it isn't allowed to change, the processor raises a protection exception. When a program refers to an address with no storage behind it, the processor raises a translation exception. z/OS reports both as system completion code 0C4, and the reason code tells them apart.
- Reason
4is a protection exception. The address is real, but the program may not change it (or, for fetch-protected storage, read it). Writing through a null pointer ends up here, because the lowest addresses in storage are protected. - Reason
10is a segment-translation exception. No storage has been obtained anywhere near the address. A garbage pointer or a truncated address is the usual source. - Reason
11is a page-translation exception. The page the address falls in was never obtained or has been freed. A pointer to storage that another routine already released often causes it.
Common causes
- A table subscript or index went past the end of an OCCURS table, so the program read or wrote storage beyond it.
- A called program's LINKAGE SECTION doesn't match the caller's USING list. If the caller passes three parameters and the subprogram expects four, the fourth address is whatever happened to be in storage.
- The program used a LINKAGE SECTION item or a pointer before setting it (a missing SET ADDRESS OF), or kept using a pointer after the storage it pointed to was freed.
- The program referred to a file's record area when the file wasn't open, either before the OPEN or after the CLOSE.
- An AMODE 24 program received an address above the 16 MB line. It only uses the low 24 bits of the address, so it reaches the wrong storage.
How to find the problem
- Find CEE3204S (Language Environment) or the IEA995I symptom dump in the job log. Note the reason code (INTC in IEA995I), the load module name and the offset.
- Work out the failing instruction. For reason 4, the PSW points just past it, so subtract the ILC from the offset. For reason 10 or 11, the PSW points at the failing instruction itself. Match the offset to the compiler listing (LIST or OFFSET option) to find the statement.
- Decode the instruction to see which registers formed the address, and read them from the dump or a tool such as Fault Analyzer or Abend-AID. Then trace where that value came from.
- If the statement uses LINKAGE SECTION fields, compare the CALL in the caller with the PROCEDURE DIVISION USING in the subprogram, field by field.
How to fix it
- Add range checks for subscripts, or compile with SSRANGE in test so overruns are caught when they happen.
- Make the caller's and the subprogram's parameter lists match, and recompile both after any change to a shared copybook.
- Set every pointer and LINKAGE SECTION address before using it, and stop using an address once its storage has been freed.
- Open files before touching their record areas, and copy any data you need after the CLOSE to WORKING-STORAGE.
- Link AMODE 24 routines as AMODE 31 if they can run that way, or pass them storage below the line.
What it looks like
IEA995I SYMPTOM DUMP OUTPUT
SYSTEM COMPLETION CODE=0C4 REASON CODE=00000011
PSW AT TIME OF ERROR 078D1000 8002B3C6 ILC 4 INTC 11
ACTIVE LOAD MODULE ADDRESS=0002A000 OFFSET=000013C6
NAME=CLMEDIT
CEE3204S The system detected a protection exception (System Completion Code=0C4).
From compile unit CLMEDIT at entry point CLMEDIT at compile unit offset +000013C6
IEF450I CLMRUN04 STEP030 - ABEND=S0C4 U0000 REASON=00000011