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).