Wykrywanie zbędnych otwarć i zamknięć plików w COBOL-u

Jak wykrywać zbędne otwarcia i zamknięcia plików w języku COBOL: podejście oparte na analizie statycznej

Obsługa plików w języku COBOL jest pozornie prosta. Deklarujesz plik w DZIALE ŚRODOWISKA, opisujesz układ jego rekordów w DZIALE DANYCH, a w DZIALE PROCEDUR używa się instrukcji OPEN, READ lub WRITE i CLOSE. Cztery czasowniki, jeden cykl życia. Problem polega na tym, że programy w języku COBOL rzadko pozostają proste – kumulują logikę, ścieżki wyjątków, rozgałęzienia warunkowe i wywołania PERFORM przez dekady konserwacji. To, co zaczyna się jako czysty schemat pojedynczego otwarcia i zamknięcia, po cichu przekształca się w coś bardziej złożonego: pliki otwierane dwukrotnie w jednej ścieżce wykonania, instrukcje CLOSE wykonywane, gdy żaden plik nie jest otwarty, wyjścia błędów, które całkowicie wykraczają poza CLOSE.

Żaden z tych problemów nie jest od razu widoczny. Program się kompiluje. Często działa bezbłędnie na testowanych danych wejściowych. Po cichu zawodzi przy nieoczekiwanych kombinacjach danych wejściowych lub obniża wydajność okna wsadowego tak stopniowo, że nikt nie łączy przyczyny ze skutkiem. Analiza statyczna wykrywa je, zanim cokolwiek się wydarzy.

Wykrywanie wycieków w każdym języku

SMART TS XL mapuje długotrwałe łańcuchy odniesień i nieograniczone struktury danych w całej bazie kodu.

Więcej informacji

Cztery wady stanu pliku, które warto znaleźć

Zanim przejdziemy do mechaniki wykrywania, oto jasna klasyfikacja tego, czego szukasz. Nie wszystkie problemy z plikami COBOL są sobie równe.

WadaCo dzieje się w czasie wykonywaniaDotkliwość
Podwójne OTWARTEOTWÓRZ w już otwartym pliku → STATUS PLIKU 41 lub abendWysoki
ZAMKNIJ bez wcześniejszego OTWÓRZZAMKNIJ plik, który nigdy nie został otwarty → STATUS PLIKU 42 lub zakończenie awaryjneWysoki
Brakuje CLOSE przy normalnym wyjściuPlik pozostawiony otwarty w trybie STOP RUN → system operacyjny go zamyka, ale nieopróżnione bufory grożą utratą danychŚredni
Brakuje CLOSE przy wyjściu z błęduProgram kończy się niepowodzeniem przy otwartym pliku → potencjalne uszkodzenie rekordu w plikach VSAMWysoki
Nadmiarowe OTWÓRZ/ZAMKNIJ w pętliPlik otwierany i zamykany przy każdej iteracji → poważne obciążenie wejścia/wyjściaŚrednio-wysoki

Kluczowy wniosek: Defekty o najwyższym stopniu istotności, podwójne OTWÓRZ i ZAMKNIJ bez OPEN, powodują natychmiastowe awarie środowiska wykonawczego lub zagrożenia integralności danych. Defekty wydajności (otwarcie/zamknięcie na poziomie pętli) nie powodują żadnych błędów, a jedynie powolne zadania wsadowe, których przyczyny nikt nie ustalił.

Dlaczego trudno to znaleźć ręcznie

Wyzwaniem nie jest identyfikacja wzorca. Każdy programista wie, że nie należy otwierać pliku dwa razy. Problemem jest nieliniowość przepływu sterowania w COBOL-u, która sprawia, że ​​ręczne śledzenie jest zawodne.

Rozważmy program o takiej strukturze:

kobol

       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.

Czy potrafisz zlokalizować defekt bez śledzenia każdej ścieżki wykonania? Jeśli WS-ERROR-FLAG jest ustawiony na 1 wewnątrz PROCESS-ONE-RECORD (być może za pomocą wywołanego podprogramu), sterowanie przepływa do ERROR-EXIT, co zamyka plik i zatrzymuje działanie. To prawda. Ale jeśli WS-ERROR-FLAG is nie ustaw, pętla się kończy, PROCESS-RECORDS zwroty i TERMINATION biegnie, co również zamyka CUSTOMER-FILE. Dwa zamknięcia, jedno otwarcie. STATUS PLIKU w czasie wykonywania 42.

To prosty program składający się z trzech sekcji. Prawdziwe programy składają się z dwudziestu sekcji, warunkowych wywołań PERFORM, instrukcji GO TO w starszym kodzie oraz procedur obsługi wyjątków, które same wywołują inne procedury. Ręczne śledzenie jest nie tylko podatne na błędy, ale i trudne do wykonania.


Jak modele analizy statycznej zapisują stan pliku

Analiza statyczna pozwala na wykrywanie tych defektów poprzez tworzenie grafu przepływu sterowania programu i propagowanie stanu pliku wzdłuż każdej ścieżki.

Analiza przypisuje każdemu plikowi zmienną stanu z trzema możliwymi wartościami:

  • CLOSEDplik nie został otwarty lub został pomyślnie zamknięty
  • OPEN, plik został otwarty, ale jeszcze nie zamknięty
  • UNKNOWN, stanu nie można określić statycznie (np. warunkowe otwarcie w gałęzi nie jest w pełni przeanalizowane)

Przy każdym poleceniu OPEN analiza sprawdza: czy ten plik jest już w stanie OPEN? Jeśli tak → podwójna wada OTWARTA.

Przy każdym poleceniu CLOSE: czy ten plik jest w stanie CLOSED or UNKNOWN? Jeśli ZAMKNIĘTE → zamknij bez otwartej wady.

W każdej ścieżce do STOP RUN lub EXIT PROGRAM: czy jakiś plik jest nadal w stanie OPEN? Jeśli tak → brak bliskiej wady.

W przypadku pętli analiza sprawdza, czy polecenie OPEN lub CLOSE jest zdominowane przez nagłówek pętli, co oznacza, że ​​jest wykonywane przy każdej iteracji.

Uważaj: Najtrudniejszymi przypadkami dla każdego analizatora są wywołania PERFORM w procedurach współdzielonych. Jeśli ERROR-HANDLER jest wywoływany z dwunastu różnych miejsc w programie, stan pliku w momencie wywołania PERFORM decyduje o tym, czy zamknięcie wewnątrz ERROR-HANDLER jest poprawny, czy błędny. Analizator, który nie propaguje stanu przez łańcuchy PERFORM, będzie generował wyniki fałszywie negatywne (brakujące rzeczywiste defekty) lub fałszywie pozytywne (oznaczające poprawny kod).


OTWÓRZ/ZAMKNIJ na poziomie pętli: wada wydajności bez kodu błędu

Ten wzorzec nie powoduje błędów w czasie wykonywania ani anomalii w STANIE PLIKU. Po prostu działa wolno, potencjalnie o rzędy wielkości wolniej niż to konieczne.

kobol

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

O ile plik nie jest fizycznie podzielony na regiony, takie podejście powoduje niepotrzebne obciążenie. W praktyce lepiej byłoby otworzyć plik raz, odczytać wszystkie rekordy i zastosować filtrowanie w pamięci lub za pomocą logiki.

Każde polecenie OPEN w pliku VSAM obejmuje wyszukiwanie w katalogu, inicjalizację bloku ACB i alokację puli buforów. Każde polecenie CLOSE opróżnia bufory, aktualizuje katalog i zwalnia blok ACB. W przypadku pliku z dziesięcioma regionami, dzieje się to dziesięć razy zamiast jednego. W przypadku pliku z 10 000 rekordów i tysiącem regionów, obliczenia stają się uciążliwe.

kobol

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

Analiza statyczna wykrywa to zjawisko poprzez identyfikację instrukcji OPEN i CLOSE, które są zdominowane przez pętlę, tzn. każde wykonanie ciała pętli powoduje wykonanie instrukcji OPEN lub CLOSE. Wykrycie wymaga, aby graf przepływu sterowania reprezentował strukturę pętli, a nie tylko sekwencję instrukcji.


STATUS PLIKU: Sygnał stanu pliku Twojego programu, jeśli go sprawdzisz

Każda operacja na plikach w języku COBOL ustawia pole FILE STATUS zdefiniowane we wpisie FILE-CONTROL. Program, który sprawdza FILE STATUS po każdym OTWARCIU, ODCZYCIE, ZAPISIE i ZAMKNIĘCIU, może wykryć i zareagować na każdą anomalię stanu pliku w czasie wykonywania. Program, który ignoruje FILE STATUS, działa na ślepo.

Lista kontrolna: kody STATUSU PLIKÓW, które powinien znać każdy programista COBOL

  • 00, Pomyślne zakończenie
  • 10Koniec pliku (ODCZYTAJ: brak więcej rekordów)
  • 35, Plik nie znaleziony (OTWÓRZ WEJŚCIE: plik nie istnieje)
  • 41, Plik już otwarty (OTWÓRZ dla pliku w stanie OTWARTY)
  • 42Plik nie jest otwarty (ZAMKNIĘTY lub ODCZYTAJ plik w stanie ZAMKNIĘTYM)
  • 47, Próba ODCZYTU pliku nie została otwarta. WEJŚCIE lub IO
  • 48, Próba zapisu w pliku nie została otwarta WYJŚCIE, IO lub ROZSZERZENIE
  • 97Plik został pomyślnie otwarty (specyficzne dla IBM, niektóre środowiska)

kobol

       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.

Uważaj: Częstym błędem konserwacyjnym jest deklarowanie STATUSU PLIKU w pozycji KONTROLA PLIKÓW, ale nigdy nieodwoływanie się do niego WS-CUST-FILE-STATUS w DZIALE PROCEDUR. Pole jest wypełniane po każdej operacji na pliku, ale jeśli żaden kod go nie sprawdza, program działa po wystąpieniu błędów. Analiza statyczna może oznaczyć ten wzorzec: STATUS PLIKU zadeklarowany, ale nigdy nieodwołany w logice warunkowej.


Trzy rzeczywiste wzorce języka COBOL powodujące defekty

Wzorzec 1: Problem wspólnego wyjścia z błędu

Program składa się z wielu sekcji przetwarzania, z których każda ma własną procedurę obsługi błędów. Kilka procedur obsługi błędów zamyka plik przed zwróceniem go. Standardowa procedura kończenia również zamyka plik. Jeśli wystąpi błąd i odzyskiwanie danych po przejściu procedury obsługi błędów zostanie zakończone, plik zostanie zamknięty dwukrotnie.

kobol

       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.

GO TO TERMINATION przenosi kontrolę bezpośrednio do TERMINATION, który wykonuje własne CLOSE CUSTOMER-FILE. STATUS PLIKU 42.

Poprawka: Użyj jednej scentralizowanej procedury zamykania. Każda ścieżka wyjścia wywołuje tę samą procedurę, która sprawdza, czy plik jest otwarty przed zamknięciem.

Wzorzec 2: Warunkowe OTWARCIE

Plik jest otwierany warunkowo, tylko gdy aktywny jest określony tryb przetwarzania. Natomiast polecenie CLOSE jest bezwarunkowe i występuje w każdej ścieżce wykonywania, także w tych, w których plik nigdy nie został otwarty.

kobol

       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.

Ten defekt jest niewidoczny podczas testów, jeśli testy są zawsze uruchamiane w trybie PEŁNYM. Pojawia się w środowisku produkcyjnym podczas pierwszego uruchomienia w trybie CZĘŚCIOWYM.

Wzorzec 3: PERFORM w jednostkach kompilacji

W programach, które używają polecenia CALL do wywoływania podprogramów, plik otwarty w programie głównym może zostać przekazany do podprogramu, który go zamknie, a następnie program główny ponownie go zamknie.

kobol

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

Ten wzorzec wymaga analizy międzyproceduralnej , śledzenia stanu pliku przez granicę CALL w zachowaniu podprogramu, czego nie można wykryć za pomocą prostej analizy wewnątrzprogramowej.


Czego potrzebuje analizator statyczny, aby dobrze to zrobić

Nie wszystkie narzędzia do analizy statycznej obsługują analizę stanu plików COBOL z równą dokładnością. Oto lista kontrolna decyzji do oceny możliwości:

Czy narzędzie obsługuje łańcuchy PERFORM? Programy COBOL używają PERFORM do wywoływania nazwanych akapitów i sekcji. Operacje na plikach wewnątrz celu PERFORM muszą być widoczne dla śledzenia stanu wywołującego.

Czy narzędzie obsługuje pętle PERFORM VARYING? Wykrywanie pętli jest wymagane do identyfikacji operacji OTWÓRZ/ZAMKNIJ zdominowanych przez pętle.

Czy śledzi stan w GO TO? Starsze programy COBOL intensywnie korzystają z GO TO. Analizator, który nie jest w stanie śledzić krawędzi GO TO w grafie przepływu sterowania, pominie całe klasy defektów.

Czy obsługuje operacje COPY i REPLACE? Kod obsługi plików często znajduje się w elementach COPY. Analizator, który nie rozwinie elementów COPY przed analizą, pominie operacje zdefiniowane w dołączonym kodzie.

Czy sprawdza użycie STATUSU PLIKU? Pełna analiza sprawdza nie tylko, czy STATUS PLIKU jest zadeklarowany, ale także, czy jest on faktycznie sprawdzany po każdej operacji.

Czy wykonuje analizę międzyproceduralną? Podprogramy CALL, które wykonują operacje na plikach, tworzą międzyprogramowe zależności stanu. Prawdziwe pokrycie wymaga następujących łańcuchów CALL.

Kluczowy wniosek: Narzędzie, które sprawdza tylko jeden akapit lub sekcję, przeoczy większość rzeczywistych defektów. Defekty, które mają znaczenie w środowisku produkcyjnym, te, których pojawienie się zajęło lata, a zdiagnozowanie godzin, to te, które obejmują wiele sekcji, gałęzi warunkowych i procedur.


Co zrobić z wynikami: Ramy ustalania priorytetów

Gdy analiza statyczna ujawnia wady plików, nie wszystkie wyniki są takie same. Oto jak je sklasyfikować:

Napraw natychmiast (przed następnym uruchomieniem partii):

  • Podwójne OTWARCIE w dowolnej ścieżce wykonywania, w której STATUS PLIKU 41 spowodowałby nieprawidłowe zakończenie
  • CLOSE bez OPEN w ścieżkach wykonywanych w środowisku produkcyjnym
  • Brak zamknięcia ścieżek wyjścia błędów dla plików VSAM (ryzyko naruszenia integralności zapisu)

Harmonogram następnego sprintu:

  • Zdominowane przez pętlę OTWÓRZ/ZAMKNIJ z mierzalnym wpływem okna wsadowego
  • Brak kontroli STATUSU PLIKU w przypadku plików krytycznych (audyt, transakcja, raport)
  • Warunkowe OTWÓRZ z bezwarunkowym ZAMKNIJ w programach wielomodowych

Śledź i zaadresuj podczas następnego przeglądu modernizacyjnego:

  • Brak deklaracji FILE STATUS
  • ZAMKNIJ tylko na normalnych ścieżkach wyjścia (system operacyjny sobie z tym radzi, ale to zła praktyka)
  • Usterki międzyproceduralne, których naprawa wymaga skoordynowania zmian w wielu programach

W jaki sposób SMART TS XL Analizuje stan pliku COBOL

SMART TS XL'S statyczna analiza kodu Buduje model przepływu sterowania dla każdego programu COBOL w środowisku, rozwijając elementy COPY, podążając za łańcuchami PERFORM, śledząc krawędzie GO TO i propagując stan pliku przez każdą gałąź każdego warunku. Nie jest to skanowanie dopasowujące wzorce; jest to model strukturalny tego, co program faktycznie robi w każdym osiągalnym punkcie swojego wykonania.

Możliwość mapowania zależności aplikacji rozszerza to na wymiar międzyproceduralny: gdy program COBOL wywołuje podprogram wykonujący operacje na plikach, mapa zależności reprezentuje tę relację, umożliwiając analizę wykraczającą poza granice jednostek kompilacji. Podwójne defekty typu OPEN, obejmujące program główny i wywoływany podprogram, są widoczne w modelu strukturalnym w sposób, w jaki nie są widoczne w żadnej analizie wewnątrzprogramowej.

Funkcja wyszukiwania korporacyjnego umożliwia wykorzystanie wyników na dużą skalę: znajdź każdy program w portfolio, który otwiera określony zestaw danych, każdy element COPY zawierający instrukcję CLOSE, każdy program z celem PERFORM zawierającym instrukcję OPEN, w milionach wierszy kodu COBOL w ciągu kilku sekund. Dla zespołu modernizacyjnego przygotowującego się do migracji obciążenia wsadowego do chmury, ta funkcja wyszukiwania zamienia wielotygodniowy ręczny audyt w ukierunkowane zapytanie.

Możliwość rozszerzenia JCL dodaje kontekst operacyjny: które kroki zadania JCL wywołują każdy program, do których zestawów danych odwołuje się każde polecenie DD oraz w jaki sposób obsługa plików w kodzie COBOL łączy się z fizycznymi zestawami danych zdefiniowanymi w JCL. Defekt CLOSE w pliku, który JCL definiuje jako krytyczny zestaw danych wyjściowych, ma wyższy priorytet niż ten sam defekt w tymczasowym pliku roboczym, a ta priorytetyzacja wymaga znajomości kontekstu JCL każdego programu COBOL.


Szersza lekcja: stan pliku to tylko jeden wymiar

Nadmiarowe operacje na plikach stanowią szczególny przykład bardziej ogólnego problemu: programy COBOL, które ewoluowały przez dziesięciolecia, zawierają zachowania zależne od stanu, stanu pliku, stanów przełączników, stanów liczników, które można prawidłowo zrozumieć jedynie poprzez prześledzenie każdej możliwej ścieżki wykonania w pełnym grafie przepływu sterowania.

Ludzki przegląd tego rodzaju kodu jest powolny, niekompletny i niespójny. Różni programiści znajdują różne defekty. Ten sam programista, przeglądając ten sam program dwukrotnie, znajduje różne defekty. Analiza statyczna jest systematyczna: stosuje te same reguły do ​​każdej ścieżki w każdym programie, za każdym razem, bez zmęczenia i bez założeń.

Dla zespołów zarządzających dużymi portfelami COBOL, niezależnie od tego, czy chodzi o bieżącą konserwację, modernizację starszych wersji oprogramowania, czy audyty zgodności, korzyścią z systematycznej analizy stanu plików są nie tylko znalezione defekty. To pewność, że portfel został kompleksowo przeanalizowany, a pozostałe defekty są znane, a nie ukryte.