Menu ▾ ▴

#1281 Run unit stops on I-O status 10 or 2x when the file has no FILE STATUS clause

GC 3.x
open
nobody
None
5 - default
2026-10-30
2026-10-30
No

A program that gets a non-fatal I-O status, such as 22 (duplicate key) or 10 (end of file), is stopped by libcob when the file has no FILE STATUS clause and the statement has no INVALID KEY or AT END phrase. The standard says control should go to the end of the statement and the program should carry on. With a FILE STATUS clause the program already carries on, so the same code behaves differently depending on an unrelated clause.

To reproduce

ikey.cob (attached) writes the same key twice:

IDENTIFICATION DIVISION.
PROGRAM-ID. IKEY.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT F ASSIGN TO "ikey.dat" ORGANIZATION INDEXED
        ACCESS RANDOM RECORD KEY F-KEY.
DATA DIVISION.
FILE SECTION.
FD F.
01 F-REC.
   05 F-KEY PIC X.
PROCEDURE DIVISION.
    OPEN OUTPUT F
    MOVE "A" TO F-KEY
    WRITE F-REC
    WRITE F-REC
    DISPLAY "AFTER WRITE"
    CLOSE F
    STOP RUN.

Two more programs are attached. ikeyfs.cob is the same with FILE STATUS FS added to the SELECT and 01 FS PIC XX in WORKING-STORAGE, and it displays "AFTER WRITE " FS. atend.cob opens an empty sequential file F for input and does READ F with no AT END phrase, then DISPLAY "AFTER READ".

cobc -std=cobol2014 -fformat=free -x ikey.cob && ./ikey

Each run starts with no .dat file.

What happens

Every compile exits 0 with no cobc diagnostic.

WRITE with a duplicate key, no INVALID KEY phrase, no FILE STATUS. 3.2.0, run exit 1:

libcob: error: record key already exists (status = 22) for file F ('ikey_dat' => ikey.dat)
libcob: warning: implicit CLOSE of F ('ikey.dat')

AFTER WRITE is not displayed. 3.3-dev r5751, the same command: byte-identical output, run exit 1.

With the FILE STATUS clause (ikeyfs.cob, same command), both versions print AFTER WRITE 22 and exit 0.

READ at end, no AT END phrase, no FILE STATUS (cobc -std=cobol2014 -fformat=free -x atend.cob && ./atend). 3.2.0, run exit 1:

libcob: error: end of file (status = 10) for file F ('atend_dat' => atend.dat)
libcob: warning: implicit CLOSE of F ('atend.dat')

AFTER READ is not displayed. 3.3-dev r5751, the same command: byte-identical output, run exit 1.

What should happen

ikey prints AFTER WRITE and atend prints AFTER READ, both exit 0, as ikeyfs already does. ISO/IEC 1989:2023 says:

  • §9.1.14 rule 4: "If the INVALID KEY phrase is not specified in the input-output statement and there are no applicable exception processing statements, control is transferred to the end of the input-output statement."
  • §14.9.30.4 (READ) general rule 24 d): "If the AT END phrase is not specified in the input-output statement, any applicable at end exception processing statements are executed. If there are no applicable at end exception processing statements, control is transferred to the end of the READ statement."
  • §9.1.12 defines the applicable exception processing statements as statements in a WHEN phrase of an active PERFORM and USE declaratives. The FILE STATUS clause is not one of them, so its presence or absence does not change these rules.
  • §9.1.13.1: "Certain classes of I-O status values indicate fatal exception conditions. These are: any that begin with the digit 3, 4, or 7, and any that begin with the digit 9 that the implementor defines as fatal." Only for those may the implementor "either continue or terminate the execution of the run unit". The table in §14.6.13.1.6 lists EC-I-O-AT-END (I-O status "1x") and EC-I-O-INVALID-KEY (I-O status "2x") as NF, nonfatal.

The 2014 and 2002 editions have the same invalid key and AT END rules (in their numbering the invalid key rule is 9.1.13 rule 4 and the READ rule is 21 d)), and list only 3x, 4x and implementor-defined 9x as fatal.

If the current behaviour is wanted for compatibility with other compilers, a dialect option that is off for the ISO dialects would keep both.

Proposed fix

The attached run-unit-ends-on-nonfatal-io-status.patch is against 3.3-dev r5751 and applies with patch -p1 at the top of the tree. It changes output_error_handler in cobc/codegen.c. In the default error handler, for a file without a FILE STATUS clause, cob_fatal_error (COB_FERROR_FILE) is now called only when the first digit of the I-O status is 3, 4, 7 or 9, the fatal classes of §9.1.13.1 (all 9x statuses stay fatal, as now). For any other status the handler returns and control goes to the end of the statement, as it already does when the file has a FILE STATUS clause. This also lets 5x and 6x continue, which §9.1.13.1 likewise does not list as fatal. Declaratives are unchanged: they run before this check, as before.

With the patch, the same commands as above (built-in-tree cobc and libcob), each run starting with no .dat file:

$ cobc -std=cobol2014 -fformat=free -x ikey.cob && ./ikey
AFTER WRITE
(exit 0)
$ cobc -std=cobol2014 -fformat=free -x ikeyfs.cob && ./ikeyfs
AFTER WRITE 22
(exit 0)
$ cobc -std=cobol2014 -fformat=free -x atend.cob && ./atend
AFTER READ
(exit 0)

ikey gives the same with the default dialect. A fatal status still ends the run: a READ of a file that was never opened (status 47, no FILE STATUS) still prints READ/START not allowed, file not open for input (status = 47) and exits 1.

make check on 3.3-dev r5751 with the patch: 1,373 behaved as expected, 9 skipped, 0 failed, as unpatched (1,372 + the new test); the new test 921 "nonfatal I-O status without FILE STATUS" (tests/testsuite.src/run_file.at) passes. It covers status 10 on a READ and 22 on a WRITE to a RELATIVE file, and checks that status 47 still ends the run.

The patch also updates the expected output of the existing test "TURN EC-I-O" (run_file.at), which pinned the old behaviour: its last READ of file g (no FILE STATUS) at end of file stopped the run with end of file (status = 10) ... on READ. It now expects that READ to continue and the program to exit 0. That test is marked AT_XFAIL_IF([true]) for an unrelated FIXME (EXCEPTION-STATUS after >>TURN ... OFF); with the patch, the FIXME lines are its only remaining difference.

  • None found on the tracker.

Details

GnuCOBOL 3.2.0 (Ubuntu gnucobol3 3.2-4build1) and 3.3-dev r5751 (CI snapshot 3.3-dev.138 of 2026-10-29), x86_64 Linux, both re-run 2026-10-30. On 3.2.0 the Ubuntu C compiler step also prints <command-line>: warning: ‘_FORTIFY_SOURCE’ redefined and its note; that is the distribution's build setting.

4 Attachments

Discussion


Log in to post a comment.