https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126336

            Bug ID: 126336
           Summary: cobol: 'USE GLOBAL AFTER ERROR PROCEDURE ON INPUT' not
                    handled.
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: cobol
          Assignee: unassigned at gcc dot gnu.org
          Reporter: peeterjoot at protonmail dot com
  Target Milestone: ---

Created attachment 65101
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65101&action=edit
use-global-nested-reopen.cob (also inline in the report)

# Summary

A contained program's failing `OPEN INPUT` that should be handled by the
containing program's `USE GLOBAL AFTER ERROR PROCEDURE ON INPUT` instead
causes gcobol to **re-enter the outer `OPEN OUTPUT`** of an already-open
printer file. That yields file status **41** and a fatal:

```
EC-I-O-LOGIC-ERROR (I-O status 4x)
```

abort. GnuCOBOL (`cobc`) runs the same program correctly: the USE procedure
executes once, then the outer program closes the printer and finishes.

Minimized from NIST COBOL85 `IC/IC233A.CBL` (CCVS USE GLOBAL / contained
program test).

# Environment

- Compiler: gcobol from GCC trunk (`gcobol (GCC) 17.0.0 20260717
(experimental)`)
- Contrast: GnuCOBOL 3.2-rc2 `cobc` — passes
- Platform: Linux aarch64 (expected elsewhere too)
- Options: `-ffixed-form` only

# Reproducer

`use-global-nested-reopen.cob` (in this directory):

```cobol
       IDENTIFICATION DIVISION.
       PROGRAM-ID. OUTER.
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT PRINT-FILE ASSIGN TO "REPORT".
           SELECT TEST-FILE ASSIGN TO "NO-SUCH-FILE".
       DATA DIVISION.
       FILE SECTION.
       FD  PRINT-FILE.
       01  PRINT-REC PIC X(40).
       FD  TEST-FILE GLOBAL.
       01  TEST-REC PIC X(20).
       PROCEDURE DIVISION.
       DECLARATIVES.
       ERR-SECTION SECTION.
           USE GLOBAL AFTER ERROR PROCEDURE ON INPUT.
       ERR-PROC.
           DISPLAY "IN USE"
           .
       END DECLARATIVES.
       MAIN-SECTION SECTION.
       MAIN.
           OPEN OUTPUT PRINT-FILE
           CALL "INNER"
           CLOSE PRINT-FILE
           DISPLAY "DONE"
           STOP RUN.
       IDENTIFICATION DIVISION.
       PROGRAM-ID. INNER.
       PROCEDURE DIVISION.
           OPEN INPUT TEST-FILE
           EXIT PROGRAM.
       END PROGRAM INNER.
       END PROGRAM OUTER.
```

```sh
gcobol -ffixed-form -o /tmp/use-nested use-global-nested-reopen.cob
./tmp/use-nested   # needs libgcobol on LD_LIBRARY_PATH / rpath
```

# Observed (gcobol)

```
use-global-nested-reopen.cob:24: OPEN REPORT: EC-I-O-LOGIC-ERROR (I-O status
4x)
Aborted
```

gdb shows the sequence:

1. `OPEN OUTPUT PRINT-FILE` — succeeds (`file_pointer` set)
2. nested `OPEN INPUT TEST-FILE` — missing file (status 35)
3. **second** `OPEN OUTPUT PRINT-FILE` with `file_pointer` still set → status
**41**
   → fatal `EC-I-O-LOGIC-ERROR`

So exception / declarative handling returns into the outer `OPEN` again instead
of resuming after the failing nested I-O.

# Expected (and cobc behavior)

```
IN USE
DONE
```

exit 0. The USE procedure runs for the nested open failure; `PRINT-FILE` is
not opened a second time.

```sh
cobc -std=cobol85 -x -o /tmp/use-nested-cobc use-global-nested-reopen.cob
/tmp/use-nested-cobc
```
# Background (note to self -- am assuming gcobol maintainers know this): what
`USE GLOBAL AFTER ERROR PROCEDURE ON INPUT` means

It is a **declarative exception handler** for file I-O, declared in
`DECLARATIVES` before the normal procedure code. When a matching I-O error
occurs, the run-time invokes the associated paragraph/section (here
`ERR-PROC`) instead of only relying on `FILE STATUS` or aborting.

Phrase by phrase:

| Phrase | Role |
|--------|------|
| `USE … PROCEDURE` | Register a declarative procedure for later I-O failures.
|
| `AFTER ERROR` | Run on **error** conditions (permanent error, logic error,
etc.). This is not the normal end-of-file path; `AT END` / end-of-file uses
different mechanisms (`AT END` phrase on `READ`, or a different `USE`). |
| `ON INPUT` | Only for files used in **INPUT** mode (e.g. failing `OPEN INPUT`
/ `READ`). It does **not** cover `OPEN OUTPUT` of the printer file. |
| `GLOBAL` | The handler is visible to **contained (nested) programs**. An I-O
failure inside `INNER` may invoke the outer program's `ERR-PROC`. Without
`GLOBAL`, a nested program would not use that outer declarative. |

Intended control flow for this reproducer (and for `IC233A`):

1. Outer opens `PRINT-FILE` for output (the report/printer file).
2. Nested program opens missing `TEST-FILE` for input → I-O error (status 35).
3. Because of `USE GLOBAL AFTER ERROR PROCEDURE ON INPUT`, control should enter
   outer `ERR-PROC`, then **resume after the failing nested I-O statement**.
4. Outer closes `PRINT-FILE` and finishes.

`IC233A` exists specifically to validate step 3: a USE procedure in the
caller is invoked by a qualifying condition in a contained program.

# Notes

- `FD … GLOBAL` matches the NIST pattern (contained program uses the outer
  file). The abort still occurs without `GLOBAL` on the FD / without the
  `GLOBAL` keyword on `USE`; those are kept here to mirror `IC233A`.
- Related NIST: `IC/IC233A.CBL`; `IC/IC234A.CBL` is a broader GLOBAL
  DECLARATIVES case (already unsupported in this tree for other reasons).

Reply via email to