Łata (informatyka)

Z Wikipedii, wolnej encyklopedii

Łata, łatka (ang. patch) – poprawka lub uaktualnienie do programu (rzadziej do danych), przeznaczona do usunięcia pewnych problemów, błędów, rozszerzenia funkcjonalności programu albo zwiększenia wydajności wcześniejszej wersji programu.

Termin ten powstał prawdopodobnie jako komenda systemu Unix (patch) wprowadzona przez Larry'ego Walla, aby ułatwić wymienianie się poprawkami kodu źródłowego i umożliwić ich szybkie, zautomatyzowane aplikowanie do oryginalnego kodu.

Firma Microsoft używa innej terminologii dla swoich poprawek. Mniejsze poprawki nazywane są software updates (aktualizacje), natomiast te bardziej kompleksowe określane są jako service packs (pakiety serwisowe).

Zadaniem łat jest zmiana kodu źródłowego albo maszynowego.

Łaty do oprogramowania dostępnego tylko w formie binarnej[edytuj | edytuj kod]

Łatanie oprogramowania zamkniętego jest możliwe wyłącznie poprzez łaty zmieniające pliki binarne, z uwagi na brak dostępności źródeł. Najprostsze łaty po prostu nadpisują pliki wymagające poprawienia ich poprawionymi wersjami. Wiąże się to z koniecznością umieszczenia w programie dokonującym aktualizacji całych plików (najczęściej poddanych uprzednio kompresji). Łaty takie mogą mieć rozmiar dochodzący do kilkuset MB.

Mniejsze poprawki mogą być wykonywane jako modyfikacje plików binarnych, jednak ze względu na budowę plików wykonywalnych jest to trudne.

Crack jest specyficzną formą łaty, która usuwa z programu zabezpieczenia uniemożliwiające korzystanie z niego nielegalnie.

Łaty do oprogramowania z kodem źródłowym[edytuj | edytuj kod]

W przypadku kodu źródłowego łaty nie muszą przechowywać całych plików, wystarczy zbiór różnic między dwiema wersjami pliku. Plik z łatą generowany jest najczęściej programem diff, a nakładany poleceniem patch. Łata taka może mieć rozmiar kilkudziesięciu MB, jednak z uwagi na zapisanie w niej informacji w postaci tekstowej łaty te doskonale się kompresują (często kompresja redukuje rozmiar łaty nawet o 75%).

Przykład łaty programu diff/patch[edytuj | edytuj kod]

Weźmy dla przykładu prosty program w języku C++ zawierający błąd:

#include <iostream>

int
main ( int argc, char **argv)
{
    char text[20] = {0};

    for ( int i = 1; i < argc; ++i )
    {

        strcat (text, argv[i]);
        strcat (text, " ");

    }

    std::cout << text << std::endl;

    return 0;
}

W powyższym kodzie użyto niebezpiecznego wywołania strcat() bez kontroli długości łańcucha argv[i], który może nie zmieścić się w pamięci przeznaczonej dla zmiennej text.

old$ ./plik Ala ma kota.
Ala ma kota. 
old$ ./plik Ala w domu ma chomika, kota, rybki oraz psa.
Ala w domu ma chomika, kota, rybki oraz psa. 
Naruszenie ochrony pamięci

Zgodnie z przewidywaniami, dane, które nie mieszczą się w pamięci dla nich przeznaczonej nadpisują adres powrotu funkcji main().

Poniżej przedstawiono drugi program w poprawionej wersji:

#include <iostream>
#include <string>

using namespace std;

int
main ( int argc, char **argv)
{
    string text;

    for ( int i = 1; i < argc; ++i )
    {

        text += string(argv[i]) + " ";

    }

    cout << text << endl;

    return 0;
}

Ta wersja nie korzysta z niebezpiecznego wywołania strcat() i używa typu string, który automatycznie zarządza swoją pamięcią.

Testowanie programu potwierdza, że błąd w nim nie występuje:

new$ ./plik Ala ma kota.
Ala ma kota. 
new$ ./plik Ala w domu ma chomika, kota, rybki oraz psa.
Ala w domu ma chomika, kota, rybki oraz psa. 

Patch można wygenerować poleceniem diff. Korzystając ze składni zalecanej przez podręcznik użytkownika, będzie to wyglądało tak:

old$ LC_ALL=C TZ=UTC0 diff -Naur old new > plik.patch

Po wykonaniu tej komendy plik.patch będzie miał 543 bajty i następującą zawartość:

diff -Naur old/plik.C new/plik.C
--- old/plik.C  2004-08-11 11:44:16.000000000 +0000
+++ new/plik.C  2004-08-11 11:48:15.000000000 +0000
@@ -1,19 +1,21 @@
 #include <iostream>
+#include <string>
+
+using namespace std;

 int
 main ( int argc, char **argv)
 {
-    char text[20] = {0};
+    string text;

     for ( int i = 1; i < argc; ++i )
     {

-       strcat (text, argv[i]);
-       strcat (text, " ");
+       text += string(argv[i]) + " ";

     }

-    std::cout << text << std::endl;
+    cout << text << endl;

     return 0;
 }

Program gzip skompresował ten plik do 322 bajtów, czyli o 46%.

Zalety łatania kodu źródłowego[edytuj | edytuj kod]

Patche mają dwie ważne przewagi nad rozpowszechnianiem nowych wersji programu. Po pierwsze są mniejsze. Po drugie, o ile zmiany nie kolidują ze sobą, można zaaplikować kilka niezależnych patchy do tych samych źródeł.

Szerokie użycie patchy w świecie Uniksów umożliwia istnienie wielu wersji tego samego programu, które nie muszą być szczególnie koordynowane. Zwykle jedna wersja jest wersją „główną”, a inne są wersjami pochodnymi, rozpowszechnianymi tylko jako patch do odpowiedniej wersji głównej. W ten sposób działają prawie wszystkie dystrybucje, mając własne wersje rozwijanych zewnętrznie programów zintegrowane z resztą dystrybucji. Tak działa też rozwój Linuksa, gdzie poza główną wersją istnieje mnóstwo odgałęzień dystrybucyjnych lub modyfikujących jądro w pewnym kierunku (np. dodając eksperymentalny kod, poprawiając bezpieczeństwo, dostosowując do szczególnych warunków itd.). System patchy umożliwia takim wersjom pokojowe współistnienie bez konieczności dokonywania trwałych forków.

Zobacz też[edytuj | edytuj kod]