Identifiera redundanta filöppningar och stängningar i COBOL

Hur man upptäcker redundanta filöppningar och stängningar i COBOL: En statisk analysmetod

Filhantering i COBOL är till synes enkelt. Du deklarerar en fil i ENVIRONMENT DIVISION, beskriver dess postlayout i DATA DIVISION och använder OPEN, READ eller WRITE, och CLOSE i PROCEDURE DIVISION. Fyra verb, en livscykel. Problemet är att COBOL-program sällan förblir enkla, de ackumulerar logik, undantagsvägar, villkorliga grenar och PERFORM-anrop under årtionden av underhåll. Det som börjar som ett rent mönster med en enda öppning och en enda stängning muterar tyst till något mer komplext: filer som öppnas två gånger i en enda exekveringsväg, CLOSE-satser som körs när ingen fil är öppen, felmeddelandet avslutar den grenen helt efter CLOSE.

Inget av dessa problem är omedelbart synliga. Programmet kompilerar. Det körs ofta utan fel på de indata du testar. Det misslyckas tyst på indatakombinationer du aldrig förväntat dig, eller försämrar batchfönstrets prestanda så gradvis att ingen kopplar orsak till verkan. Statisk analys hittar dem innan något av det händer.

Läckagedetektering på alla språk

SMART TS XL mappar långlivade referenskedjor och obegränsade datastrukturer över hela din kodbas.

Mer information

De fyra filtillståndsfel som är värda att hitta

Innan vi går in på detekteringsmekanik, här är en tydlig taxonomi för vad du letar efter. Alla COBOL-filproblem är inte skapade lika.

defektVad händer vid körningSvårighetsgraden
Dubbel ÖPPENÖPPNA på en redan öppen fil → FILSTATUS 41 eller avbrytHög
STÄNG utan föregående ÖPPNASTÄNG på en fil som aldrig öppnades → FILSTATUS 42 eller abendHög
Saknar STÄNG vid normal utgångFilen lämnas öppen vid STOP RUN → OS stänger den, men buffertar som inte har tömts riskerar dataförlustMedium
Saknar STÄNG vid felmeddelandeProgrammet avbryts med filen öppen → potentiell postkorruption på VSAM-filerHög
Redundant ÖPPNA/STÄNGA i en loopFil öppnas och stängs vid varje iteration → allvarlig I/O-overheadMedelhög

Viktig slutsats: De mest allvarliga felen, dubbel ÖPPNA och STÄNGA utan ÖPPNA, orsakar omedelbara fel vid körning eller dataintegritetsrisker. Prestandadefelen (öppna/stänga på loopnivå) producerar inga fel alls, bara långsamma batchjobb som ingen har kunnat spåra till orsaken.

Vad gör detta svårt att hitta manuellt

Utmaningen ligger i att inte identifiera mönstret. Alla utvecklare vet att man inte ska öppna en fil två gånger. Utmaningen är att COBOL-kontrollflödet är icke-linjärt på sätt som gör manuell spårning opålitlig.

Tänk dig ett program med denna struktur:

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.

Kan du upptäcka felet utan att spåra varje exekveringsväg? WS-ERROR-FLAG är satt till 1 inuti PROCESS-ONE-RECORD (kanske av ett anropat delprogram), styrningen går till ERROR-EXIT, vilket stänger filen och stoppar. Det stämmer. Men om WS-ERROR-FLAG is inte inställd, loopen är klar, PROCESS-RECORDS returer, och TERMINATION körningar, som också stänger CUSTOMER-FILETvå stängningar, en öppen. Körtidsfilstatus 42.

Detta är ett enkelt program i tre sektioner. Riktiga program har tjugo sektioner, villkorliga PERFORM-anrop, GOTO-satser i äldre kod och rutiner för undantagshantering som själva anropar andra rutiner. Manuell spårning är inte bara felbenägen, den är inte hanterbar.


Hur statisk analys modellerar filtillstånd

Statisk analys upptäcker dessa defekter genom att konstruera ett kontrollflödesdiagram för programmet och sprida filtillståndet längs varje sökväg.

Analysen tilldelar varje fil en tillståndsvariabel med tre möjliga värden:

  • CLOSED, filen har inte öppnats, eller så stängdes den utan problem
  • OPEN, filen har öppnats och ännu inte stängts
  • UNKNOWN, tillståndet kan inte bestämmas statiskt (t.ex. villkorlig öppen i en gren som inte analyserats fullständigt)

Vid varje OPEN-sats kontrollerar analysen: är den här filen redan i tillstånd OPENOm ja → dubbel ÖPPEN-defekt.

Vid varje CLOSE-sats: är den här filen i tillstånd CLOSED or UNKNOWNOm STÄNGD → stäng utan öppen defekt.

Vid varje sökväg till STOP KÖR eller EXIT PROGRAM: finns det fortfarande någon fil i tillståndet OPENOm ja → saknas nära defekt.

För loopar kontrollerar analysen om en OPEN- eller CLOSE-sats domineras av en loop-rubrik, vilket innebär att den exekverar varje iteration.

Se upp: De svåraste fallen för alla analysatorer är PERFORM-anrop till delade rutiner. Om ERROR-HANDLER anropas från tolv olika platser i ett program, avgör filens tillstånd vid punkten för PERFORM-anropet om stängning inuti ERROR-HANDLER är korrekt eller felaktig. En analysator som inte sprider tillstånd genom PERFORM-kedjor kommer att producera falska negativa resultat (saknade verkliga defekter) eller falska positiva resultat (flaggar korrekt kod).


ÖPPNA/STÄNGA på loopnivå: Ett prestandafel utan felkod

Det här mönstret producerar inga körtidsfel och inga fel i FILSTATUS. Det körs helt enkelt långsamt, potentiellt flera storleksordningar långsammare än nödvändigt.

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.

Om inte filen är fysiskt partitionerad efter region orsakar den här metoden onödig overhead. I praktiken vore det bättre att öppna filen en gång, läsa alla poster och tillämpa filtrering i minnet eller via logik.

Varje ÖPPNING på en VSAM-fil involverar en katalogsökning, ACB-initiering och buffertpoolallokering. Varje STÄNGNING tömmer buffertar, uppdaterar katalogen och frigör ACB:n. För en fil med tio regioner händer detta tio gånger istället för en gång. För en fil med 10 000 poster och tusen regioner blir matematiken smärtsam.

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.

Statisk analys detekterar detta genom att identifiera OPEN- och CLOSE-satser som är loopdominerade, det vill säga att varje exekvering av loopkroppen exekverar OPEN eller CLOSE. Detekteringen kräver att kontrollflödesgrafen representerar loopstrukturen, inte bara satssekvensen.


FILSTATUS: Ditt programs filstatussignal, om du markerar den

Varje COBOL-filoperation ställer in fältet FILE STATUS som definieras i FILE-CONTROL-posten. Ett program som kontrollerar FILE STATUS efter varje OPEN, READ, WRITE och CLOSE kan upptäcka och reagera på varje filtillståndsanomali vid körning. Ett program som ignorerar FILE STATUS flyger i blindo.

Checklista: FILSTATUS-koder som alla COBOL-utvecklare bör känna till

  • 00, Lyckad slutförande
  • 10, Slut på fil (LÄS: inga fler poster)
  • 35, Filen hittades inte (ÖPPNA INGÅNG: filen finns inte)
  • 41, Filen är redan öppen (ÖPPEN på en fil i ÖPPET tillstånd)
  • 42, Filen kan inte öppnas (STÄNGD eller LÄST på en fil i STÄNGD tillstånd)
  • 47, LÄSNING försökte göras på fil som inte öppnades INPUT eller IO
  • 48, SKRIVFÖRSÖKAD på fil som inte öppnades OUTPUT, IO eller EXTEND
  • 97, Filen öppnades (IBM-specifik, vissa miljöer)

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.

Se upp: Ett vanligt underhållsfel är att deklarera FILE STATUS i FILE-CONTROL-posten men aldrig referera till den. WS-CUST-FILE-STATUS i PROCEDURE DIVISION. Fältet fylls i efter varje filoperation, men om ingen kod kontrollerar det kör programmet fel utan att spela in dem. Statisk analys kan flagga detta mönster: FILE STATUS deklarerad men aldrig refererad i villkorlig logik.


Tre verkliga COBOL-mönster som orsakar defekter

Mönster 1: Det delade fel- och utgångsproblemet

Ett program har flera bearbetningssektioner, var och en med sin egen felhanterare. Flera felhanterare stänger filen innan den återgår. Den normala avslutningsrutinen stänger också filen. Om ett fel uppstår och återställningen fortsätter förbi felhanteraren stängs filen två gånger.

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.

Ocuco-landskapet GO TO TERMINATION överför kontrollen direkt till TERMINATION, som utför sin egen CLOSE CUSTOMER-FILE. FILSTATUS 42.

Åtgärd: Använd en enda centraliserad stängningsrutin. Varje utgångsväg anropar samma rutin, som kontrollerar om filen är öppen innan den stängs.

Mönster 2: Den villkorliga ÖPPNA

En fil öppnas villkorligt, endast när ett visst bearbetningsläge är aktivt. Men STÄNGNINGEN är villkorslös och inträffar i alla exekveringsvägar, inklusive de där filen aldrig öppnades.

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.

Denna defekt är osynlig vid testning om testerna alltid körs i FULL-läge. Den uppstår i produktion vid den första körningen i PARTIAL-läge.

Mönster 3: UTFÖR över kompileringsenheter

I program som använder CALL för att anropa underprogram kan en fil som öppnats i huvudprogrammet skickas till ett underprogram som stänger den, varefter huvudprogrammet stänger den igen.

cobol

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

Detta mönster kräver interprocedural analys , där filtillstånd spåras över CALL-gränsen in i delprogrammets beteende, vilket enkel intraprogramanalys inte kan upptäcka.


Vad en statisk analysator behöver för att göra detta bra

Inte alla statiska analysverktyg hanterar COBOL-filtillståndsanalys med samma djup. Här är en checklista för beslutsfattande för att utvärdera kapaciteten:

Hanterar verktyget PERFORM-kedjor? COBOL-program använder PERFORM för att anropa namngivna stycken och avsnitt. Filåtgärder inuti ett PERFORM-mål måste vara synliga för anroparens tillståndsspårning.

Hanterar verktyget inline PERFORM VARYING (loopar)? Loopdetektering krävs för att identifiera loopdominerade ÖPPNA/STÄNGA-operationer.

Spårar den tillstånd över GO TO? Äldre COBOL-program använder GO TO i stor utsträckning. En analysator som inte kan följa GO TO-kanterna i kontrollflödesgrafen kommer att missa hela klasser av defekter.

Hanterar den COPY och REPLACE? Filhanteringskod finns ofta i COPY-medlemmar. En analysator som inte expanderar COPY-medlemmar före analysen kommer att missa operationer som definierats i inkluderad kod.

Kontrollerar den användningen av FILE STATUS? En fullständig analys kontrollerar inte bara om FILE STATUS deklareras utan om den faktiskt kontrolleras efter varje operation.

Utför den interprocedurell analys? Anropade delprogram som utför filoperationer skapar tillståndsberoenden mellan program. Sann täckning kräver att man följer anropskedjor.

Viktig slutsats: Ett verktyg som bara kontrollerar inom ett enda stycke eller avsnitt kommer att missa de flesta verkliga fel. De fel som är viktiga i produktionen, de som tog år att uppstå och timmar att diagnostisera, är de som sträcker sig över flera avsnitt, villkorliga grenar och så kallade rutiner.


Vad man ska göra med resultaten: Ett prioriteringsramverk

När statisk analys avslöjar filfel är inte alla fynd likadana. Så här prioriterar du dem:

Åtgärda omedelbart (innan nästa batchkörning):

  • Dubbel ÖPPNA i valfri exekveringsväg där FILSTATUS 41 skulle orsaka ett fel
  • STÄNG utan ÖPPEN i sökvägar som körs i produktion
  • Saknar CLOSE på felutgångsvägar för VSAM-filer (risk för skrivintegritet)

Schema för nästa sprint:

  • Loopdominerad ÖPPNA/STÄNGA med mätbar effekt av batchfönstret
  • Saknade FILE STATUS-kontroller på kritiska filer (granskning, transaktion, rapport)
  • Villkorlig ÖPPNING med villkorlig STÄNGNING i flerlägesprogram

Spårning och adress under nästa moderniseringspass:

  • Saknade FILE STATUS-deklarationer
  • STÄNG endast på normala utgångsvägar (OS hanterar det, men dålig praxis)
  • Interprocedurella fel där korrigeringen kräver samordning av ändringar över flera program

Hur SMART TS XL Analyserar COBOL-filens tillstånd

SMART TS XLÄr statisk kodanalys bygger en kontrollflödesmodell för varje COBOL-program i miljön, expanderar COPY-medlemmar, följer PERFORM-kedjor, spårar GO TO-kanter och sprider filtillstånd genom varje gren i varje villkorsstyrt element. Det är inte en mönstermatchningsskanning; det är en strukturell modell av vad programmet faktiskt gör vid varje nåbar punkt i sin exekvering.

Funktionen för mappning av applikationsberoenden utökar detta till den interprocedurala dimensionen: när ett COBOL-program ANROPAR ett delprogram som utför filoperationer, representerar beroendemappningen den relationen, vilket möjliggör analys som korsar kompileringsenhetsgränser. Dubbla OPEN-defekter som sträcker sig över ett huvudprogram och ett anropat delprogram är synliga i den strukturella modellen på ett sätt som de inte är i någon intraprogramanalys.

Företagssökfunktionen gör resultaten användbara i stor skala: hitta alla program i portföljen som öppnar en specifik datamängd, varje COPY - medlem som innehåller en CLOSE-sats, alla program som har ett PERFORM-mål som innehåller en OPEN, över miljontals rader COBOL på några sekunder. För ett moderniseringsteam som förbereder sig för att migrera en batch-arbetsbelastning till molnet förvandlar den här sökfunktionen en veckolång manuell granskning till en riktad fråga.

JCL -expansionsfunktionen lägger till den operativa kontexten: vilka JCL-jobbsteg anropar varje program, vilka dataset varje DD-sats refererar till och hur filhanteringen i COBOL-koden ansluter till de fysiska dataset som definieras i JCL. En CLOSE-defekt på en fil som JCL definierar som en kritisk utdataset har högre prioritet än samma defekt på en temporär arbetsfil, och den prioriteringen kräver att man känner till JCL-kontexten för varje COBOL-program.


Den bredare lärdomen: Filtillstånd är bara en dimension

Redundanta filoperationer är ett specifikt exempel på ett mer generellt problem: COBOL-program som har utvecklats under årtionden innehåller tillståndsberoende beteenden, filtillstånd, växeltillstånd, räknartillstånd, som bara förstås korrekt genom att spåra alla möjliga exekveringsvägar genom hela kontrollflödesgrafen.

Mänsklig granskning av den här typen av kod är långsam, ofullständig och inkonsekvent. Olika utvecklare hittar olika fel. Samma utvecklare som granskar samma program två gånger hittar olika fel. Statisk analys är systematisk: den tillämpar samma regler på varje sökväg i varje program, varje gång, utan trötthet eller antaganden.

För team som hanterar stora COBOL-portföljer, oavsett om det gäller löpande underhåll, äldre moderniseringsprogram eller efterlevnadsrevisioner, är utdelningen av systematisk filstatusanalys inte bara de fel som upptäcks. Det är förtroendet för att portföljen har analyserats fullständigt och att de fel som kvarstår är kända snarare än dolda.