System abend

S0CB: Decimal divide exception

An S0CB abend means a packed decimal division failed, almost always because the divisor was zero. Less often the quotient was too large for the field that receives it.

Also written as 0CB, SOCB, abend 0CB, system abend 0CB, decimal divide exception, divide by zero abend.

What it means

The processor divides packed decimal fields with a single instruction. Before it does, it checks that the divisor isn't zero and that the quotient will fit in the space the instruction leaves for it. If either check fails, it raises a decimal-divide exception, program interrupt code 11 (hex B), and z/OS ends the step with system completion code 0CB.

In COBOL, a DIVIDE statement or a COMPUTE with a division on packed decimal (COMP-3) or zoned decimal fields can produce it. The compiler sizes its work areas so that the quotient nearly always fits, which leaves a zero divisor as the cause in almost every case. Binary (COMP) fields can go through different instructions, so the same mistake there can show up as S0C9, the fixed-point divide exception.

Zero is a valid number, so the data passes every validity check. The program has met a case nobody coded for.

Common causes

  • A count used as a divisor is zero, for example an average computed after reading no records, or a unit cost for an item with a quantity of zero.
  • A divisor read from an input file or a table is zero because the record is incomplete or the table entry was never filled in.
  • The divisor was initialized to zero and the code path that should have set it didn't run.
  • A COBOL DIVIDE or COMPUTE has no ON SIZE ERROR clause, so nothing in the program catches a zero divisor.
  • In assembler, the dividend field doesn't have enough leading zeros for the quotient, so the result won't fit even though the divisor isn't zero.

How to find the problem

  1. Look for CEE3211S in the job log, or the IEA995I symptom dump with completion code 0CB. Note the program name and the offset.
  2. Find that offset in the compiler listing made with the LIST or OFFSET option. It points to a DIVIDE, or to a COMPUTE that divides.
  3. Check each divisor in that statement. In a dump or a debugger, a packed zero is all zero digits followed by the sign, such as X'00000C'.
  4. Trace where the divisor got its value. Look at the record being processed when the step failed, the table entry it came from, or the counter that should have been added to.

How to fix it

  • Test the divisor before dividing, for example with IF WS-COUNT NOT = ZERO, and decide what the result should be when it is zero.
  • Add ON SIZE ERROR to DIVIDE and COMPUTE statements, so the program handles a zero divisor or an oversized result instead of abending.
  • If the zero came from bad input or an incomplete table, fix the data and rerun from the failed step.
  • In assembler, make the dividend field long enough, with enough leading zeros, for the largest quotient you expect.

What it looks like

CEE3211S The system detected a decimal-divide exception (System Completion Code=0CB).
         From compile unit RATECALC at entry point RATECALC at compile unit offset +00000B1E
IEA995I SYMPTOM DUMP OUTPUT
  SYSTEM COMPLETION CODE=0CB  REASON CODE=0000000B
IEF450I BILLRUN3 STEP020 - ABEND=S0CB U0000 REASON=0000000B

Questions

Does ON SIZE ERROR catch division by zero in COBOL?

Yes. COBOL treats division by zero as a size error, so ON SIZE ERROR runs its statements and the step carries on. Without the clause, the step usually abends.

What is the difference between S0CB and S0C7?

S0C7 means a field didn't hold a valid packed number. S0CB means the numbers were valid but the division couldn't be done, usually because the divisor was zero. If the divisor holds spaces or low-values, you get S0C7 instead.

Why did I get S0C9 instead of S0CB?

S0C9 is the binary version. When the divisor is a COMP or BINARY field, the compiler can use binary divide instructions, and dividing by zero there raises a fixed-point divide exception.