2016-04-14 14 views
5

Projekty o krytycznym znaczeniu dla bezpieczeństwa nie zalecają żadnych dynamicznych alokacji lub zwalniania przydzielonej pamięci. Tylko podczas fazy opracowania/inicjalizacji wykonania programu jest to dozwolone.Alternatywy dla alokacji dynamicznych w projektach krytycznych dla bezpieczeństwa (C)

Wiem, że większość z was będzie się spierać, aby wdrożyć SW w kategoriach, w których powinien wykonywać wszystkie alokacje statyczne lub w kodeksie uzasadnić, że alokacje dynamiczne nie zaszkodzą całemu programowi, itd., Ale wciąż, czy jest jakakolwiek alternatywa dla ten problem? Czy jest jakiś sposób lub dowolny przykład, aby przydzielić trochę pamięci (sterty) podczas inicjowania/tworzenia programu i alokować/zwolnić pamięć z tego miejsca? Lub jakiekolwiek rozwiązania/alternatywy dla tego problemu, jeśli naprawdę chcemy dynamiczne alokacje w projekcie (krytycznym pod względem bezpieczeństwa)?

Odpowiedz

10

Tego typu pytanie jest najczęściej zadawane przez programistów, którzy chcą mieć możliwość dynamicznego przydzielania pamięci w systemie bezpieczeństwa bez "nieuzasadnionych" ograniczeń - co często zdaje się oznaczać, że nie zapobiegają one dynamicznemu przydzielaniu pamięci w ilościach, które wybierają, kiedy wybierają i (ewentualnie) zwalniają tę pamięć, kiedy wybierają.

Zajmę się tym pytaniem (czy dynamiczny przydział pamięci może być użyty w krytycznym systemie bez ograniczeń?). Następnie wrócę do opcji obejmujących akceptację pewnych ograniczeń dotyczących sposobu (dynamicznego przydzielania pamięci).

W przypadku "projektu o kluczowym znaczeniu dla bezpieczeństwa" takie rzeczy na ogół nie są możliwe. Systemy związane z bezpieczeństwem na ogół mają obowiązkowe wymagania dotyczące łagodzenia lub eliminowania określonych zagrożeń. Niewłaściwe złagodzenie lub wyeliminowanie określonych zagrożeń (tj. Spełnienie wymagań) może spowodować szkody - na przykład śmierć lub zranienie ludzi. W takich systemach na ogół konieczne jest ustalenie, na pewnym poziomie rygoryzmu, że zagrożenia są odpowiednio i niezawodnie złagodzone lub wyeliminowane. Konsekwencją tego jest zwykle zestaw wymagań związanych z determinizmem - umiejętność określenia, za pomocą odpowiedniej analizy, że system wykonuje akcje w określony sposób - gdzie atrybuty takie jak zachowanie i czas są ściśle określone.

Jeśli dynamiczna alokacja pamięci jest używana bez ograniczeń, trudno jest określić, czy części systemu zachowują się zgodnie z wymaganiami. Rodzaje problemów obejmują;

  • Fragmentacja nieprzydzielonej pamięci. Nie można zagwarantować, że żądanie przydzielenia N sąsiadujących bajtów pamięci zakończy się pomyślnie, nawet jeśli dostępnych jest N bajtów pamięci. Jest to szczególnie prawdziwe, jeśli wcześniej przydzielono wiele alokacji i deallocations w dowolnej kolejności - nawet jeśli dostępne jest N bajtów pamięci, nie mogą one znajdować się w przyległej przesyłce.
  • Wystarczająca. Często trudno jest zapewnić, że krytyczna alokacja pamięci, która musi odnieść sukces, faktycznie się udaje.
  • Odpowiednie wydanie. Trudno jest zapobiec zwolnieniu pamięci, gdy jest ona nadal potrzebna (co skutkuje potencjalnym dostępem do pamięci, która została zwolniona) lub aby zagwarantować, że pamięć, która nie jest już potrzebna, jest faktycznie zwolniona (np. Zapobiec wyciekom pamięci).
  • Terminowość. Próby złagodzenia powyższych problemów oznaczają, że czas alokacji lub dealokacji jest zmienny, nieprzewidywalny, z potencjalnie bez górnej granicy. Przykłady metod radzenia sobie z nimi to defragmentacja (aby poradzić sobie z problemami fragmentacji) lub zbieranie śmieci (aby poradzić sobie z problemami z wystarczalnością i/lub z odpowiednią wersją). Te procesy wymagają czasu i innych zasobów systemowych. Jeśli zostaną one wykonane podczas próby alokacji, czas przydzielenia pamięci stanie się nieprzewidywalny.Jeśli są wykonywane po zwolnieniu pamięci, czas zwolnienia pamięci staje się nieprzewidywalny. Jeśli są wykonywane w innym czasie, zachowanie innego - potencjalnie krytycznego - kodu może stać się nieprzewidywalne (np. Świat skutecznie zamarza dla aplikacji).

Wszystkie te czynniki, i więcej, oznaczają, że nieograniczony dynamiczny przydział pamięci nie działa dobrze w zakresie wymagań dotyczących determinizmu czasu lub zużycia zasobów systemu. Z natury rzeczy wymagania systemowe wymagają nałożenia pewnych ograniczeń i, w zależności od systemu, egzekwowane.

Jeśli ograniczenia dotyczące dynamicznej alokacji pamięci są akceptowalne, istnieją opcje. Zasadniczo techniki te wymagają wsparcia zarówno pod względem ograniczeń politycznych, jak i rozwiązań technicznych, aby zachęcać (najlepiej egzekwować w systemach o wysokiej krytyczności) zgodność z tymi zasadami. Egzekwowanie polityki może mieć charakter techniczny (na przykład zautomatyzowane i ręczne projektowanie i przeglądy kodu, dostosowane środowiska programistyczne, testowanie zgodności itp.) Lub organizacyjne (np. Odwoływanie programistów, którzy świadomie zajmują się kluczowymi zasadami).

Przykłady technik obejmują;

  • Brak alokacji dynamicznej., tj. Tylko statyczne przydziały.
  • Używaj tylko dynamicznego przydzielania pamięci podczas inicjalizacji systemu. Wymaga to maksymalnej ilości pamięci, która musi zostać przydzielona do ustalenia z góry. Jeśli alokacja pamięci nie powiedzie się, potraktuj ją jak dowolną awarię POST (power-on-self-test).
  • Przydziel pamięć, ale nigdy jej nie zwolnij. Pozwala to uniknąć problemów związanych z fragmentacją, ale może utrudnić określenie górnej granicy wymaganej ilości pamięci przez system.
  • Niestandardowy przydział. System (lub aplikacja) jawnie zarządza dynamicznym przydzielaniem pamięci, zamiast korzystać z ogólnych funkcji bibliotecznych (na przykład związanych z wybranym językiem programowania). Zwykle oznacza to wprowadzenie niestandardowego programu przydzielającego i zabraniającego (lub wyłączającego) korzystania z ogólnych funkcji bibliotecznych do dynamicznego zarządzania pamięcią. Niestandardowy alokator musi być jawnie zaprojektowany pod kątem potrzeb konkretnego systemu.
  • Boks w zarządzaniu pamięcią. Jest to szczególny rodzaj przydziału niestandardowego, w którym aplikacja przydziela pulę pamięci, a funkcje żądają stałych kwot (lub wielokrotności stałych kwot) z puli. Ponieważ pula jest ustalana przez aplikację, aplikacja monitoruje ilość pamięci z puli i podejmuje działania w celu zwolnienia pamięci, jeśli pamięć jest wyczerpana. Alokacje i deallokacje z puli mogą być również wykonywane w sposób przewidywalny (ponieważ zarządzane są niektóre z bardziej ogólnych zagadnień związanych z dynamiczną alokacją pamięci). Systemy krytyczne mogą mieć wiele pul, z których każda może być używana wyłącznie przez określone zestawy funkcji.
  • Partycjonowanie. Jawnie zapobiega niekrytycznym funkcjom dostępu do pul pamięci, które zostały ustanowione do użycia przez funkcje krytyczne. Pozwala to uzyskać pewność, że krytyczne funkcje mogą uzyskać dostęp do potrzebnej pamięci, a także zapewnia, że ​​niepowodzenie funkcji o niskiej krytyczności nie może wywołać awarii o wysokiej funkcji krytycznej. Partycjonowanie może być wykonywane w aplikacji lub w (odpowiednio certyfikowanym) systemie operacyjnym hosta lub w obu ... .... w zależności od potrzeb systemu.

Niektóre z tych podejść można wykorzystać do wzajemnego wspierania się.