Warum ist die Funktion gets so gefährlich, dass sie nicht benutzt werden sollte?
Wenn ich versuche zu kompilieren von C-code, der verwendet die gets()
Funktion mit GCC,
Bekomme ich diese
Warnung:
(.text+0x34): Warnung: der `bekommt' Funktion ist gefährlich und sollte nicht verwendet werden.
Ich erinnere mich, das hat etwas zu tun mit dem Stapel Schutz und Sicherheit, aber ich bin mir nicht sicher, warum genau?
Kann mir jemand helfen mit dem entfernen dieser Warnung und erklären, warum es solche eine Warnung über die Verwendung von gets()
?
Wenn gets()
so gefährlich ist, warum dann nicht können wir es entfernen?
InformationsquelleAutor der Frage vinit dhatrak | 2009-11-07
Du musst angemeldet sein, um einen Kommentar abzugeben.
Um
gets
sicher, Sie haben um genau zu wissen, wie viele Zeichen, die Sie Lesen werden, so dass Sie machen können Sie den Puffer groß genug ist. Kennen Sie nur, wenn Sie genau wissen, welche Daten Sie Lesen werden.Anstatt
gets
die Sie verwenden möchtenfgets
die die Signatur(
fgets
wenn er liest eine ganze Zeile, verlassen die'\n'
in der Zeichenfolge; Sie haben, damit umzugehen.)Blieb es ein offizieller Teil der Sprache bis zum Jahr 1999 ISO-C-standard, sondern
offiziell wurde es entfernt von der 2011-standard. Die meisten C-Implementierungen noch unterstützen, aber zumindest gcc gibt eine Warnung für jeden code, der es verwendet.
InformationsquelleAutor der Antwort Thomas Owens
Warum ist
gets()
gefährlichDer erste internet-Wurm (der Morris-Internet-Wurm) flüchtete vor 27 Jahren (1988-11-02), und es verwendet
gets()
- und einem Puffer-überlauf, der als eine seiner Methoden zur Vermehrung von system zu system. Das grundlegende problem ist, dass die Funktion nicht weiß, wie groß der Puffer ist, so dass es weiterhin Lesen, bis es findet ein Zeilenumbruch oder trifft auf EOF, und kann überlauf der Grenzen des Puffers gegeben wurde.Sollten Sie vergessen, Sie jemals gehört, dass
gets()
existierte.Den C11-standard ISO/IEC 9899:2011 beseitigt
gets()
als eine standard-Funktion, das ist Eine Gute Sache™. Leider bleibt es in Bibliotheken seit vielen Jahren (was bedeutet, 'Jahrzehnten') aus Gründen der rückwärts-Kompatibilität. Wenn es nach mir geht, die Umsetzung dergets()
werden würde:Gegeben, dass Ihr code wird crash sowieso, früher oder später ist es besser, den Kopf der ärger aus, eher früher als später. Ich würde bereit sein, um hinzuzufügen eine Fehlermeldung:
Moderne Versionen des Linux-Kompilierung system generiert Warnungen wenn Sie einen link
gets()
— und auch einige andere Funktionen, die auch die security-Probleme (mktemp()
...).Alternativen zu
gets()
fgets()
Als alle anderen sagte, ist die kanonische alternative zu
gets()
istfgets()
Angabestdin
wie die Datei-stream.Was niemand sonst noch erwähnt wird, dass
gets()
beinhaltet nicht das newline aberfgets()
tut. Also, müssen Sie möglicherweise verwenden Sie einen wrapper umfgets()
löscht die newline:Auch, wie caf Punkte in einen Kommentar und paxdiablo zeigt in seiner Antwort, mit
fgets()
müssen Sie möglicherweise Daten über Links auf einer Linie. Meine wrapper-code Blättern, die Daten zu Lesen, die nächste Zeit; Sie können leicht ändern Sie es zu fressen, der rest der Zeile der Daten, wenn Sie bevorzugen:Das Verbleibende problem ist, wie die Berichterstattung der drei verschiedenen Ergebnis-Staaten — EOF oder Fehler, Zeile Lesen und nicht abgeschnitten, und teilweise Zeile Lesen, aber die Daten abgeschnitten wurde.
Dieses problem entsteht nicht mit
gets()
weil Sie nicht wissen, wo Sie den Puffer beendet und fröhlich tramples über das Ende, wütet auf Ihrem wunderschön gepflegten memory layout, oft Unordnung auf dem return-stack (eine - Stack Overflow), wenn der Puffer auf dem Stapel reserviert, oder trampeln über die Kontrolle der Informationen, wenn der Puffer wird dynamisch zugewiesen, oder kopieren von Daten über andere wertvolle Globale (oder-Modul) - Variablen, wenn der Puffer statisch zugewiesen. Keines von diesen ist eine gute Idee — Sie verkörpern die phrase 'undefined behaviour`.Gibt es auch die TR 24731-1 (Technischer Bericht vom C Standard Committee), die sicherere alternativen zu einer Vielzahl von Funktionen, einschließlich
gets()
:Microsoft Visual Studio-Compiler implementieren, die eine Annäherung an die TR 24731-1 standard, aber es gibt Unterschiede zwischen den Signaturen, die von Microsoft implementiert und die in der TR.
Dem C11 standard, ISO/IEC 9899-2011, umfasst TR24731 in Anhang K als optionaler Teil der Bibliothek. Leider ist es selten umgesetzt, auf Unix-ähnlichen Systemen.
getline()
— POSIX -POSIX 2008 bietet auch eine sichere alternative zu
gets()
genanntgetline()
. Es reserviert Speicherplatz für dynamisch, so dass Sie am Ende brauchen, um zu befreien. Es beseitigt die Beschränkung der Länge der Linie, daher. Es auch gibt die Länge der Daten, die gelesen wurde, oder-1
(und nichtEOF
!), was bedeutet, dass null-bytes in der Eingabe behandelt werden können, zuverlässig. Es gibt auch eine "wählen Sie Ihr eigenes single-character delimiter' Variante namensgetdelim()
; dies kann nützlich sein, wenn Sie sich mit der Ausgabe vonfind -print0
wo die enden der Dateinamen, die markiert sind mit einem ASCII-NUL'\0'
Charakter, zum Beispiel.InformationsquelleAutor der Antwort Jonathan Leffler
Weil
gets
nicht jede Art von überprüfen, während das erste Byte von stdin und setzen Sie irgendwo aus. Ein einfaches Beispiel:Nun, zunächst darfst du die Eingabe, wie viele Zeichen Sie wollen,
gets
nicht darum kümmern. Zweitens werden die bytes über die Größe des Arrays, in dem du Sie (in diesem Fallarray1
) überschrieben wird, was auch immer Sie finden im Speicher, weilgets
Sie schreiben. Im vorherigen Beispiel bedeutet dies, dass, wenn Sie Eingabe"abcdefghijklmnopqrts"
vielleicht, unvorhersehbar, es überschreibt aucharray2
oder was auch immer.Die Funktion ist unsicher, weil es annimmt, dass konsistente Eingabe. NIE BENUTZEN!
InformationsquelleAutor der Antwort Jack
Sollten Sie nicht verwenden
gets
da hat es keine Möglichkeit zu stoppen Sie einen Pufferüberlauf. Wenn der Benutzer mehr Daten als fit in den Puffer, werden Sie wahrscheinlich am Ende mit Korruption oder schlechter.In der Tat, ISO tatsächlich den Schritt von entfernen
gets
aus dem C-standard (C11, obwohl es veraltet in C99), was angesichts der Tatsache, wie hoch diese rate Abwärtskompatibilität, sollte ein Indiz dafür, wie schlecht diese Funktion war.Das richtige zu tun, ist die Verwendung der
fgets
Funktion mit derstdin
Datei-handle, seit Sie beschränken können, die Zeichen Lesen des Benutzers aus.Aber dies hat auch seine Probleme, wie:
Zu diesem Zweck werden in fast jeder C Programmierer an einem gewissen Punkt in Ihrer Karriere schreiben ein nützlicher wrapper
fgets
als gut. Hier ist meins:mit einigen test-code:
Es bietet den gleichen Schutz wie
fgets
in, dass es verhindert Pufferüberläufe aber auch, informiert den Anrufer, was passiert ist, und löscht die überschüssigen Zeichen, so dass Sie nicht auf Ihre nächste Eingabe.Fühlen Sie sich frei, es zu benutzen, wie du willst, befreie ich Sie unter dem "tun, was Sie verdammt nochmal wollen" - Lizenz 🙂
InformationsquelleAutor der Antwort paxdiablo
fgets.
Lesen von stdin:
InformationsquelleAutor der Antwort Thiago Silveira
Können Sie nicht entfernen Sie API-Funktionen, ohne die API. Wenn Sie viele Anwendungen nicht mehr kompilieren oder ausführen überhaupt.
Dies ist der Grund dafür, dass eine Referenz gibt:
InformationsquelleAutor der Antwort Gerd Klima
Las ich kürzlich in einer USENET-Beitrag zu
comp.lang.c
dassgets()
wird immer entfernt von der Norm. WOOHOOInformationsquelleAutor der Antwort pmg
In C11(ISO/IEC 9899:201x),
gets()
entfernt wurde. (Es ist veraltet, die in ISO/IEC 9899:1999/Cor.3:2007(E))Neben
fgets()
C11 stellt eine neue sichere alternativegets_s()
:Jedoch in der Empfohlen Abschnitt
fgets()
noch immer bevorzugt.InformationsquelleAutor der Antwort Yu Hao
gets()
ist gefährlich, weil es dem Benutzer ermöglicht, das Programm zum Absturz bringen, indem Sie eingeben, zu viel in die Eingabeaufforderung. Es kann nicht erkennen das Ende des verfügbaren Speichers, also, wenn Sie reservieren einen Betrag von Speicher zu klein für den Zweck, kann es zu einer seg Fehler und Absturz. Manchmal scheint es sehr unwahrscheinlich, dass ein Benutzer geben Sie 1000 Buchstaben in eine Eingabeaufforderung eingeben, bedeutete für den Namen einer person, aber als Programmierer brauchen wir, um unsere Programme zu bulletproof. (es kann auch ein Sicherheitsrisiko sein, wenn ein Benutzer kann ein crash-system-Programm durch das senden zu viele Daten).fgets()
können Sie angeben, wie viele Zeichen aus dem standard-input-buffer, damit Sie nicht überrannt die variable.InformationsquelleAutor der Antwort Aradhana Mohanty
Ich würde gerne verlängern, eine ernsthafte Einladung an alle C-Bibliothek Betreuer da draußen, die noch darunter
gets
in Ihren Bibliotheken "nur falls jemand immer noch davon abhängig zu sein": Bitte ersetzen Sie Ihre Implementierung mit dem äquivalent vonDies wird helfen, sicherzustellen, dass niemand ist noch davon abhängig zu sein. Danke.
InformationsquelleAutor der Antwort Steve Summit
Den C ruft die Funktion ist gefährlich und hat schon einen sehr teuren Fehler. Tony Hoare singles aus für spezifische Erwähnung in seinem Vortrag "Null References: The Billion Dollar Mistake":
http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare
Ganze Stunde ist sehenswert, aber für seine Kommentare anzeigen von 30 Minuten mit der spezifischen Kritik bekommt rund 39 Minuten.
Hoffentlich wetzt Ihren Appetit für die ganze Rede, die Sie lenkt die Aufmerksamkeit auf, wie wir brauchen, mehr formale Korrektheit Beweise in Sprachen und wie die Sprache-Designer sollten verantwortlich gemacht werden für die Fehler in Ihren Sprachen, nicht der Programmierer. Dies war wohl auch die ganzen dubiosen Grund für Designer, die schlechter Sprachen, schieben die Schuld auf die Programmierer in der Gestalt der 'programmer ' Freiheit'.
InformationsquelleAutor der Antwort user3717661