Le funzioni delle librerie
C Run-Time (o CRT) come
memcpy, risalgono ad un tempo in cui era di moda portare i capelli lunghi e saltare le vocali per i nomi delle funzioni. Queste funzioni sono state concepite in un mondo a
bassa connettività. A quel tempo non c'erano malintenzionati che analizzavano tutte le porte dei PC, attraverso una connessione broadband, alla ricerca di vulnerabilità nei software (tipo i famosi
buffer overrun). Erano i
tempi d'oro delle run-time C ed il peggior danno, che poteva causare un buffer overrun, era un crash del sistema.
Ma quei tempi sono ormai passati. I costo dei danni causati da un attacco massiccio da parte di virus come Slummer o Red Code (che sfruttano la vulnerabilità di un buffer overrun) è pari a quello di un disastro nucleare: il worm Code Red ha causato danni pari a circa 2.6 miliardi di dollari. Circa 973 milioni di dollari il danno provocato dal meno famoso Three Mile Island, almeno
secondo quanto riportato da News.com. Fortunatamente, l'uso delle funzioni CRT, che rendono più probabile un buffer overrun, non è più richiesto e vi sono in ogni caso alternative più sicure. Le funzioni CRT non sicure, sono considerate oggi
Legacy Code.
Chi decidesse oggi di creare
from scratch un progetto in C++, troverebbe poco utile l'uso delle librerie CRT. Le librerie standard C++, quelle del .NET Framework e molte altre di terze parti, offrono maggiori funzionalità e facilità d'uso se paragonate alle CRT. Sfortunatamente, molti sviluppatori, hanno una grossa quantità di codice già scritto da mantenere ed estendere, codice che talvolta fa uso di CRT.
Visual C++ fornisce funzioni estese che offrono con le medesime funzioni di CRT ma con una più vasta rete di sicurezza per prevenire errori comuni che malintenzionati potrebbero sfruttare.
Consideriamo la venerabile e largamente usata funzione
memcpy che permette la copia del contenuto di un buffer all'interno di un altro. La funzione
memcopy standard ha il seguente prototipo:
void *memcpy(void *dest, const void *src, size_t count);
La funzione in oggetto ha il seguente problema: la dimensione del buffer di destinazione non è mai specificata. Questo significa che non è possibile implementare un controllo di sicurezza, il quale verifichi che il buffer di destinazione sia grosso abbastanza per ricevere i dati. Qualsiasi sviluppatore sensibile, naturalmente, controllerà che il buffer di destinazione sia grande a sufficienza, ma l'esperienza ha dimostrato che nel corso dello sviluppo di un grosso progetto, a cui facciano seguito diverse release, sapere quale parte del codice è responsabile di fare questo controllo, può diventare poco chiaro. Come risultato, il controllo stesso potrebbe mancare totalmente, rendendo così il programma vulnerabile.
La versione estesa di questa CRT, aggiunge un
_s al nome della funziona e con esso anche un nuovo parametro che permette di specificare la dimensione del buffer di destinazione. La funzione CRT può quindi effettuare un controllo veloce che assicura che la dimensione del buffer di destinazione sia sufficiente ad allocare il numero di byte che necessitano di essere copiati.
In molti casi, questo controllo delle dimensioni del buffer di destinazione, occorrerà già nel codice che richiama funzioni come
memcpy, ma nei casi dove programmazione sciatta o errori di mantenimento hanno trascurato di includere il controllo, la nuova funzione lo effettuerà automaticamente. Il prototipo modificato è il seguente:
errno_t memcpy_s(void *dest, size_t sizeInBytes, const void *src, size_t count);
Da notare che il valore di ritorno è stato cambiato da
puntatore (nel caso della funzione
memcpy), a
codice di errore (nel caso della funzione
memcpy_s). Se il buffer di destinazione non è di dimensioni sufficienti, quando viene fatta una chiamata a
memcpy_s viene invocato l'handler di parametro non valido.
Mentre la conversione alle funzioni CRT sicure è generalmente una buona idea, il lavoro che bisogna fare per identificare tutte le funzioni CRT, le quali adesso anno una versione
sicura, trovare tutte le istanze di queste funzioni in una grossa mole di codice e quindi convertirle, è un grosso lavoro. A tale proposito potete rifarvi
alla lista completa delle funzioni CRT. La lista è piuttosto lunga, ma fortunatamente il compilatore segnala l'uso della versione non sicura di molte funzioni CRT che hanno una corrispondente versione sicura. Questo significa che il compilatore produrrà un warning ogni volta che una di queste funzioni deprecate viene utilizzata.