cobol

Addition of PIC 9 variable with space not causing ABEND S0C7


I expected the ADD instruction in the following COBOL program to trigger an ABEND S0C7. However the program terminated normally and the ouput was quite surprising.

The SYSIN in the JCL

//SYSIN   DD *
5
//* There is only the character 5 in the SYSIN (well, followed by a newline character of course)

The COBOL program

WORKING-STORAGE SECTION.
77 X                     PIC 9(10).

PROCEDURE DIVISION.
    ACCEPT X
*   This addition did not trigger an ABEND S0C7
    ADD 1                TO X
    DISPLAY 'X = ' X
    STOP RUN
    .

The output

X = 5000000001

I then ran the program in a debugger

The ACCEPT statement moved a '5' in the leftmost character of X and spaces in the others on the right. So to be more specific, X looked like this after the ACCEPT:

'9         '   <-- These are the 10 characters of X
 0987654321    <-- These are the bytes numbered for clarity

I thought maybe the display of X of my debugger had a bug and showed me space characters instead of zeros but no. I checked the memory at X and it really contained nine bytes with the value 0x40 which are indeed ' ' characters in EBCDIC.

I then checked the assembly generated by the compiler

Well, I forgot to copy the exact output from my machine at work but here is the assembly code in pseudo language.

* ADD 1                TO X
    PACK  XP, X         * Pack X to XP
    AP    XP, ONEP      * XP += 1
    UNPK  XP, X         * Unpack XP to X

So, what am I missing here?

Thanks for your help.

EDIT #1 - February 26th - I checked the exact assembly code

Monday morning. Got the assembly code from my machine at work...

*     ADD 1       TO X
PKA   672(R13),152(10,R9)      PACK ASCII  Y,X
AP    682(6,R13),1072(1,R13)   ADD PACKED  Y,1
UNPK  152(10,R9),682(6,R13)    UNPACK      X,Y
OI    161(,R9),X'F0'

... and the compile option ZONEDATA(NOPFD) was used.


Solution

  • So you are using zoned decimal:

    77 X  PIC 9(10).
    

    When you see c'9 ' in the input, the actual byte values are x'F910F0F0F0F0F0F0F0F0'. Only the low nibble is considered, so that is valid numeric data.

    (The same thing works for ASCII, but the range is x'30313233343536373839', but the same idea. Only the low nibble is used except for the sign byte.)

    As you can see, you are not getting the output you are expecting, because you are accepting directly into a variable that can handle that zoned decimal data you are throwing at it.

    I feel like this is a case where you need to sanitize your inputs. Get them in a string, make sure you have the numbers you think, and only the numbers you think, and ensure you have proper right alignment. Accept is a text oriented verb, it really isn't intended for use with raw numbers, and can be quite dangerous to do so.

    Also, if you edited your JCL with a record oriented editor, like ISPF, you will not have a newline after the c'5', but 79 c' '.