System abend

S0C8: Fixed-point overflow exception

An S0C8 abend means a binary (fixed-point) add, subtract, shift or similar instruction produced a result too large for the register, and the program had told the processor to report fixed-point overflow. It is uncommon in COBOL and turns up mostly in assembler code.

Other names for this code

Also written as 0C8, SOC8, abend 0C8, system abend 0C8, S0C8-8, fixed-point overflow, fixed point overflow exception.

What it means

Binary integers on the mainframe are signed 32-bit or 64-bit values held in general registers. A 32-bit register holds values from -2,147,483,648 to 2,147,483,647. When an add, subtract, load-complement or left shift produces a result outside that range, the processor keeps the low-order bits, sets condition code 3, and checks the fixed-point overflow mask bit in the program mask of the PSW. If the bit is on, it raises a fixed-point overflow exception, program interruption code 8, and z/OS ends the task with system completion code 0C8 and reason code 8.

Fixed-point overflow is one of the four program checks that a program can switch off. Assembler programs set the program mask with the SPM instruction. Compiled languages decide through their run-time setup. With the bit off, the result simply wraps around and the program carries on with a wrong value. So an S0C8 tells you two things. A value outgrew its register, and the code was running with overflow reporting switched on.

Compiled COBOL checks size errors in its own code, which is why COBOL batch programs rarely end with S0C8.

Common causes

  • A counter or total kept in a 32-bit register or fullword passed 2,147,483,647, often after data volumes grew well beyond what the program was written for.
  • A shift left arithmetic (SLA or SLDA) moved a significant bit into the sign position.
  • LOAD COMPLEMENT or LOAD POSITIVE was applied to the most negative value, -2,147,483,648, which has no positive counterpart in 32 bits.
  • Two large values were added or subtracted in a register when the result needed 64 bits.
  • A field holding garbage, such as an uninitialized fullword, was used in arithmetic and happened to produce an out-of-range result.

How to find the problem

  1. Find CEE3208S (Language Environment) or the IEA995I symptom dump in the job log. Note the PSW address, the ILC and the load module offset.
  2. Overflow is reported after the instruction completes, so the PSW points to the next instruction. Subtract the ILC from the offset and match it to the listing to find the add, subtract or shift that overflowed.
  3. Read the registers involved in the dump. The result register holds the wrapped value, which often looks like a large negative number.
  4. Check where the operands came from, such as a record count, an accumulated total or a field read from input.

How to fix it

  • Use 64-bit arithmetic (the G-form instructions such as AG and SG) or a wider field for values that can grow beyond 2,147,483,647.
  • Check input values and running totals against a sensible limit before using them.
  • Initialize every binary field before use.
  • Switch the fixed-point overflow mask off only where wraparound is really what the program wants, and then test condition code 3 yourself if you need to know.

What it looks like

IEA995I SYMPTOM DUMP OUTPUT
  SYSTEM COMPLETION CODE=0C8  REASON CODE=00000008
IEF450I ACCTLIB1 STEP030 - ABEND=S0C8 U0000 REASON=00000008

IBM documentation

IBM z/OS: 0Cx program interruptions. Use the documentation for your installed release.

Report a correction to WND Software.

Questions

What is the difference between S0C8 and S0CA?

S0C8 is overflow in binary (fixed-point) arithmetic. S0CA is overflow in packed decimal arithmetic. Both can be masked off by the program, and both mean a result was too large for where it was put.

Is S0C8 related to S0C9?

They are both binary arithmetic errors, but S0C9 is the divide case and can't be masked off. S0C8 covers add, subtract, shift and similar instructions.

Why does a COBOL program rarely get S0C8?

Compiled COBOL handles oversize results in its own code, through truncation rules and ON SIZE ERROR. It doesn't depend on the hardware interrupt to find them.