La gestione dei file in COBOL è apparentemente semplice. Si dichiara un file nella DIVISIONE AMBIENTI, se ne descrive la struttura dei record nella DIVISIONE DATI e si utilizzano i comandi OPEN, READ o WRITE e CLOSE nella DIVISIONE PROCEDURE. Quattro verbi, un unico ciclo di vita. Il problema è che i programmi COBOL raramente rimangono semplici: accumulano logica, percorsi di eccezione, salti condizionali e chiamate PERFORM nel corso di decenni di manutenzione. Ciò che inizia come un semplice schema di apertura e chiusura si trasforma silenziosamente in qualcosa di più complesso: file aperti due volte in un singolo percorso di esecuzione, istruzioni CLOSE eseguite anche quando non è aperto alcun file, uscite di errore che saltano completamente l'istruzione CLOSE.
Nessuno di questi problemi è immediatamente visibile. Il programma viene compilato. Spesso viene eseguito senza errori, con gli input che si testano. Fallisce silenziosamente con combinazioni di input non previste, oppure le prestazioni della finestra batch si degradano così gradualmente che nessuno riesce a collegare la causa all'effetto. L'analisi statica li individua prima che tutto ciò accada.
Rilevamento delle perdite in ogni lingua
SMART TS XL Mappa le catene di riferimenti di lunga durata e le strutture dati illimitate nell'intero codice sorgente.
Maggiori InformazioniI quattro difetti di stato dei file che vale la pena individuare
Prima di addentrarci nei meccanismi di rilevamento, ecco una chiara tassonomia di ciò che state cercando. Non tutti i problemi relativi ai file COBOL sono uguali.
| Difetto | Cosa succede durante l'esecuzione | Gravità |
|---|---|---|
| Doppio aperto | APRI su un file già aperto → STATO FILE 41 o aberrazione | Alto |
| CHIUDERE senza preavviso APERTURA | CHIUDI un file che non è mai stato aperto → STATO FILE 42 o aberrazione | Alto |
| Manca la funzione CHIUSURA sull'uscita normale | File lasciato aperto durante l'esecuzione di STOP RUN → Il sistema operativo lo chiude, ma i buffer non svuotati comportano il rischio di perdita di dati | Medio |
| Manca la funzione CLOSE all'uscita di errore | Il programma si arresta in modo anomalo con il file aperto → potenziale danneggiamento dei record nei file VSAM | Alto |
| Apertura/chiusura ridondante in un ciclo | File aperto e chiuso a ogni iterazione → elevato overhead di I/O | Media altezza |
Punto chiave: i difetti di massima gravità, ovvero le doppie aperture e chiusure senza apertura, causano errori di runtime immediati o rischi per l'integrità dei dati. I difetti di prestazioni (aperture/chiusure a livello di ciclo) non producono alcun errore, ma solo rallentamenti nei processi batch di cui nessuno è riuscito a risalire alla causa.
Cosa rende difficile trovarlo manualmente?
La difficoltà non sta nell'identificare lo schema. Qualsiasi sviluppatore sa che non si dovrebbe aprire un file due volte. La difficoltà sta nel fatto che il flusso di controllo COBOL non è lineare, il che rende inaffidabile la tracciatura manuale.
Consideriamo un programma con questa struttura:
cobolo
PROCEDURE DIVISION.
MAIN-LOGIC.
PERFORM INITIALIZATION
PERFORM PROCESS-RECORDS
PERFORM TERMINATION
STOP RUN.
INITIALIZATION.
OPEN INPUT CUSTOMER-FILE
OPEN OUTPUT REPORT-FILE
MOVE 0 TO WS-ERROR-FLAG.
PROCESS-RECORDS.
READ CUSTOMER-FILE INTO WS-CUSTOMER-REC
AT END MOVE 1 TO WS-EOF-FLAG
END-READ
IF WS-ERROR-FLAG = 1
PERFORM ERROR-EXIT
END-IF
PERFORM UNTIL WS-EOF-FLAG = 1
PERFORM PROCESS-ONE-RECORD
READ CUSTOMER-FILE INTO WS-CUSTOMER-REC
AT END MOVE 1 TO WS-EOF-FLAG
END-EXEC
END-PERFORM.
ERROR-EXIT.
DISPLAY 'Error in processing'
CLOSE CUSTOMER-FILE *> CLOSE here...
STOP RUN.
TERMINATION.
CLOSE CUSTOMER-FILE *> ...and CLOSE here too
CLOSE REPORT-FILE
STOP RUN.
Riesci a individuare il difetto senza tracciare ogni percorso di esecuzione? Se WS-ERROR-FLAG è impostato su 1 all'interno PROCESS-ONE-RECORD (forse tramite un sottoprogramma chiamato), i flussi di controllo vanno a ERROR-EXIT, che chiude il file e si ferma. Questo è corretto. Ma se WS-ERROR-FLAG is non è un impostato, il ciclo si completa, PROCESS-RECORDS ritorna, e TERMINATION corre, che chiude anche CUSTOMER-FILEDue chiusure, una apertura. Stato del file di runtime 42.
Questo è un semplice programma in tre sezioni. I programmi reali hanno venti sezioni, chiamate condizionali PERFORM, istruzioni GO TO nel codice legacy e routine di gestione delle eccezioni che a loro volta chiamano altre routine. La tracciatura manuale non solo è soggetta a errori, ma è anche impraticabile.
Come l'analisi statica modella lo stato dei file
L'analisi statica rileva questi difetti costruendo un grafo di flusso di controllo del programma e propagando lo stato dei file lungo ogni percorso.
L'analisi assegna a ciascun file una variabile di stato con tre possibili valori:
CLOSEDIl file non è stato aperto oppure è stato chiuso correttamente.OPENIl file è stato aperto e non è ancora stato chiuso.UNKNOWN, lo stato non può essere determinato staticamente (ad esempio, apertura condizionale in un ramo non completamente analizzato)
Ad ogni istruzione OPEN, l'analisi controlla: questo file è già nello stato OPEN? Se sì → difetto di doppio APERTURA.
Ad ogni istruzione CLOSE: questo file è nello stato CLOSED or UNKNOWN? Se CHIUSO → chiudere senza difetto aperto.
Ad ogni percorso per INTERROMPERE L'ESECUZIONE o USCIRE DAL PROGRAMMA: c'è qualche file ancora nello stato OPEN? Se sì → difetto di chiusura mancante.
Per i cicli, l'analisi verifica se un'istruzione OPEN o CLOSE è dominata da un'intestazione di ciclo, ovvero se viene eseguita a ogni iterazione.
Attento: I casi più difficili per qualsiasi analizzatore sono le chiamate PERFORM alle routine condivise. Se
ERROR-HANDLERviene chiamato da dodici punti diversi in un programma, lo stato del file nel punto della chiamata PERFORM determina se la chiusura all'internoERROR-HANDLERè corretto o errato. Un analizzatore che non propaga lo stato attraverso le catene PERFORM produrrà falsi negativi (mancando difetti reali) o falsi positivi (segnalando codice corretto).
L'apertura/chiusura a livello di ciclo: un difetto di prestazioni senza codice di errore
Questo schema non produce errori di runtime né anomalie di stato dei file. Semplicemente, viene eseguito lentamente, potenzialmente di ordini di grandezza più lentamente del necessario.
cobolo
*> PROBLEMATIC: file opened and closed on every iteration
PROCESS-ALL-REGIONS.
PERFORM VARYING WS-REGION-ID FROM 1 BY 1
UNTIL WS-REGION-ID > 10
OPEN INPUT CUSTOMER-FILE
PERFORM PROCESS-REGION-RECORDS
CLOSE CUSTOMER-FILE
END-PERFORM.
A meno che il file non sia fisicamente partizionato per regione, questo approccio causa un sovraccarico non necessario. In pratica, sarebbe meglio aprire il file una sola volta, leggere tutti i record e applicare il filtraggio in memoria o tramite logica.
Ogni operazione OPEN su un file VSAM comporta una ricerca nel catalogo, l'inizializzazione dell'ACB e l'allocazione del pool di buffer. Ogni operazione CLOSE svuota i buffer, aggiorna il catalogo e rilascia l'ACB. Per un file con dieci regioni, questo processo si ripete dieci volte anziché una sola. Per un file con 10,000 record e mille regioni, i calcoli diventano complessi.
cobolo
*> CORRECT: open once, filter inside the loop
PROCESS-ALL-REGIONS.
OPEN INPUT CUSTOMER-FILE
PERFORM VARYING WS-REGION-ID FROM 1 BY 1
UNTIL WS-REGION-ID > 10
PERFORM PROCESS-REGION-RECORDS
END-PERFORM
CLOSE CUSTOMER-FILE.
L'analisi statica rileva questo problema identificando le istruzioni OPEN e CLOSE che sono dominate dai cicli, ovvero ogni esecuzione del corpo del ciclo esegue l'istruzione OPEN o CLOSE. Il rilevamento richiede che il grafo di flusso di controllo rappresenti la struttura del ciclo, non solo la sequenza delle istruzioni.
STATO DEL FILE: Il segnale di stato del file del tuo programma, se lo controlli
Ogni operazione su un file COBOL imposta il campo FILE STATUS definito nella voce FILE-CONTROL. Un programma che controlla FILE STATUS dopo ogni OPEN, READ, WRITE e CLOSE può rilevare e rispondere a qualsiasi anomalia dello stato del file in fase di esecuzione. Un programma che ignora FILE STATUS procede alla cieca.
Lista di controllo: codici di stato file che ogni sviluppatore COBOL dovrebbe conoscere
00Completamento con successo10, Fine del file (LETTURA: nessun altro record)35File non trovato (OPEN INPUT: il file non esiste)41File già aperto (OPEN su un file in stato APERTO)42File non aperto (CHIUDERE o LEGGERE su un file in stato CHIUSO)47, tentativo di lettura su file non aperto INPUT o IO48, tentativo di scrittura su file non aperto OUTPUT, IO o EXTEND97File aperto correttamente (specifico per IBM, in alcuni ambienti)
cobolo
FILE-CONTROL.
SELECT CUSTOMER-FILE
ASSIGN TO CUSTFILE
FILE STATUS IS WS-CUST-FILE-STATUS.
WORKING-STORAGE SECTION.
01 WS-CUST-FILE-STATUS PIC XX.
PROCEDURE DIVISION.
OPEN INPUT CUSTOMER-FILE
IF WS-CUST-FILE-STATUS NOT = '00'
DISPLAY 'OPEN failed: ' WS-CUST-FILE-STATUS
PERFORM ABEND-ROUTINE
END-IF.
Attento: Un errore di manutenzione comune è dichiarare lo STATO DEL FILE nella voce CONTROLLO FILE ma non farvi mai riferimento
WS-CUST-FILE-STATUSnella DIVISIONE PROCEDURE. Il campo viene popolato dopo ogni operazione sui file, ma se nessun codice lo controlla, il programma continua l'esecuzione ignorando gli errori. L'analisi statica può segnalare questo schema: FILE STATUS dichiarato ma mai utilizzato nella logica condizionale.
Tre modelli COBOL reali che causano difetti
Modello 1: Il problema dell'uscita di errore condivisa
Un programma ha più sezioni di elaborazione, ognuna con il proprio gestore degli errori. Diversi gestori degli errori chiudono il file prima di restituire il controllo. Anche la normale routine di terminazione chiude il file. Se si verifica un errore e il ripristino procede oltre il gestore degli errori, il file viene chiuso due volte.
cobolo
VALIDATE-RECORDS.
READ CUSTOMER-FILE INTO WS-REC
AT END MOVE 1 TO WS-EOF
END-READ
IF WS-CUST-FILE-STATUS NOT = '00' AND '10'
CLOSE CUSTOMER-FILE *> closes here on read error
PERFORM WRITE-ERROR-LOG
GO TO TERMINATION *> skips to close in TERMINATION?
END-IF.
TERMINATION.
CLOSE CUSTOMER-FILE *> double close if GO TO reached here
CLOSE REPORT-FILE
STOP RUN.
Migliori GO TO TERMINATION trasferisce il controllo direttamente a TERMINATION, che esegue il proprio CLOSE CUSTOMER-FILESTATO DEL FILE 42.
Soluzione: utilizzare un'unica routine di chiusura centralizzata. Ogni percorso di uscita richiama la stessa routine, che verifica se il file è aperto prima di chiuderlo.
Schema 2: L'APERTURA condizionale
L'apertura di un file è condizionata, ovvero avviene solo quando è attiva una determinata modalità di elaborazione. La chiusura, invece, è incondizionata e si verifica in ogni percorso di esecuzione, inclusi quelli in cui il file non è mai stato aperto.
cobolo
INITIALIZATION.
IF WS-PROCESSING-MODE = 'FULL'
OPEN OUTPUT AUDIT-FILE *> only opened in FULL mode
END-IF.
TERMINATION.
CLOSE AUDIT-FILE *> ALWAYS closes -- FILE STATUS 42 in PARTIAL mode
STOP RUN.
Questo difetto non è visibile durante i test se questi vengono sempre eseguiti in modalità COMPLETA. Si manifesta in produzione alla prima esecuzione in modalità PARZIALE.
Schema 3: ESEGUIRE su tutte le unità di compilazione
Nei programmi che utilizzano CALL per richiamare sottoprogrammi, un file aperto nel programma principale può essere passato a un sottoprogramma che lo chiude, dopodiché il programma principale lo chiude nuovamente.
cobolo
*> Main program
CALL 'SUBPROG1' USING CUSTOMER-FILE-STATUS
*> SUBPROG1 closes CUSTOMER-FILE internally
CLOSE CUSTOMER-FILE *> double close
Questo schema richiede un'analisi interprocedurale , che traccia lo stato del file attraverso il confine della CALL fino al comportamento del sottoprogramma, cosa che una semplice analisi intra-programma non è in grado di rilevare.
Cosa serve a un analizzatore statico per svolgere bene questo compito?
Non tutti gli strumenti di analisi statica gestiscono l'analisi dello stato dei file COBOL con la stessa accuratezza. Ecco una lista di controllo per valutare le loro capacità:
Lo strumento gestisce le catene PERFORM? I programmi COBOL utilizzano PERFORM per richiamare paragrafi e sezioni denominati. Le operazioni sui file all'interno di una destinazione PERFORM devono essere visibili al sistema di tracciamento dello stato del chiamante.
Lo strumento gestisce le istruzioni PERFORM VARYING in linea (cicli)? Il rilevamento dei cicli è necessario per identificare le operazioni OPEN/CLOSE dominate dai cicli.
Traccia lo stato attraverso GO TO? I programmi COBOL legacy utilizzano ampiamente GO TO. Un analizzatore che non è in grado di seguire i collegamenti GO TO nel diagramma di flusso di controllo non rileverà intere classi di difetti.
Gestisce le operazioni di COPIA e SOSTITUZIONE? Il codice per la gestione dei file si trova spesso nei membri COPY. Un analizzatore che non espande i membri COPY prima dell'analisi non rileverà le operazioni definite nel codice incluso.
Il sistema controlla l'utilizzo di FILE STATUS? Un'analisi completa verifica non solo se FILE STATUS è dichiarato, ma anche se viene effettivamente controllato dopo ogni operazione.
Esegue analisi interprocedurali? I sottoprogrammi CALL che eseguono operazioni sui file creano dipendenze di stato tra programmi. Una copertura completa richiede di seguire le catene di CALL.
Punto chiave: uno strumento che controlla solo un singolo paragrafo o una singola sezione non rileverà la maggior parte dei difetti reali. I difetti che contano in produzione, quelli che impiegano anni a manifestarsi e ore a essere diagnosticati, sono quelli che si estendono su più sezioni, rami condizionali e routine chiamate.
Cosa fare con i risultati: un quadro di riferimento per la definizione delle priorità.
Quando l'analisi statica rileva difetti nei file, non tutti i risultati sono uguali. Ecco come classificarli:
Correggere immediatamente (prima della successiva esecuzione del batch):
- Doppio OPEN in qualsiasi percorso di esecuzione in cui FILE STATUS 41 causerebbe un abend
- CHIUDI senza APRI nei percorsi che vengono eseguiti in produzione
- Mancanza di CLOSE sui percorsi di uscita degli errori per i file VSAM (rischio di integrità della scrittura)
Programma per il prossimo sprint:
- Apertura/chiusura dominata da cicli con impatto misurabile sulla finestra batch
- Mancanza di controlli sullo stato dei file critici (audit, transazioni, report).
- Apertura condizionale con chiusura incondizionale nei programmi multimodali
Monitorare e affrontare il problema durante la prossima fase di modernizzazione:
- Dichiarazioni di STATO DEL FILE mancanti
- CHIUDERE solo sui percorsi di uscita normali (il sistema operativo lo gestisce, ma è una cattiva pratica)
- Difetti interprocedurali in cui la correzione richiede il coordinamento di modifiche su più programmi
Come SMART TS XL Analizza lo stato del file COBOL
SMART TS XL'S analisi statica del codice Crea un modello di flusso di controllo di ogni programma COBOL nell'ambiente, espandendo i membri COPY, seguendo le catene PERFORM, tracciando i collegamenti GO TO e propagando lo stato del file attraverso ogni ramo di ogni istruzione condizionale. Non si tratta di una scansione di corrispondenza di pattern; è un modello strutturale di ciò che il programma fa effettivamente in ogni punto raggiungibile della sua esecuzione.
La funzionalità di mappatura delle dipendenze dell'applicazione estende questo concetto alla dimensione interprocedurale: quando un programma COBOL CHIAMA un sottoprogramma che esegue operazioni sui file, la mappa delle dipendenze rappresenta tale relazione, consentendo un'analisi che attraversa i confini delle unità di compilazione. I difetti di doppia apertura che interessano un programma principale e un sottoprogramma chiamato sono visibili nel modello strutturale in un modo che non è possibile in alcuna analisi intra-programma.
La funzionalità di ricerca aziendale rende i risultati utilizzabili su larga scala: trova ogni programma nel portfolio che apre uno specifico dataset, ogni membro COPY che contiene un'istruzione CLOSE, ogni programma che ha un target PERFORM contenente un'istruzione OPEN, attraverso milioni di righe di COBOL in pochi secondi. Per un team di modernizzazione che si prepara a migrare un carico di lavoro batch sul cloud, questa funzionalità di ricerca trasforma un audit manuale di settimane in una query mirata.
La funzionalità di espansione JCL aggiunge il contesto operativo: quali passaggi del job JCL richiamano ciascun programma, a quali dataset fa riferimento ogni istruzione DD e come la gestione dei file nel codice COBOL si connette ai dataset fisici definiti nel JCL. Un difetto di CHIUSURA su un file che il JCL definisce come dataset di output critico ha una priorità più alta rispetto allo stesso difetto su un file di lavoro temporaneo, e tale prioritizzazione richiede la conoscenza del contesto JCL di ciascun programma COBOL.
La lezione più ampia: lo stato del file è solo una dimensione
Le operazioni ridondanti sui file rappresentano un caso specifico di un problema più generale: i programmi COBOL, evolutisi nel corso dei decenni, contengono comportamenti dipendenti dallo stato, come lo stato dei file, gli stati degli switch e degli switch, che possono essere compresi correttamente solo tracciando ogni possibile percorso di esecuzione attraverso l'intero grafo di flusso di controllo.
La revisione umana di questo tipo di codice è lenta, incompleta e incoerente. Sviluppatori diversi trovano difetti diversi. Lo stesso sviluppatore che esamina lo stesso programma due volte trova difetti diversi. L'analisi statica è sistematica: applica le stesse regole a ogni percorso in ogni programma, ogni volta, senza affaticamento o supposizioni.
Per i team che gestiscono ampi portfolio COBOL, sia per la manutenzione ordinaria, sia per programmi di modernizzazione di sistemi legacy o per audit di conformità, il vantaggio di un'analisi sistematica dello stato dei file non si limita all'individuazione dei difetti. Risiede nella certezza che il portfolio sia stato analizzato in modo completo e che i difetti rimanenti siano noti, anziché nascosti.


