Warum ist es so schwierig, C weniger anfällig für Pufferüberläufe zu machen?

23

Ich mache einen College-Kurs, in dem eine der Übungen darin besteht, Pufferüberlauf-Exploits für Code durchzuführen, den sie uns geben. Dies reicht von einfachen Exploits wie dem Ändern der Rücksprungadresse für eine Funktion auf einem Stack, um zu einer anderen Funktion zurückzukehren, bis hin zu Code, der den Status eines Programmregisters / -speichers ändert, aber dann zu der von Ihnen aufgerufenen Funktion zurückkehrt Die von Ihnen aufgerufene Funktion kennt den Exploit nicht.

Ich habe einige Nachforschungen angestellt, und diese Arten von Exploits werden auch heute noch fast überall verwendet, zum Beispiel bei der Ausführung von Homebrew auf der Wii und dem Jailbreak ohne Tethering für iOS 4.3.1

Meine Frage ist, warum dieses Problem so schwer zu beheben ist? Es ist offensichtlich, dass dies ein wichtiger Exploit ist, der verwendet wird, um Hunderte von Dingen zu hacken, aber es scheint ziemlich einfach zu sein, Eingaben über die zulässige Länge hinaus zu kürzen und alle von Ihnen aufgenommenen Eingaben zu bereinigen.

BEARBEITEN: Eine andere Perspektive, über die ich Antworten haben möchte - warum beheben die Entwickler von C diese Probleme nicht, indem sie die Bibliotheken neu implementieren?

Ankit Soni
quelle

Antworten:

35

Sie haben die Bibliotheken repariert.

Jede modernen C - Standardbibliothek enthält sicherere Varianten strcpy, strcat, sprintf, und so weiter.

Auf C99-Systemen, bei denen es sich um die meisten Unix-Systeme handelt, finden Sie diese mit Namen wie strncatund snprintf, wobei das "n" angibt, dass ein Argument verwendet wird, das die Größe eines Puffers oder eine maximale Anzahl von Elementen hat, die kopiert werden sollen.

Diese Funktionen können verwendet werden, um viele Vorgänge sicherer abzuwickeln, aber im Nachhinein ist ihre Verwendbarkeit nicht großartig. Beispielsweise snprintfgarantieren einige Implementierungen nicht, dass der Puffer mit Null terminiert ist. strncatDas Kopieren erfordert eine Reihe von Elementen, aber viele Leute übergeben fälschlicherweise die Größe des Zielpuffers.

Unter Windows findet man oft die strcat_s, sprintf_sdie „_s“ Suffix , das „sicher“. Auch diese haben ihren Weg in die C-Standardbibliothek in C11 gefunden und bieten mehr Kontrolle darüber, was im Falle eines Überlaufs geschieht (z. B. Abschneiden vs. Bestätigen).

Viele Anbieter bieten noch mehr Nicht-Standard-Alternativen an, wie asprintfin der GNU libc, die automatisch einen Puffer mit der entsprechenden Größe zuweisen.

Die Idee, dass Sie "nur C reparieren" können, ist ein Missverständnis. C zu beheben ist nicht das Problem - und wurde bereits getan. Das Problem besteht darin, jahrzehntelangen C-Code zu reparieren, der von ignoranten, müden oder hastigen Programmierern geschrieben wurde, oder Code, der aus Kontexten portiert wurde, in denen Sicherheit keine Rolle spielte, in Kontexten, in denen Sicherheit keine Rolle spielt. Keine Änderungen an der Standardbibliothek können diesen Code beheben, obwohl die Migration auf neuere Compiler und Standardbibliotheken häufig dazu beiträgt, die Probleme automatisch zu identifizieren.


quelle
11
+1, um das Problem auf die Programmierer zu lenken, nicht auf die Sprache.
Nicol Bolas
8
@Nicol: Zu sagen "das Problem sind die Programmierer" ist unfair reduktionistisch. Das Problem ist, dass es jahrelang (Jahrzehnte) einfacher war, unsicheren Code als sicheren Code zu schreiben, zumal sich unsere Definition von "sicher" schneller entwickelte als jeder Sprachstandard, und dass es diesen Code immer noch gibt. Wenn Sie versuchen möchten, dies auf ein einziges Substantiv zu reduzieren, lautet das Problem "1970-1999 libc", nicht "die Programmierer".
1
Es liegt immer noch in der Verantwortung der Programmierer, die Tools zu verwenden, die sie jetzt haben, um diese Probleme zu beheben . Nehmen Sie sich etwa einen halben Tag Zeit und durchsuchen Sie den Quellcode nach diesen Dingen.
Nicol Bolas
1
@Nicol: Obwohl es trivial ist, einen möglichen Pufferüberlauf zu erkennen, ist es oft nicht trivial, sicherzugehen, dass es sich um eine echte Bedrohung handelt, und es ist weniger trivial, herauszufinden, was passieren soll, wenn der Puffer jemals überläuft. Fehlerbehandlung wird / wurde oft nicht berücksichtigt, es ist nicht möglich, eine Verbesserung "schnell" umzusetzen, da Sie das Verhalten eines Moduls auf unerwartete Weise ändern können. Wir haben dies gerade in einer Multi-Millionen-Zeilen-Legacy-Codebasis getan, und obwohl sich eine Übung lohnt, hat sie viel Zeit (und Geld) gekostet.
Mattnz
4
@NicolBolas: Ich bin mir nicht sicher, in welcher Art von Geschäft Sie arbeiten, aber der letzte Ort, an dem ich C für die Produktion geschrieben habe, erforderte eine Änderung des detaillierten Designdokuments, eine Überprüfung, eine Änderung des Codes, eine Änderung des Testplans, eine Überprüfung des Testplans und eine vollständige Durchführung Systemtest, Überprüfung der Testergebnisse und erneute Zertifizierung des Systems beim Kunden. Dies ist für ein Telekommunikationssystem auf einem anderen Kontinent gedacht, das für ein Unternehmen geschrieben wurde, das es nicht mehr gibt. Zuletzt wusste ich, dass sich die Quelle in einem RCS-Archiv auf einem QIC-Band befand, das noch lesbar sein sollte, wenn Sie ein geeignetes Bandlaufwerk finden.
TMN
19

Es ist nicht wirklich ungenau zu sagen , dass C tatsächlich „fehleranfällig“ durch ist Design . Abgesehen von einigen schwerwiegenden Fehlern wie gets, kann die C-Sprache nicht anders sein, ohne das Hauptmerkmal zu verlieren, das die Leute an erster Stelle zu C zieht.

C wurde als Systemsprache entwickelt, um als eine Art "tragbare Baugruppe" zu fungieren. Ein Hauptmerkmal der C-Sprache ist, dass C-Code im Gegensatz zu höheren Sprachen häufig sehr genau dem tatsächlichen Maschinencode zugeordnet ist. Mit anderen Worten, es ++ihandelt sich in der Regel nur um eine incAnweisung, und Sie können häufig anhand des C-Codes eine allgemeine Vorstellung davon bekommen, was der Prozessor zur Laufzeit tun wird.

Das Hinzufügen impliziter Grenzwertprüfungen erhöht jedoch den Overhead, den der Programmierer nicht verlangt hat und möglicherweise nicht wünscht. Dieser Overhead geht weit über den zusätzlichen Speicherplatz hinaus, der zum Speichern der Länge jedes Arrays erforderlich ist, oder über die zusätzlichen Anweisungen zum Überprüfen der Array-Grenzen bei jedem Array-Zugriff. Was ist mit Zeigerarithmetik? Oder was ist, wenn Sie eine Funktion haben, die einen Zeiger aufnimmt? Die Laufzeitumgebung kann nicht erkennen, ob dieser Zeiger innerhalb der Grenzen eines legitim zugewiesenen Speicherblocks liegt. Um dies zu verfolgen, benötigen Sie eine seriöse Laufzeitarchitektur, die jeden Zeiger mit einer Tabelle der aktuell zugewiesenen Speicherblöcke vergleicht. Zu diesem Zeitpunkt befinden wir uns bereits im Bereich der verwalteten Java / C # -Stil-Laufzeit.

Charles Salvia
quelle
12
Ehrlich gesagt, wenn die Leute fragen, warum C nicht "sicher" ist, frage ich mich, ob sie sich beschweren würden, dass die Versammlung nicht "sicher" ist.
Ben Brocka
5
Die Sprache C ähnelt einer tragbaren Baugruppe auf einem PDP-11-Gerät von Digital Equipment Corporation. Zur gleichen Zeit hatten die Burroughs-Maschinen eine Überprüfung der Array-Grenzen in der CPU, so dass es wirklich einfach war, Programme direkt einzulesen. Array-Überprüfungen der Hardwarelebensdauer von Rockwell Collins-Hardware (meistens in der Luftfahrt verwendet)
Tim Williscroft,
15

Ich denke , das eigentliche Problem ist , zu beheben nicht , dass diese Art von Fehlern hart ist, aber dass sie so einfach zu machen: Wenn Sie verwenden strcpy, sprintfund Freunde in die (scheinbar) einfachste Art und Weise, arbeiten kann, dann haben Sie wahrscheinlich öffnete die Tür für einen Pufferüberlauf. Und niemand wird es bemerken, bis jemand es ausnutzt (es sei denn, Sie haben sehr gute Codeüberprüfungen). Fügen Sie jetzt die Tatsache hinzu, dass es viele mittelmäßige Programmierer gibt und dass sie die meiste Zeit unter Zeitdruck stehen - und Sie haben ein Rezept für Code, das so voller Pufferüberläufe ist, dass es schwierig sein wird, sie alle zu beheben, nur weil es solche gibt so viele von ihnen und sie verstecken sich so gut.

Nikie
quelle
3
"Sehr gute Code-Reviews" braucht man eigentlich nicht. Sie müssen nur sprintf verbieten oder sprintf auf einen Wert umdefinieren, der sizeof () und Fehler in Bezug auf die Größe eines Zeigers usw. verwendet. Sie benötigen nicht einmal Codeüberprüfungen. Sie können solche Dinge mit SCM-Commit ausführen Haken und Grep.
1
@ JoeWreschnig: sizeof(ptr)ist in der Regel 4 oder 8. Dies ist eine weitere C-Einschränkung: Es gibt keine Möglichkeit, die Länge eines Arrays zu bestimmen, wenn nur der Zeiger darauf angegeben wird.
MSalters
@MSalters: Ja, ein Array von int [1] oder char [4] oder was auch immer kann falsch positiv sein, aber in der Praxis werden mit diesen Funktionen niemals Puffer dieser Größe verarbeitet. (Ich spreche hier theoretisch nicht - ich habe vier Jahre lang an einer großen C-Codebasis gearbeitet, die diesen Ansatz verwendet hat. Ich bin nie auf die Beschränkung gestoßen, in ein Zeichen [4] zu
5
@BlackJack: Die meisten Programmierer sind nicht dumm - wenn Sie sie zwingen, die Größe zu überschreiten, werden sie die richtige übergeben. Es ist nur das Meiste, das die Größe nicht überschreitet, wenn es nicht dazu gezwungen wird. Sie können ein Makro schreiben, das die Länge eines Arrays zurückgibt, wenn es statisch oder automatisch dimensioniert ist, aber Fehler, wenn ein Zeiger angegeben wird. Dann # definieren Sie sprintf neu, um snprintf mit diesem Makro aufzurufen, das die Größe angibt. Sie haben jetzt eine Version von sprintf, die nur auf Arrays mit bekannten Größen funktioniert und den Programmierer dazu zwingt, snprintf mit einer manuell festgelegten Größe aufzurufen.
1
Ein einfaches Beispiel für ein solches Makro wäre, #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]) / (sizeof(a) != sizeof(void *))das eine Division durch Null während der Kompilierung auslöst. Eine andere clevere, die ich zum ersten Mal in Chromium gesehen habe, ist #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]) / !(sizeof(a) % sizeof((a)[0]))die, bei der eine Handvoll falscher Positive gegen einige falsche Negative getauscht werden - für char [] ist sie leider nutzlos. Sie können verschiedene Compiler-Erweiterungen verwenden, um die Zuverlässigkeit zu erhöhen , z . B. blogs.msdn.com/b/ce_base/archive/2007/05/08/… .
7

Es ist schwierig, Pufferüberläufe zu beheben, da C praktisch keine nützlichen Tools zur Behebung des Problems bietet. Es ist ein grundlegender Sprachfehler, dass die nativen Puffer keinen Schutz bieten und es praktisch, wenn nicht sogar vollständig, unmöglich ist, sie durch ein überlegenes Produkt zu ersetzen, wie es C ++ mit std::vectorund getan hat std::array, und es ist selbst im Debug-Modus schwierig, Pufferüberläufe zu finden.

DeadMG
quelle
13
"Sprachfehler" ist eine schrecklich voreingenommene Behauptung. Dass die Bibliotheken keine Grenzkontrollen durchführten, war ein Fehler. dass die Sprache keine bewusste Wahl ist, um Overhead zu vermeiden. Diese Wahl ist Teil dessen, was ermöglicht, dass Konstrukte höherer Ebenen std::vectoreffizient implementiert werden. Und vector::operator[]macht die gleiche Wahl für Geschwindigkeit über Sicherheit. Die Sicherheit besteht vectordarin, dass das Karren um die Größe erleichtert wird, wie es auch in modernen C-Bibliotheken der Fall ist.
1
@Charles: "C bietet keine dynamisch expandierenden Puffer als Teil der Standardbibliothek." Nein, das hat nichts damit zu tun. Erstens stellt C sie über zur Verfügung realloc(C99 ermöglicht es Ihnen auch, Stack-Arrays mithilfe einer laufzeitbestimmten, aber konstanten Größe über eine beliebige automatische Variable zu dimensionieren, die fast immer bevorzugt wird char buf[1024]). Zweitens hat das Problem nichts mit dem Erweitern von Puffern zu tun. Es hat damit zu tun, ob Puffer die Größe mit sich führen und diese Größe prüfen, wenn Sie darauf zugreifen.
5
@ Joe: Das Problem ist nicht so sehr, dass native Arrays defekt sind. Es ist so, dass sie unmöglich zu ersetzen sind. Für den Anfang vector::operator[]macht die Überprüfung Grenzen im Debug - mode- etwas nativen Arrays nicht do- und zweitens können, gibt es keine Möglichkeit , in C auszulagern den nativen Array - Typen mit einem, kann die Überprüfung der Grenzen tun, denn es gibt keine Vorlagen ist und keinen Operator Überlastung. In C ++, wenn Sie von zu verschiebe T[]zu std::array, können Sie praktisch tauschen nur ein typedef. In C gibt es keine Möglichkeit, dies zu erreichen, und es gibt keine Möglichkeit, eine Klasse mit äquivalenter Funktionalität zu schreiben, geschweige denn eine Schnittstelle.
DeadMG
3
@ Joe: Außer es kann niemals eine statische Größe haben und man kann es niemals generisch machen. Es ist unmöglich , eine Bibliothek in C zu schreiben , die die gleiche Rolle wird erreicht , daß std::vector<T>und std::array<T, N>tut in C ++. Es gäbe keine Möglichkeit, eine Bibliothek zu entwerfen und anzugeben, auch keine Standardbibliothek, die dies könnte.
DeadMG
1
Ich bin nicht sicher, was Sie mit "es kann niemals statisch dimensioniert werden" meinen. Wie ich diesen Begriff benutze, std::vectorkann er auch niemals statisch dimensioniert werden. Was generisches betrifft, können Sie es so generisch machen, wie es gut sein muss. C benötigt es - eine kleine Anzahl grundlegender Operationen für void * (Hinzufügen, Entfernen, Ändern der Größe) und alles andere, was speziell geschrieben wurde. Wenn Sie sich darüber beschweren, dass C keine Generika im C ++ - Stil enthält, liegt dies weit außerhalb des Rahmens der sicheren Pufferbehandlung.
7

Das Problem liegt nicht in der C- Sprache .

IMO, das einzige große Hindernis, das es zu überwinden gilt, ist, dass C einfach schlecht unterrichtet ist . Jahrzehntelange Missbräuche und falsche Informationen wurden in Referenzhandbüchern und Vorlesungsskripten verankert und haben den Verstand jeder neuen Generation von Programmierern von Anfang an vergiftet. Die Schüler erhalten eine kurze Beschreibung der "einfachen" E / A-Funktionen wie gets1 oder scanfund werden dann ihren eigenen Geräten überlassen. Ihnen wird nicht gesagt, wo oder wie diese Tools ausfallen können oder wie diese Ausfälle verhindert werden können. Ihnen wird nicht gesagt, wie man fgetsund benutztstrtol/strtodweil diese als "fortgeschrittene" Werkzeuge gelten. Dann werden sie in die Berufswelt entlassen, um ihr Chaos anrichten zu können. Nicht viele der erfahreneren Programmierer wissen es besser, weil sie die gleiche gehirngeschädigte Ausbildung erhalten haben. Es ist verrückt. Ich sehe hier und auf Stack Overflow und auf anderen Websites so viele Fragen, bei denen klar ist, dass die Person, die die Frage stellt, von jemandem unterrichtet wird, der einfach nicht weiß, wovon er spricht , und natürlich kann man das nicht einfach sagen "Ihr Professor ist falsch", weil er ein Professor ist und Sie nur ein Typ im Internet sind.

Und dann haben Sie die Menge, die jede Antwort, die mit "nun ja, gemäß dem Sprachstandard ..." beginnt, verachtet, weil sie in der realen Welt arbeiten und gemäß ihnen der Standard nicht für die reale Welt gilt . Ich kann mit jemandem umgehen, der nur eine schlechte Ausbildung hat, aber jeder, der darauf besteht , unwissend zu sein, ist nur eine Panne für die Branche.

Es würde keine Pufferüberlaufprobleme geben, wenn die Sprache korrekt unterrichtet würde , wobei der Schwerpunkt auf dem Schreiben von sicherem Code liegt. Es ist nicht "schwer", es ist nicht "fortgeschritten", es ist nur vorsichtig.

Ja, das war eine Schande.


1 Zum Glück wurde es endgültig aus der Sprachspezifikation gestrichen, obwohl es in 40 Jahren alten Codes für immer lauern wird.

John Bode
quelle
1
Obwohl ich Ihnen größtenteils zustimme, denke ich, dass Sie immer noch ein bisschen unfair sind. Was wir als "sicher" betrachten, ist auch eine Funktion der Zeit (und ich sehe, dass Sie viel länger als ich ein professioneller Softwareentwickler waren, also bin ich sicher, dass Sie damit vertraut sind). In zehn Jahren wird jemand dasselbe Gespräch darüber führen, warum zum Teufel 2012 alle DoS-fähige Hash-Tabellenimplementierungen verwendet haben, wussten wir nichts über Sicherheit? Wenn es ein Problem im Unterrichten gibt, ist es ein Problem, dass wir uns zu sehr auf das Unterrichten von "bester" Praxis konzentrieren und nicht, dass sich die beste Praxis selbst entwickelt.
1
Und seien wir ehrlich. Sie könnten mit nur sicheren Code schreiben sprintf, aber das bedeutet nicht, dass die Sprache nicht fehlerhaft ist. C war fehlerhaft und ist fehlerhaft - wie jede Sprache - und es ist wichtig, dass wir diese Fehler zugeben, damit wir sie weiterhin beheben können.
@JoeWreschnig - Obwohl ich dem größeren Punkt zustimme, gibt es meiner Meinung nach einen qualitativen Unterschied zwischen DoS-fähigen Hashtabellenimplementierungen und Pufferüberläufen. Ersteres kann auf Umstände zurückgeführt werden, die sich um Sie herum entwickeln, während das Zweite keine Ausreden hat. Pufferüberläufe sind Codierungsfehler, Punkt. Ja, C hat keinen Klingenschutz und schneidet Sie, wenn Sie unachtsam sind. Wir können darüber streiten, ob dies ein Sprachfehler ist oder nicht. Das ist , die orthogonal zu der Tatsache , dass nur sehr wenige Studenten gegeben sind alle Sicherheitshinweise , wenn sie die Sprache noch lernen.
John Bode
5

Das Problem liegt in der Kurzsichtigkeit des Managements und nicht in der Inkompetenz der Programmierer. Denken Sie daran, dass eine Anwendung mit 90.000 Zeilen nur einen unsicheren Vorgang benötigt, um vollständig unsicher zu sein. Es ist fast unmöglich, dass eine Anwendung, die über eine grundlegend unsichere String-Behandlung geschrieben wurde, zu 100% perfekt ist - was bedeutet, dass sie unsicher ist.

Das Problem ist, dass die Kosten für die Unsicherheit entweder nicht dem richtigen Adressaten in Rechnung gestellt werden (das Unternehmen, das die App verkauft, muss den Kaufpreis so gut wie nie erstatten) oder zum Zeitpunkt der Entscheidungsfindung nicht klar ersichtlich sind ("Wir müssen versenden") im März egal was! "). Ich bin mir ziemlich sicher, dass das Schreiben in C oder verwandten Sprachen viel teurer wäre, wenn Sie die langfristigen Kosten und Kosten für Ihre Benutzer berücksichtigt hätten und nicht für Ihr Unternehmen. Wahrscheinlich so teuer, dass es in vielen Fällen eindeutig die falsche Wahl ist Felder, in denen heutzutage konventionelle Weisheit sagt, dass es eine Notwendigkeit ist. Dies wird sich jedoch erst ändern, wenn eine strengere Softwarehaftpflicht eingeführt wird - was niemand in der Branche wünscht.

Kilian Foth
quelle
-1: Das Management als die Wurzel allen Übels zu beschuldigen, ist nicht besonders konstruktiv. Die Geschichte etwas weniger ignorieren. Die Antwort ist fast durch den letzten Satz abgelöst.
Mattnz
Eine strengere Haftung für Software könnte von Benutzern eingeführt werden, die an Sicherheit interessiert sind und bereit sind, dafür zu zahlen. Möglicherweise könnte dies durch schwerwiegende Strafen für Sicherheitsverletzungen eingeleitet werden. Eine marktbasierte Lösung würde funktionieren, wenn die Benutzer bereit wären, für die Sicherheit zu zahlen, dies jedoch nicht.
David Thornley
4

Eine der großen Stärken von C ist, dass Sie damit das Gedächtnis so manipulieren können, wie Sie es für richtig halten.

Eine der großen Schwächen bei der Verwendung von C ist, dass Sie damit das Gedächtnis so manipulieren können, wie Sie es für richtig halten.

Es gibt sichere Versionen von unsicheren Funktionen. Programmierer und Compiler erzwingen ihre Verwendung jedoch nicht strikt.

Sardathrion - Setzen Sie Monica wieder ein
quelle
2

Warum beheben die Entwickler von C diese Probleme nicht, indem sie die Bibliotheken neu implementieren?

Wahrscheinlich, weil C ++ dies bereits getan hat und abwärtskompatibel mit C-Code ist. Wenn Sie also einen sicheren Zeichenfolgentyp in Ihren C-Code einfügen möchten, verwenden Sie einfach std :: string und schreiben Ihren C-Code mit einem C ++ - Compiler.

Das zugrunde liegende Speichersubsystem kann dazu beitragen, Pufferüberläufe zu verhindern, indem Schutzblöcke eingeführt und deren Gültigkeit überprüft werden. Bei allen Zuordnungen werden also 4 Byte 'fefefefe' hinzugefügt. Wenn in diese Blöcke geschrieben wird, kann das System einen Wobbler auslösen. Es ist nicht garantiert, dass ein Speicherschreiben verhindert wird, aber es zeigt, dass ein Fehler aufgetreten ist und behoben werden muss.

Ich denke, das Problem ist, dass die alten strcpy usw.-Routinen noch vorhanden sind. Wenn sie zugunsten von strncpy usw. entfernt würden, würde das helfen.

gbjbaanb
quelle
1
Das vollständige Entfernen von strcpy usw. würde inkrementelle Upgrade-Pfade noch schwieriger machen, was wiederum dazu führen würde, dass Benutzer überhaupt kein Upgrade durchführen. So wie es jetzt gemacht wird, können Sie zu einem C11-Compiler wechseln, dann _s-Varianten verwenden, dann Nicht-_s-Varianten sperren und dann die vorhandene Nutzung korrigieren, unabhängig davon, wie lange dies praktikabel ist.
-2

Es ist leicht zu verstehen, warum das Überlaufproblem nicht behoben ist. C war in einigen Bereichen fehlerhaft. Zu der Zeit wurden diese Mängel als erträglich oder sogar als Merkmal angesehen. Jetzt, Jahrzehnte später, sind diese Mängel nicht mehr zu beheben.

Einige Teile der Programmiergemeinschaft möchten nicht, dass diese Löcher verstopft werden. Schauen Sie sich alle Flammenkriege an, die über Strings, Arrays, Zeiger, Garbage Collection ... beginnen.

mhoran_psprep
quelle
5
LOL, schreckliche und falsche Antwort.
Heath Hunnicutt
1
Um zu erklären, warum dies eine schlechte Antwort ist: C hat in der Tat viele Mängel, aber das Zulassen von Pufferüberläufen usw. hat sehr wenig damit zu tun, sondern mit den grundlegenden Sprachanforderungen. Es wäre nicht möglich, eine Sprache für die Arbeit von C zu entwerfen und keinen Pufferüberlauf zuzulassen. Teile der Community möchten nicht auf die Fähigkeiten verzichten, die C ihnen bietet, oft aus gutem Grund. Es gibt auch Meinungsverschiedenheiten darüber, wie einige dieser Probleme vermieden werden können. Dies zeigt, dass wir kein vollständiges Verständnis für das Design von Programmiersprachen haben, mehr nicht.
David Thornley
1
@DavidThornley: Man könnte eine Sprache entwerfen, um die Arbeit von C zu erledigen, aber sie so gestalten, dass die normale idiomatische Vorgehensweise es einem Compiler zumindest ermöglicht , Pufferüberläufe einigermaßen effizient zu überprüfen, falls der Compiler dies wählt. Es gibt einen großen Unterschied zwischen der memcpy()Verfügbarkeit und der Tatsache, dass dies nur die Standardmethode zum effizienten Kopieren eines Arraysegments ist.
Supercat