Détection des ouvertures et fermetures de fichiers redondantes en COBOL

Comment détecter les ouvertures et fermetures de fichiers redondantes en COBOL : une approche d’analyse statique

La gestion des fichiers en COBOL paraît simple au premier abord. On déclare un fichier dans la division ENVIRONMENT, on décrit sa structure d'enregistrement dans la division DATA, et on utilise les instructions OPEN, READ ou WRITE, et CLOSE dans la division PROCEDURE. Quatre verbes, un cycle de vie. Le problème, c'est que les programmes COBOL restent rarement simples : au fil des décennies de maintenance, ils accumulent logique, gestion des exceptions, branchements conditionnels et appels PERFORM. Ce qui commence comme un modèle simple d'ouverture et de fermeture uniques se transforme insidieusement en quelque chose de plus complexe : des fichiers ouverts deux fois dans un même chemin d'exécution, des instructions CLOSE exécutées alors qu'aucun fichier n'est ouvert, des sorties d'erreur qui s'écartent complètement de l'instruction CLOSE.

Aucun de ces problèmes n'est immédiatement visible. Le programme compile. Il s'exécute souvent sans erreur avec les entrées testées. Il échoue silencieusement avec des combinaisons d'entrées imprévues, ou dégrade les performances de la fenêtre de traitement par lots si progressivement que personne ne fait le lien de cause à effet. L'analyse statique les détecte avant même que cela ne se produise.

Détection des fuites dans toutes les langues

SMART TS XL cartographie les chaînes de références à longue durée de vie et les structures de données illimitées sur l'ensemble de votre code source.

En savoir plus

Les quatre défauts d'état de fichier qu'il convient de détecter

Avant d'aborder les mécanismes de détection, voici une classification claire de ce que vous recherchez. Tous les problèmes liés aux fichiers COBOL ne sont pas identiques.

DéfautQue se passe-t-il lors de l'exécution ?Gravité
Double OUVERTOUVRIR un fichier déjà ouvert → STATUT DU FICHIER 41 ou erreur d'exécutionHaute
FERMER sans ouverture préalableFERMER un fichier qui n'a jamais été ouvert → STATUT DU FICHIER 42 ou erreur d'ouvertureHaute
Fermeture manquante sur la sortie normaleFichier laissé ouvert lors de l'arrêt de l'exécution → Le système d'exploitation le ferme, mais les tampons non vidés présentent un risque de perte de données.Moyenne
Fermeture manquante en cas d'erreur de sortieLe programme s'arrête anormalement avec un fichier ouvert → corruption potentielle des enregistrements dans les fichiers VSAMHaute
Opérations OPEN/CLOSE redondantes en boucleOuverture et fermeture du fichier à chaque itération → surcharge d'E/S importanteMoyen-élevé

Point clé : Les défauts les plus critiques, à savoir les doubles ouvertures et fermetures sans ouverture, entraînent des défaillances d’exécution immédiates ou des risques pour l’intégrité des données. Les défauts de performance (ouvertures/fermetures au niveau des boucles) ne génèrent aucune erreur, mais seulement des ralentissements des traitements par lots dont la cause reste inconnue.

Ce qui rend cela difficile à trouver manuellement

Le problème n'est pas d'identifier le schéma. Tout développeur sait qu'il ne faut pas ouvrir un fichier deux fois. Le problème, c'est que le flux de contrôle COBOL est non linéaire, ce qui rend le traçage manuel peu fiable.

Prenons l'exemple d'un programme ayant cette structure :

Cobol

       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.

Pouvez-vous repérer le défaut sans analyser chaque chemin d'exécution ? WS-ERROR-FLAG est fixé à 1 à l'intérieur PROCESS-ONE-RECORD (peut-être par un sous-programme appelé), le contrôle est transmis à ERROR-EXITce qui ferme le fichier et s'arrête. C'est exact. Mais si WS-ERROR-FLAG is pas L'ensemble est défini, la boucle est terminée, PROCESS-RECORDS retours, et TERMINATION courses, ce qui ferme également CUSTOMER-FILEDeux fermetures, une ouverture. Durée d'exécution : 42.

Il s'agit d'un programme simple en trois sections. Les programmes réels comportent vingt sections, des appels conditionnels à PERFORM, des instructions GO TO dans du code hérité et des routines de gestion des exceptions qui appellent elles-mêmes d'autres routines. Le traçage manuel est non seulement source d'erreurs, mais aussi impossible à gérer.


Comment les modèles d'analyse statique enregistrent l'état des fichiers

L'analyse statique détecte ces défauts en construisant un graphe de flux de contrôle du programme et en propageant l'état du fichier le long de chaque chemin.

L'analyse attribue à chaque fichier une variable d'état avec trois valeurs possibles :

  • CLOSEDLe fichier n'a pas été ouvert ou a été fermé avec succès.
  • OPENLe fichier a été ouvert mais pas encore fermé.
  • UNKNOWN, l'état ne peut pas être déterminé statiquement (par exemple, ouverture conditionnelle dans une branche non entièrement analysée)

À chaque instruction OPEN, l'analyse vérifie : ce fichier est-il déjà dans l'état OPEN? Si oui → défaut double OUVERT.

À chaque instruction CLOSE : ce fichier est-il dans l'état CLOSED or UNKNOWN? Si FERMÉ → fermer sans défaut ouvert.

À chaque étape de l'arrêt ou de la sortie du programme : un fichier est-il encore dans cet état ? OPEN? Si oui → défaut de fermeture manquant.

Pour les boucles, l'analyse vérifie si une instruction OPEN ou CLOSE est dominée par un en-tête de boucle, ce qui signifie qu'elle exécute chaque itération.

Fais attention: Les cas les plus difficiles pour tout analyseur sont les appels PERFORM dans des routines partagées. ERROR-HANDLER La fonction PERFORM est appelée depuis douze endroits différents dans un programme. L'état du fichier au moment de l'appel PERFORM détermine si la fermeture interne doit être effectuée. ERROR-HANDLER est correct ou erroné. Un analyseur qui ne propage pas l'état à travers les chaînes PERFORM produira des faux négatifs (manquant de véritables défauts) ou des faux positifs (signalant du code correct).


L'ouverture/fermeture au niveau de la boucle : un défaut de performance sans code d'erreur

Ce modèle ne génère aucune erreur d'exécution ni aucune anomalie de statut de fichier. Il s'exécute simplement lentement, potentiellement plusieurs ordres de grandeur plus lentement que nécessaire.

Cobol

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

À moins que le fichier ne soit physiquement partitionné par région, cette approche engendre une surcharge inutile. En pratique, il serait préférable d'ouvrir le fichier une seule fois, de lire tous les enregistrements et d'appliquer le filtrage en mémoire ou par un mécanisme logique.

Chaque ouverture d'un fichier VSAM implique une recherche dans le catalogue, l'initialisation de l'ACB et l'allocation d'un pool de mémoires tampons. Chaque fermeture vide les mémoires tampons, met à jour le catalogue et libère l'ACB. Pour un fichier comportant dix régions, ce processus se répète dix fois au lieu d'une seule. Pour un fichier contenant 10 000 enregistrements et mille régions, le calcul devient complexe.

Cobol

      *> 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'analyse statique détecte ce problème en identifiant les instructions OPEN et CLOSE qui sont dominées par les boucles, c'est-à-dire que chaque exécution du corps de la boucle déclenche l'appel à OPEN ou à CLOSE. Cette détection nécessite que le graphe de flux de contrôle représente la structure de la boucle, et non seulement la séquence des instructions.


ÉTAT DU FICHIER : Signal d’état du fichier de votre programme, si vous le vérifiez

Chaque opération sur un fichier COBOL modifie le champ FILE STATUS défini dans l'entrée FILE-CONTROL. Un programme qui vérifie FILE STATUS après chaque opération OPEN, READ, WRITE et CLOSE peut détecter et corriger toute anomalie d'état de fichier lors de son exécution. Un programme qui ignore FILE STATUS navigue à vue.

Liste de vérification : Codes d’état de fichier que tout développeur COBOL devrait connaître

  • 00, Réussite
  • 10Fin du fichier (LECTURE : plus d’enregistrements)
  • 35Fichier introuvable (OPEN INPUT : le fichier n'existe pas)
  • 41Fichier déjà ouvert (OUVERT sur un fichier à l'état OUVERT)
  • 42Fichier non ouvert (FERMER ou LIRE sur un fichier à l'état FERMÉ)
  • 47Tentative de lecture sur un fichier non ouvert (entrée ou E/S)
  • 48, écriture tentée sur un fichier non ouvert OUTPUT, IO ou EXTEND
  • 97Fichier ouvert avec succès (spécifique à IBM, certains environnements)

Cobol

       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.

Fais attention: Une erreur de maintenance courante consiste à déclarer FILE STATUS dans l'entrée FILE-CONTROL sans jamais y faire référence. WS-CUST-FILE-STATUS Dans la division PROCEDURE, le champ est renseigné après chaque opération sur les fichiers. Toutefois, si aucun code ne le vérifie, le programme ignore les erreurs. L'analyse statique peut révéler ce comportement : le champ FILE STATUS est déclaré mais jamais utilisé dans la logique conditionnelle.


Trois exemples concrets de code COBOL à l'origine de défauts

Modèle 1 : Le problème de sortie d'erreur partagé

Un programme comporte plusieurs sections de traitement, chacune dotée de son propre gestionnaire d'erreurs. Plusieurs gestionnaires d'erreurs ferment le fichier avant de retourner. La routine de terminaison normale ferme également le fichier. Si une erreur survient et que la récupération se poursuit au-delà du gestionnaire d'erreurs, le fichier est fermé deux fois.

Cobol

       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.

Le GO TO TERMINATION transfère le contrôle directement dans TERMINATION, qui exécute ses propres CLOSE CUSTOMER-FILE. ÉTAT DU FICHIER 42.

Solution : Utiliser une routine de fermeture centralisée unique. Chaque chemin de sortie appelle la même routine, qui vérifie si le fichier est ouvert avant de le fermer.

Modèle 2 : L’OUVERTURE conditionnelle

L'ouverture d'un fichier est conditionnelle et ne se produit que lorsqu'un certain mode de traitement est actif. En revanche, la fermeture est inconditionnelle et intervient dans tous les cas, même lorsque le fichier n'a jamais été ouvert.

Cobol

       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.

Ce défaut est invisible lors des tests si ceux-ci sont toujours exécutés en mode COMPLET. Il apparaît en production dès la première exécution en mode PARTIEL.

Modèle 3 : EXÉCUTER à travers les unités de compilation

Dans les programmes qui utilisent CALL pour appeler des sous-programmes, un fichier ouvert dans le programme principal peut être transmis à un sous-programme qui le ferme, puis le programme principal le ferme à nouveau.

Cobol

      *> Main program
       CALL 'SUBPROG1' USING CUSTOMER-FILE-STATUS
       *> SUBPROG1 closes CUSTOMER-FILE internally
       CLOSE CUSTOMER-FILE    *> double close

Ce modèle nécessite une analyse interprocédurale , traçant l'état du fichier à travers la limite CALL jusqu'au comportement du sous-programme, ce qu'une simple analyse intra-programme ne peut pas détecter.


Ce dont un analyseur statique a besoin pour bien faire cela

Tous les outils d'analyse statique ne gèrent pas l'analyse de l'état des fichiers COBOL avec la même profondeur. Voici une liste de critères pour évaluer leurs capacités :

L'outil prend-il en charge les chaînes PERFORM ? Les programmes COBOL utilisent PERFORM pour appeler des paragraphes et des sections nommés. Les opérations sur les fichiers effectuées à l'intérieur d'une cible PERFORM doivent être visibles par le système de suivi d'état de l'appelant.

L'outil gère-t-il les instructions PERFORM VARYING en ligne (boucles) ? La détection de boucles est nécessaire pour identifier les opérations OPEN/CLOSE dominées par les boucles.

Est-ce que le suivi de l'état est possible lors des instructions GO TO ? Les programmes COBOL anciens utilisent abondamment les instructions GO TO. Un analyseur incapable de suivre les arêtes GO TO dans le graphe de flux de contrôle passera à côté de catégories entières de défauts.

Gère-t-il les opérations COPY et REPLACE ? Le code de gestion des fichiers se trouve souvent dans les membres COPY. Un analyseur qui n'étend pas les membres COPY avant l'analyse manquera des opérations définies dans le code inclus.

Vérifie-t-il l'utilisation de FILE STATUS ? Une analyse complète vérifie non seulement si FILE STATUS est déclaré, mais aussi s'il est effectivement vérifié après chaque opération.

Effectue-t-il une analyse interprocédurale ? Les sous-programmes appelés qui effectuent des opérations sur les fichiers créent des dépendances d'état entre programmes. Une couverture complète nécessite de suivre les chaînes d'appels.

Point clé : Un outil qui ne vérifie qu’un seul paragraphe ou une seule section passera à côté de la plupart des défauts réels. Les défauts critiques en production, ceux qui ont mis des années à apparaître et des heures à diagnostiquer, sont ceux qui s’étendent sur plusieurs sections, des branches conditionnelles et des routines appelées.


Que faire des résultats : un cadre de priorisation

Lorsqu'une analyse statique révèle des défauts dans les fichiers, tous les résultats ne se valent pas. Voici comment les hiérarchiser :

Corrigez immédiatement (avant le prochain traitement par lots) :

  • Double OUVRIR dans tout chemin d'exécution où le STATUT DE FICHIER 41 provoquerait un arrêt anormal
  • FERMER sans OUVRIR dans les chemins qui s'exécutent en production
  • Absence de la commande CLOSE sur les chemins de sortie d'erreur pour les fichiers VSAM (risque d'intégrité d'écriture)

Calendrier du prochain sprint :

  • Opérations d'ouverture/fermeture dominées par les boucles avec un impact mesurable sur la fenêtre de traitement par lots
  • Absence de vérifications de l'état des fichiers critiques (audit, transaction, rapport)
  • OUVERTURE conditionnelle avec FERMETURE inconditionnelle dans les programmes multimodes

Suivi et traitement lors de la prochaine phase de modernisation :

  • Déclarations d'état de fichier manquantes
  • FERMER uniquement sur les chemins de sortie normaux (le système d'exploitation le gère, mais c'est une mauvaise pratique)
  • Défauts interprocéduraux où la correction nécessite la coordination de modifications entre plusieurs programmes

Comment SMART TS XL Analyse l'état des fichiers COBOL

SMART TS XL's analyse de code statique Ce modèle construit le flux de contrôle de chaque programme COBOL de l'environnement, en développant les membres COPY, en suivant les chaînes PERFORM, en traçant les instructions GO TO et en propageant l'état des fichiers à travers chaque branche de chaque instruction conditionnelle. Il ne s'agit pas d'une analyse par correspondance de motifs ; c'est un modèle structurel de ce que fait réellement le programme à chaque point accessible de son exécution.

La fonctionnalité de cartographie des dépendances applicatives étend cette capacité à la dimension interprocédurale : lorsqu’un programme COBOL appelle un sous-programme effectuant des opérations sur des fichiers, la cartographie des dépendances représente cette relation, permettant ainsi une analyse qui dépasse les limites des unités de compilation. Les défauts de double ouverture (Double OPEN) qui s’étendent sur un programme principal et un sous-programme appelé sont visibles dans le modèle structurel, contrairement à toute analyse intra-programme.

La fonction de recherche d'entreprise permet d'exploiter les résultats à grande échelle : elle permet de trouver en quelques secondes, parmi des millions de lignes de COBOL, tous les programmes du portefeuille qui ouvrent un ensemble de données spécifique, tous les membres COPY contenant une instruction CLOSE, tous les programmes dont la cible PERFORM contient une instruction OPEN. Pour une équipe de modernisation préparant la migration d'une charge de travail par lots vers le cloud, cette fonction transforme un audit manuel de plusieurs semaines en une requête ciblée.

La fonctionnalité d'extension JCL ajoute le contexte opérationnel : les étapes de travail JCL qui appellent chaque programme, les fichiers référencés par chaque instruction DD et la manière dont la gestion des fichiers dans le code COBOL est liée aux fichiers physiques définis dans le JCL. Un défaut de type « FERMÉ » sur un fichier défini par le JCL comme fichier de sortie critique est prioritaire par rapport au même défaut sur un fichier de travail temporaire, et cette priorisation nécessite de connaître le contexte JCL de chaque programme COBOL.


Leçon plus générale : l’état des fichiers n’est qu’une dimension.

Les opérations redondantes sur les fichiers sont un cas particulier d'un problème plus général : les programmes COBOL qui ont évolué au fil des décennies contiennent des comportements dépendants de l'état (état des fichiers, états des commutateurs, états des compteurs) qui ne peuvent être correctement compris qu'en traçant chaque chemin d'exécution possible à travers le graphe de flux de contrôle complet.

L'analyse humaine de ce type de code est lente, incomplète et incohérente. Différents développeurs découvrent des défauts différents. Un même développeur, en relisant le même programme à deux reprises, peut trouver des défauts différents. L'analyse statique est systématique : elle applique les mêmes règles à chaque chemin d'accès dans chaque programme, systématiquement, sans fatigue ni supposition.

Pour les équipes gérant d'importants portefeuilles COBOL, que ce soit pour la maintenance courante, la modernisation de systèmes existants ou les audits de conformité, l'intérêt d'une analyse systématique de l'état des fichiers ne se limite pas à la détection des défauts. Il réside surtout dans la certitude que le portefeuille a été analysé de manière exhaustive et que les défauts restants sont identifiés plutôt que dissimulés.