In primo luogo, come altri hanno già detto, C / C ++ è talvolta caratterizzato come un macro assemblatore glorificato: è pensato per essere "vicino al ferro", come linguaggio per la programmazione a livello di sistema.
Quindi, ad esempio, il linguaggio mi permette di dichiarare una matrice di lunghezza zero come segnaposto quando, in effetti, può rappresentare una sezione di lunghezza variabile in un pacchetto di dati o l'inizio di una regione di lunghezza variabile nella memoria che è usato per comunicare con un pezzo di hardware.
Sfortunatamente significa anche che C / C ++ è pericoloso nelle mani sbagliate; se un programmatore dichiara un array di 10 elementi e poi scrive nell'elemento 101, il compilatore lo compilerà felicemente, il codice eseguirà felicemente, cestinando qualunque cosa si trovi in quella posizione di memoria (codice, dati, stack, chissà.)
In secondo luogo, C / C ++ è idiosincratico. Un buon esempio sono le stringhe, che sono fondamentalmente array di caratteri. Ma ogni costante di stringa porta un carattere di terminazione aggiuntivo, invisibile. Questa è stata la causa di innumerevoli errori in quanto (soprattutto, ma non esclusivamente) i programmatori inesperti spesso non riescono ad allocare quel byte in più necessario per terminare il nulla.
In terzo luogo, C / C ++ è piuttosto vecchio. Il linguaggio è nato in un momento in cui gli attacchi esterni a un sistema software erano praticamente inesistenti. Ci si aspettava che gli utenti fossero fidati e cooperativi, non ostili, poiché il loro obiettivo era quello di far funzionare il programma, non di mandarlo in crash.
Ecco perché la libreria standard C / C ++ contiene molte funzioni intrinsecamente insicure. Prendi strcpy (), per esempio. Copierà felicemente qualsiasi cosa fino a quando un carattere null terminante. Se non trova un carattere nullo terminante, continuerà a copiare finché l'inferno si blocca, o più probabilmente, finché non sovrascrive qualcosa di vitale e il programma si blocca. Questo non era un problema nei bei vecchi tempi, quando, non ci si aspettava che un utente entrasse in un campo riservato, ad esempio, a un codice postale, 16000 caratteri illeggibili seguito da un set di byte appositamente progettato che doveva essere eseguito dopo che lo stack è stato cestinato e il processore ha ripreso l'esecuzione all'indirizzo sbagliato.
Solo per essere sicuri, C / C ++ non è l'unico linguaggio idiosincratico là fuori. Altri sistemi hanno comportamenti idiosincratici diversi, ma possono essere altrettanto negativi. Prendi linguaggi di programmazione back-end come PHP e quanto è facile scrivere codice che consente l'iniezione SQL.
Alla fine, se diamo ai programmatori i potenti strumenti di cui hanno bisogno per svolgere il loro lavoro, ma senza un'adeguata formazione e consapevolezza dell'ambiente di sicurezza, le cose brutte accadranno indipendentemente dal linguaggio di programmazione utilizzato.