In primo luogo, come altri hanno già detto, C / C ++ è talvolta caratterizzato come un glorificato macro assembler: è pensato per essere "vicino al ferro", come linguaggio per la programmazione a livello di sistema.
Quindi, ad esempio, il linguaggio mi consente di dichiarare un array di lunghezza zero come segnaposto quando, in realtà, può rappresentare una sezione di lunghezza variabile in un pacchetto di dati o l'inizio di una regione di lunghezza variabile nella memoria che viene utilizzata per comunicare con un componente 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 verrà eseguito felicemente, eliminando qualunque cosa accada in quella posizione di memoria (codice, dati, stack, chi lo sa.)
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 invisibile aggiuntivo. Questa è stata la causa di innumerevoli errori in quanto (soprattutto, ma non esclusivamente) i programmatori inesperti spesso non riescono ad allocare quel byte aggiuntivo necessario per il null di terminazione.
Terzo, C / C ++ è in realtà piuttosto vecchio. Il linguaggio è nato in un momento in cui gli attacchi esterni a un sistema software erano praticamente inesistenti. Gli utenti dovevano essere affidabili e collaborativi, non ostili, poiché il loro obiettivo era far funzionare il programma, non bloccarlo.
Ecco perché la libreria C / C ++ standard contiene molte funzioni che sono intrinsecamente non sicure. Prendi strcpy (), per esempio. Copierà felicemente qualsiasi cosa fino a quando un carattere nullo terminante. Se non trova un carattere nullo di terminazione, continuerà a copiare finché l'inferno non si congela, o più probabilmente, finché non sovrascrive qualcosa di vitale e il programma si blocca. Questo non era un problema ai bei vecchi tempi, quando non ci si aspettava che un utente entrasse in un campo riservato, ad esempio, a un codice postale, 16000 caratteri spazzatura seguiti da un insieme di byte appositamente costruito che dovevano essere eseguiti dopo che lo stack è stato eliminato e il processore ha ripreso l'esecuzione all'indirizzo sbagliato.
Giusto per essere sicuri, C / C ++ non è l'unico linguaggio idiosincratico là fuori. Altri sistemi hanno un comportamento idiosincratico diverso, ma può essere altrettanto negativo. Prendi i linguaggi di programmazione back-end come PHP e quanto è facile scrivere codice che consenta l'iniezione SQL.
Alla fine, se diamo ai programmatori i potenti strumenti di cui hanno bisogno per fare il loro lavoro, ma senza una formazione adeguata e consapevolezza dell'ambiente di sicurezza, le cose brutte accadranno indipendentemente dal linguaggio di programmazione utilizzato.