2016-04-14 15 views
5

I progetti critici di sicurezza non consigliano allocazioni dinamiche o liberano memoria allocata. È consentito solo durante la fase di elaborazione/inizializzazione dell'esecuzione del programma.Alternative a allocazioni dinamiche in progetti di sicurezza critici (C)

So che la maggior parte di voi sosterrà l'implementazione del SW in termini in cui dovrebbe fare solo tutte le allocazioni statiche o fare qualche giustificazione nel codice che le allocazioni dinamiche non danneggeranno il programma generale, ecc. Ma, tuttavia, esiste un'alternativa al questo problema? C'è un modo o un esempio per assegnare una memoria (heap) durante l'inizializzazione/elaborazione del programma e allocare/deallocare la memoria da lì? O eventuali soluzioni/alternative a questo problema se vogliamo davvero allocazioni dinamiche nel progetto (safety critical)?

risposta

10

Questo tipo di domanda viene posta più spesso dagli sviluppatori che vogliono essere in grado di utilizzare l'allocazione dinamica della memoria all'interno di un sistema di sicurezza senza restrizioni "indebite" - il che spesso sembra significare che non viene impedito dall'allocazione dinamica della memoria nelle quantità che scelgono, quando scelgono, e (eventualmente) liberano quel ricordo quando scelgono.

Mi occuperò di questa domanda (l'allocazione dinamica della memoria può essere utilizzata in un sistema critico senza restrizioni?) Prima. Quindi tornerò alle opzioni che comportano l'accettazione di alcune restrizioni su come (quando, o se) viene utilizzata l'allocazione dinamica della memoria.

All'interno di un "progetto critico per la sicurezza", una cosa del genere non è generalmente possibile. I sistemi relativi alla sicurezza in genere hanno requisiti obbligatori relativi alla mitigazione o all'eliminazione dei rischi specificati. La mancata adeguata attenuazione o eliminazione dei rischi specificati (ad esempio per soddisfare i requisiti) può causare danni, ad esempio, la morte o la ferita di persone. In tali sistemi, è generalmente necessario determinare, con un certo livello di rigore, che i pericoli siano adeguatamente mitigati o eliminati in modo affidabile. Una conseguenza di ciò è tipicamente un insieme di requisiti relativi al determinismo - la capacità di determinare, attraverso un'analisi appropriata, che il sistema completi le azioni in un modo specificato - dove attributi come il comportamento e i tempi sono strettamente specificati.

Se l'allocazione della memoria dinamica viene utilizzata senza restrizioni, è difficile determinare se le parti del sistema si comportano come richiesto. I tipi di problemi includono;

  • Frammentazione della memoria non allocata. Non è possibile garantire che una richiesta di allocazione di N byte contigui di memoria abbia esito positivo, anche se sono disponibili N byte di memoria. Ciò è particolarmente vero se in precedenza sono state assegnate allocazioni e deallocazioni multiple in ordine arbitrario - anche se sono disponibili N byte di memoria, potrebbero non essere in un pacchetto contiguo.
  • Sufficienza. Spesso è difficile fornire una garanzia che un'allocazione di memoria critica, che deve avere successo, abbia effettivamente successo.
  • Rilascio appropriato. È difficile evitare che la memoria venga rilasciata mentre è ancora necessaria (con conseguente possibilità di accedere alla memoria che è stata deallocata) o per garantire che la memoria che non è più necessaria sia effettivamente rilasciata (ad esempio, impedire perdite di memoria).
  • Tempestività. I tentativi di attenuare i problemi precedenti indicano che il tempo di un'allocazione o di una deallocazione è variabile, imprevedibile, con potenziale limite superiore. Esempi di approcci per affrontarli sono la deframmentazione (per affrontare i problemi di frammentazione) o la raccolta dei rifiuti (per affrontare i problemi con sufficienza e/o con rilascio appropriato). Questi processi richiedono tempo e altre risorse di sistema. Se sono fatti quando si tenta un'allocazione, il tempo di allocare la memoria diventa imprevedibile.Se sono fatti per liberare memoria, il tempo per rilasciare la memoria diventa imprevedibile. Se vengono eseguiti in altri momenti, il comportamento di un altro codice potenzialmente critico potrebbe diventare imprevedibile (ad esempio il mondo si blocca effettivamente per l'applicazione).

Tutti questi fattori, e altri ancora, significano che l'allocazione dinamica illimitata della memoria non funziona bene nei requisiti per la determinazione del tempo o dell'utilizzo delle risorse del sistema. Intrinsecamente, i requisiti di sistema richiedono che vengano imposte alcune restrizioni e, in base al sistema, applicate.

Se le restrizioni sull'allocazione della memoria dinamica sono accettabili, ci sono opzioni. Generalmente, queste tecniche richiedono supporto sia in termini di vincoli politici che di soluzioni tecniche per incoraggiare (preferibilmente applicare, in sistemi con alta criticità) la conformità a tali politiche. L'applicazione delle norme può essere tecnica (ad esempio progettazione automatizzata e manuale e revisioni di codici, ambienti di sviluppo personalizzati, test di conformità, ecc. Ecc.) O organizzativi (ad esempio, gli sviluppatori che risolvono intenzionalmente le policy chiave).

Esempi di tecniche includono;

  • Assenza di allocazione dinamica., ad esempio solo allocazioni statiche.
  • Utilizzare solo l'allocazione della memoria dinamica durante l'inizializzazione del sistema. Ciò richiede la quantità massima di memoria che deve essere assegnata per essere determinata in anticipo. Se l'allocazione della memoria fallisce, trattala come qualsiasi errore POST (power-on-self-test).
  • Assegna memoria ma non rilasciarlo mai. Questo tende ad evitare problemi di frammentazione, ma può rendere più difficile determinare un limite superiore su quanta memoria è necessaria al sistema.
  • Allocazione personalizzata. Il sistema (o l'applicazione) gestisce esplicitamente l'allocazione dinamica della memoria, piuttosto che l'uso di funzioni di libreria generiche (ad esempio quelle associate al linguaggio di programmazione scelto). Questo di solito significa introdurre un allocatore personalizzato e vietare (o disabilitare) l'uso di funzioni di libreria generiche per la gestione dinamica della memoria. L'allocatore personalizzato deve essere progettato in modo esplicito tenendo conto delle esigenze del particolare sistema.
  • Boxing nella gestione della memoria. Questo è un particolare tipo di allocazione personalizzata, in cui l'applicazione alloca un pool di memoria e le funzioni richiedono importi fissi (o multipli di importi fissi) dal pool. Poiché il pool viene riparato dall'applicazione, l'applicazione controlla la quantità di memoria disponibile dal pool e intraprende azioni per liberare memoria se la memoria è esaurita. Anche allocazioni e deallocations dal pool possono essere eseguite in modo prevedibile (poiché vengono gestiti alcuni dei problemi più generali relativi all'assegnazione dinamica della memoria). I sistemi critici possono avere più pool, ciascuno per uso esclusivo da specifici gruppi di funzioni.
  • Partizionamento. Impedisce esplicitamente alle funzioni non critiche di accedere a pool di memoria che sono stati stabiliti per l'utilizzo da parte di funzioni critiche. Ciò consente di garantire che le funzioni critiche possano accedere alla memoria di cui hanno bisogno e inoltre garantisce che il malfunzionamento di una funzione a bassa criticità non possa innescare il fallimento di una funzione di alta criticità. Il partizionamento può essere eseguito all'interno di un'applicazione, o all'interno di un sistema operativo host (opportunamente certificato), o entrambi ... in base alle esigenze del sistema.

Alcuni di questi approcci possono essere utilizzati per sostenersi a vicenda.