Ich habe auf Stack Overflow gelesen, dass einige C-Funktionen "veraltet" sind oder "vermieden werden sollten". Können Sie mir bitte einige Beispiele für diese Art von Funktion und den Grund dafür geben?
Welche Alternativen zu diesen Funktionen gibt es?
Können wir sie sicher verwenden - irgendwelche guten Praktiken?
c
standard-library
obsolete
Andrei Ciobanu
quelle
quelle
strncpy()
als allgemeinen Ersatz für verwendenstrcpy()
, und ich würde es nie verwendenstrncat()
, weil es die unintuitivste Schnittstelle hat, die man sich vorstellen kann - wissen SIE, was der Längenparameter angibt?Antworten:
Veraltete Funktionen
unsicher
Ein perfektes Beispiel für eine solche Funktion ist get () , da es keine Möglichkeit gibt, festzustellen, wie groß der Zielpuffer ist. Folglich weist jedes Programm, das Eingaben mit get () liest, eine Sicherheitsanfälligkeit bezüglich Pufferüberlauf auf . Aus ähnlichen Gründen sollte man strncpy () anstelle von strcpy () und strncat () anstelle von strcat () verwenden .
Weitere Beispiele sind die Funktionen tmpfile () und mktemp () aufgrund möglicher Sicherheitsprobleme beim Überschreiben temporärer Dateien, die durch die sicherere Funktion mkstemp () ersetzt werden.
Nicht wiedereintrittsfähig
Andere Beispiele sind gethostbyaddr () und gethostbyname (), die nicht wiedereintrittsfähig sind (und daher nicht garantiert threadsicher sind) und durch die wiedereintrittsberechtigten getaddrinfo () und freeaddrinfo () ersetzt wurden .
Möglicherweise bemerken Sie hier ein Muster ... entweder mangelnde Sicherheit (möglicherweise weil nicht genügend Informationen in die Signatur aufgenommen wurden, um sie möglicherweise sicher zu implementieren) oder Nicht-Wiedereintritt sind häufige Ursachen für Missbilligung.
Veraltet,
nicht portierbar Einige andere Funktionen werden einfach veraltet, weil sie die Funktionalität duplizieren und nicht so portabel sind wie andere Varianten. Zum Beispiel ist bzero () zugunsten von memset () veraltet .
Thread-Sicherheit und Wiedereintritt
Sie haben in Ihrem Beitrag nach Thread-Sicherheit und Wiedereintritt gefragt. Es gibt einen kleinen Unterschied. Eine Funktion ist wiedereintrittsfähig, wenn sie keinen gemeinsamen, veränderlichen Status verwendet. Wenn beispielsweise alle benötigten Informationen an die Funktion übergeben werden und alle benötigten Puffer auch an die Funktion übergeben werden (anstatt von allen Aufrufen der Funktion gemeinsam genutzt zu werden), ist sie wiedereintrittsfähig. Das bedeutet, dass verschiedene Threads durch die Verwendung unabhängiger Parameter nicht das Risiko eingehen, versehentlich den Status zu teilen. Wiedereintritt ist eine stärkere Garantie als Gewindesicherheit. Eine Funktion ist threadsicher, wenn sie von mehreren Threads gleichzeitig verwendet werden kann. Eine Funktion ist threadsicher, wenn:
Im Allgemeinen ist in der Single UNIX-Spezifikation und in IEEE 1003.1 (dh "POSIX") nicht garantiert, dass eine Funktion, deren Wiedereintritt nicht garantiert wird, threadsicher ist. Mit anderen Worten, in Multithread-Anwendungen (ohne externe Sperre) können nur Funktionen portabel verwendet werden, deren Wiedereintritt garantiert ist. Dies bedeutet jedoch nicht, dass Implementierungen dieser Standards sich nicht dafür entscheiden können, eine nicht wiedereintretende Funktion threadsicher zu machen. Beispielsweise fügt Linux häufig nicht wiedereintretenden Funktionen häufig eine Synchronisierung hinzu, um eine Garantie (über die der Single UNIX-Spezifikation hinaus) für die Thread-Sicherheit hinzuzufügen.
Strings (und Speicherpuffer im Allgemeinen)
Sie haben auch gefragt, ob bei Strings / Arrays ein grundlegender Fehler vorliegt. Einige mögen argumentieren, dass dies der Fall ist, aber ich würde argumentieren, dass es keinen grundlegenden Fehler in der Sprache gibt. In C und C ++ müssen Sie die Länge / Kapazität eines Arrays separat übergeben (dies ist keine ".length" -Eigenschaft wie in einigen anderen Sprachen). Dies ist per se kein Fehler. Jeder C- und C ++ - Entwickler kann korrekten Code schreiben, indem er bei Bedarf einfach die Länge als Parameter übergibt. Das Problem ist, dass mehrere APIs, für die diese Informationen erforderlich waren, diese nicht als Parameter angeben konnten. Oder angenommen, dass eine MAX_BUFFER_SIZE-Konstante verwendet wird. Solche APIs sind jetzt veraltet und werden durch alternative APIs ersetzt, mit denen die Array- / Puffer- / Zeichenfolgengrößen angegeben werden können.
Scanf (als Antwort auf Ihre letzte Frage)
Ich persönlich verwende die C ++ - iostreams-Bibliothek (std :: cin, std :: cout, die Operatoren << und >>, std :: getline, std :: istringstream, std :: ostringstream) usw.), damit beschäftige ich mich normalerweise nicht. Wenn ich jedoch gezwungen wäre, reines C zu verwenden, würde ich persönlich nur fgetc () oder getchar () in Kombination mit strtol () , strtoul () usw. verwenden und die Dinge manuell analysieren, da ich kein großer Fan von bin varargs oder Formatstrings. Nach meinem besten Wissen gibt es jedoch kein Problem mit [f] scanf () , [f] printf ()usw. Solange Sie die Formatzeichenfolgen selbst erstellen, übergeben Sie niemals beliebige Formatzeichenfolgen oder lassen zu, dass Benutzereingaben als Formatzeichenfolgen verwendet werden, und verwenden Sie gegebenenfalls die in <inttypes.h> definierten Formatierungsmakros . (Beachten Sie, dass snprintf () anstelle von sprintf () verwendet werden sollte. Dies hat jedoch damit zu tun, dass die Größe des Zielpuffers nicht angegeben wird und keine Formatzeichenfolgen verwendet werden.) Ich sollte auch darauf hinweisen, dass boost :: format in C ++ eine printf-ähnliche Formatierung ohne varargs bietet.
quelle
strncpy
sollte generell auch vermieden werden. Es macht nicht das, was die meisten Programmierer annehmen. Es garantiert keine Beendigung (was zu Pufferüberläufen führt) und füllt kürzere Zeichenfolgen auf (was in einigen Fällen möglicherweise die Leistung beeinträchtigt).strncpy()
noch noch schlimmerstrncat()
ist ein vernünftiger Ersatz für die n-weniger Varianten.Wieder wiederholen die Leute mantraartig die lächerliche Behauptung, dass die "n" -Version von str-Funktionen sichere Versionen sind.
Wenn dies das war, wofür sie bestimmt waren, würden sie die Zeichenfolgen immer mit Null beenden.
Die "n" -Versionen der Funktionen wurden für die Verwendung mit Feldern fester Länge (z. B. Verzeichniseinträge in frühen Dateisystemen) geschrieben, bei denen der nul-Terminator nur erforderlich ist, wenn die Zeichenfolge das Feld nicht ausfüllt. Dies ist auch der Grund, warum die Funktionen seltsame Nebenwirkungen haben, die sinnlos ineffizient sind, wenn sie nur als Ersatz verwendet werden - nehmen Sie zum Beispiel strncpy ():
Da die für die Verarbeitung von Dateinamen zugewiesenen Puffer normalerweise 4 KB groß sind, kann dies zu einer massiven Verschlechterung der Leistung führen.
Wenn Sie "angeblich" sichere Versionen wünschen, erhalten oder schreiben Sie Ihre eigenen strl-Routinen (strlcpy, strlcat usw.), die die Strings immer nicht beenden und keine Nebenwirkungen haben. Bitte beachten Sie jedoch, dass diese nicht wirklich sicher sind, da sie die Zeichenfolge stillschweigend abschneiden können - dies ist selten die beste Vorgehensweise in einem realen Programm. Es gibt Fälle, in denen dies in Ordnung ist, aber es gibt auch viele Umstände, in denen dies zu katastrophalen Ergebnissen führen kann (z. B. Ausdrucken von medizinischen Rezepten).
quelle
strncpy()
, aber Unrechtstrncat()
.strncat()
wurde nicht für die Verwendung mit Feldern fester Länge entwickelt - es wurde tatsächlich so konzipiert,strcat()
dass die Anzahl der verketteten Zeichen begrenzt wird. Es ist recht einfach, dies als "sicherstrcat()
" zu verwenden, indem der im Puffer verbleibende Speicherplatz bei mehreren Verkettungen verfolgt wird, und es ist noch einfacher, ihn als "sicherstrcpy()
" zu verwenden (indem das erste Zeichen des Zielpuffers auf "'\0'
Vorher" gesetzt wird nenne es). Beendetstrncat()
immer die Zielzeichenfolge und schreibt keine zusätzlichen'\0'
s.strncat()
das Ziel nicht immer nicht terminiert wird und dass es für die Verwendung mit Feldern fester Länge entwickelt wurde, die beide falsch sind.strncat()
unabhängig von der Länge der Quellzeichenfolge ordnungsgemäß,strcat()
jedoch nicht. Das Problemstrlcat()
dabei ist, dass es sich nicht um eine Standard-C-Funktion handelt.Einige Antworten hier schlagen vor,
strncat()
over zu verwendenstrcat()
; Ich würde vorschlagen, dassstrncat()
(undstrncpy()
) auch vermieden werden sollten. Es gibt Probleme, die die korrekte Verwendung erschweren und zu Fehlern führen:strncat()
bezieht sich auf die maximale Anzahl von Zeichen, die auf das Ziel kopiert werden können (aber nicht ganz genau - siehe 3. Punkt) und nicht auf die Größe des Zielpuffers. Dies machtstrncat()
die Verwendung schwieriger als es sein sollte, insbesondere wenn mehrere Elemente mit dem Ziel verknüpft werden.s1
wird,strlen(s1)+n+1
" für einen Anruf, der aussiehtstrncat( s1, s2, n)
strncpy()
Es gibt auch ein Problem, das zu Fehlern führen kann, die Sie versuchen, es auf intuitive Weise zu verwenden. Es garantiert nicht, dass das Ziel nullterminiert ist. Um sicherzustellen, dass Sie sicherstellen müssen, dass Sie diesen Eckfall speziell behandeln, indem'\0'
Sie a (zumindest in bestimmten Situationen) selbst an der letzten Stelle des Puffers ablegen.Ich würde vorschlagen, etwas wie OpenBSDs zu verwenden
strlcat()
undstrlcpy()
(obwohl ich weiß, dass einige Leute diese Funktionen nicht mögen; ich glaube, sie sind viel einfacher sicher zu verwenden alsstrncat()
/strncpy()
).Hier ist ein wenig von dem, was Todd Miller und Theo de Raadt über Probleme mit
strncat()
und zu sagen hattenstrncpy()
:Die Sicherheitsüberprüfung von OpenBSD ergab, dass Fehler mit diesen Funktionen "weit verbreitet" waren. Im Gegensatz zu
gets()
, diese Funktionen können sicher verwendet werden, aber in der Praxis gibt es viele Probleme gibt , da die Schnittstelle ist verwirrend, nicht intuitiv und schwer richtig zu verwenden. Ich weiß, dass Microsoft auch Analysen durchgeführt hat (obwohl ich nicht weiß, wie viele ihrer Daten sie möglicherweise veröffentlicht haben) und infolgedessen das Verbot verboten (oder zumindest sehr stark entmutigt - das "Verbot" ist möglicherweise nicht absolut) hat Verwendung vonstrncat()
undstrncpy()
(unter anderem).Einige Links mit weiteren Informationen:
quelle
memmove()
. (Nun, Sie könnenmemcpy()
im Normalfall verwenden, wenn die Zeichenfolgen unabhängig sind.)strncat()
immer die Zielzeichenfolge.strncat()
. Es ist jedoch richtig fürstrncpy()
, was einige andere Probleme hat.strncat()
ist ein angemessener Ersatz fürstrcat()
, aberstrncpy()
kein angemessener Ersatz fürstrcpy()
.strncat()
die nicht immer null endet. Ich habe das Verhalten vonstrncat()
undstrncpy()
ein bisschen verwirrt (ein weiterer Grund, warum sie zu vermeidende Funktionen sind - sie haben Namen, die ähnliche Verhaltensweisen implizieren, sich aber in wichtigen Punkten tatsächlich anders verhalten ...). Ich habe meine Antwort geändert, um dies zu korrigieren und zusätzliche Informationen hinzuzufügen.char str[N] = ""; strncat(str, "long string", sizeof(str));
ein Pufferüberlauf ist, wenn N nicht groß genug ist. Diestrncat()
Funktion ist zu leicht zu missbrauchen. es sollte nicht verwendet werden. Wenn Siestrncat()
sicher verwenden können, könnten Siememmove()
odermemcpy()
stattdessen verwendet haben (und diese wären effizienter).Standardbibliotheksfunktionen, die niemals verwendet werden sollten:
setjmp.h
setjmp()
. Zusammen mitlongjmp()
diesen Funktionen wird allgemein als unglaublich gefährlich angesehen: Sie führen zu Spaghetti-Programmierung, sie weisen zahlreiche Formen undefinierten Verhaltens auf und können unbeabsichtigte Nebenwirkungen in der Programmumgebung verursachen, z. B. die Beeinflussung der auf dem Stapel gespeicherten Werte. Referenzen: MISRA-C: 2012 Regel 21.4, CERT C MSC22-C .longjmp()
. Siehesetjmp()
.stdio.h
gets()
. Die Funktion wurde aus der C-Sprache entfernt (gemäß C11), da sie gemäß Design unsicher war. Die Funktion wurde bereits in C99 als veraltet markiert. Verwenden Siefgets()
stattdessen. Referenzen: ISO 9899: 2011 K.3.5.4.1, siehe auch Anmerkung 404.stdlib.h
atoi()
Funktionsfamilie. Diese haben keine Fehlerbehandlung, rufen jedoch bei Auftreten von Fehlern undefiniertes Verhalten auf. Völlig überflüssige Funktionen, die durch die ersetzt werden könnenstrtol()
Funktionsfamilie ersetzt werden können. Referenzen: MISRA-C: 2012 Regel 21.7.string.h
strncat()
. Hat eine umständliche Oberfläche, die oft missbraucht wird. Es ist meist eine überflüssige Funktion. Siehe auch Anmerkungen zustrncpy()
.strncpy()
. Die Absicht dieser Funktion war niemals, eine sicherere Version von zu seinstrcpy()
. Sein einziger Zweck war immer, ein altes String-Format auf Unix-Systemen zu verarbeiten, und dass es in die Standardbibliothek aufgenommen wurde, ist ein bekannter Fehler. Diese Funktion ist gefährlich, da die Zeichenfolge möglicherweise ohne Nullterminierung bleibt und Programmierer sie häufig falsch verwenden. Referenzen: Warum werden strlcpy und strlcat als unsicher angesehen? .Standardfunktionen der Bibliothek, die mit Vorsicht verwendet werden sollten:
assert.h
assert()
. Kommt mit Overhead und sollte im Allgemeinen nicht im Produktionscode verwendet werden. Es ist besser, einen anwendungsspezifischen Fehlerbehandler zu verwenden, der Fehler anzeigt, aber nicht unbedingt das gesamte Programm schließt.signal.h
signal()
. Referenzen: MISRA-C: 2012 Regel 21.5, CERT C SIG32-C .stdarg.h
va_arg()
Funktionsfamilie. Das Vorhandensein von Funktionen variabler Länge in einem C-Programm ist fast immer ein Hinweis auf ein schlechtes Programmdesign. Sollte vermieden werden, es sei denn, Sie haben sehr spezielle Anforderungen.stdio.h Im
Allgemeinen wird diese gesamte Bibliothek nicht für Produktionscode empfohlen , da es zahlreiche Fälle von schlecht definiertem Verhalten und schlechter Typensicherheit gibt.
fflush()
. Perfekt für Ausgabestreams. Ruft undefiniertes Verhalten auf, wenn es für Eingabestreams verwendet wird.gets_s()
. Sichere Version dergets()
in C11 enthaltenen Schnittstelle zur Überprüfung der Grenzen. Es wird bevorzugt,fgets()
stattdessen gemäß der C-Standardempfehlung zu verwenden. Referenzen: ISO 9899: 2011 K.3.5.4.1.printf()
Funktionsfamilie. Ressourcenintensive Funktionen, die mit viel undefiniertem Verhalten und schlechter Typensicherheit einhergehen.sprintf()
hat auch Schwachstellen. Diese Funktionen sollten im Produktionscode vermieden werden. Referenzen: MISRA-C: 2012 Regel 21.6.scanf()
Funktionsfamilie. Siehe Anmerkungen zuprintf()
. Außerdem ist -scanf()
anfällig für Pufferüberläufe, wenn es nicht richtig verwendet wird.fgets()
wird bevorzugt verwendet, wenn möglich. Referenzen: CERT C INT05-C , MISRA-C: 2012 Regel 21.6.tmpfile()
Funktionsfamilie. Kommt mit verschiedenen Schwachstellenproblemen. Referenzen: CERT C FIO21-C .stdlib.h
malloc()
Funktionsfamilie. Perfekt für gehostete Systeme geeignet. Beachten Sie jedoch die bekannten Probleme in C90 und geben Sie das Ergebnis nicht weiter . Diemalloc()
Funktionsfamilie sollte niemals in freistehenden Anwendungen verwendet werden. Referenzen: MISRA-C: 2012 Regel 21.3.Beachten Sie auch, dass dies
realloc()
gefährlich ist, wenn Sie den alten Zeiger mit dem Ergebnis von überschreibenrealloc()
. Wenn die Funktion fehlschlägt, erstellen Sie ein Leck.system()
. Mit viel Aufwand verbunden und obwohl portabel, ist es oft besser, stattdessen systemspezifische API-Funktionen zu verwenden. Kommt mit verschiedenen schlecht definierten Verhaltensweisen. Referenzen: CERT C ENV33-C .string.h
strcat()
. Siehe Anmerkungen zustrcpy()
.strcpy()
. Perfekt zu verwenden, es sei denn, die Größe der zu kopierenden Daten ist unbekannt oder größer als der Zielpuffer. Wenn die Größe der eingehenden Daten nicht überprüft wird, kann es zu Pufferüberläufen kommen. Was nicht an sichstrcpy()
selbst schuld ist , sondern an der aufrufenden Anwendung - dasstrcpy()
ist unsicher, ist meistens ein Mythos, der von Microsoft erstellt wurde .strtok()
. Ändert die Aufruferzeichenfolge und verwendet interne Statusvariablen, wodurch sie in einer Umgebung mit mehreren Threads unsicher werden kann.quelle
static_assert()
anstelle von zu empfehlenassert()
, ob die Bedingung zur Kompilierungszeit behoben werden kann. Auchsprintf()
kann fast immer ausgetauscht werden,snprintf()
was etwas sicherer ist.strtok()
in einer Funktion A bedeutet, dass (a) die Funktion keine andere Funktion aufrufen kann, die ebenfalls verwendet wird,strtok()
während A sie verwendet, und (b) bedeutet, dass keine Funktion, die A aufruft, verwendet werden kann,strtok()
wenn sie A aufruft. Mit anderen Worten: usingstrtok()
vergiftet die Anrufkette; Es kann nicht sicher im Bibliothekscode verwendet werden, da es dokumentieren mussstrtok()
, dass andere Benutzerstrtok()
den Bibliothekscode nicht aufrufen können.strncpy
ist die richtige Funktion zu verwenden , wenn ein Schreiben von null- gepolsterten String - Puffern mit Daten aus entweder einer Null-terminierte Zeichenkette oder ein mit Nullen aufgefüllt Puffern , deren Größe genommen ist mindestens so groß wie das Ziel. Null-gepolsterte Puffer sind nicht besonders häufig, aber auch nicht gerade dunkel.Einige Leute würden das behaupten
strcpy
undstrcat
sollten vermieden werden, zugunsten vonstrncpy
undstrncat
. Das ist meiner Meinung nach etwas subjektiv.Sie sollten beim Umgang mit Benutzereingaben unbedingt vermieden werden - hier kein Zweifel.
Im Code "weit weg vom Benutzer", wenn Sie nur wissen, dass die Puffer lang genug sind
strcpy
undstrcat
möglicherweise etwas effizienter sind, da die Berechnung dern
Weitergabe an ihre Cousins möglicherweise überflüssig ist.quelle
strlcat
undstrlcpy
, da die 'n'-Version keine NULL-Beendigung der Zielzeichenfolge garantiert.strncpy()
schreibt genau Schreibbytesn
und verwendet bei Bedarf keine Zeichen. Als Dan ist die Verwendung einer sicheren Version die beste Wahl, IMO.strncat()
es schwierig sein kann, richtig und sicher zu verwenden (und vermieden werden sollte), ist ein Thema.Vermeiden
strtok
für Multithread-Programme als nicht threadsicher.gets
da dies einen Pufferüberlauf verursachen könntequelle
strtok()
geht ein wenig über die Thread-Sicherheit hinaus - es ist selbst in einem einzelnen Thread-Programm nicht sicher, es sei denn, Sie wissen mit Sicherheit, dass keine Funktionen, die Ihr Code während der Verwendungstrtok()
aufruft, diese auch nicht verwenden (oder denstrtok()
Status des Benutzers durcheinander bringen) von unter dir). Tatsächlich kümmern sich die meisten Compiler, die auf Multithread-Plattformen abzielen, umstrtok()
potenzielle Probleme in Bezug auf Threads, indem sie threadlokalen Speicher fürstrtok()
statische Daten verwenden. Aber das behebt immer noch nicht das Problem, dass andere Funktionen es verwenden, während Sie (im selben Thread) sind.strtok()
ist, dass genau ein Puffer zum Arbeiten vorhanden ist, sodass für die meisten guten Ersetzungen ein Pufferwert beibehalten und übergeben werden muss.strcspn
erledigt das meiste, was Sie brauchen - finden Sie das nächste Token-Trennzeichen. Sie können damit eine vernünftige Variante erneut implementierenstrtok
.Es lohnt sich wahrscheinlich, noch einmal hinzuzufügen, dass dies
strncpy()
nicht der allgemeine Ersatz für iststrcpy()
den Namen ist. Es wurde für Felder mit fester Länge entwickelt, für die kein Nullterminator erforderlich ist (es wurde ursprünglich für die Verwendung mit UNIX-Verzeichniseinträgen entwickelt, kann jedoch beispielsweise für Verschlüsselungsschlüsselfelder hilfreich sein).Es ist jedoch einfach
strncat()
als Ersatz fürstrcpy()
:(Der
if
Test kann natürlich im allgemeinen Fall abgebrochen werden, wenn Sie wissen, dass diesdest_size
definitiv ungleich Null ist).quelle
Lesen Sie auch die Liste der gesperrten APIs von Microsoft . Hierbei handelt es sich um APIs (einschließlich vieler hier bereits aufgelisteter APIs), die aus Microsoft-Code verbannt sind, da sie häufig missbraucht werden und zu Sicherheitsproblemen führen.
Sie sind vielleicht nicht mit allen einverstanden, aber sie sind alle eine Überlegung wert. Sie fügen der Liste eine API hinzu, wenn deren Missbrauch zu einer Reihe von Sicherheitslücken geführt hat.
quelle
Fast jede Funktion, die sich mit NUL-terminierten Zeichenfolgen befasst, ist möglicherweise unsicher. Wenn Sie Daten von außen empfangen und über die Funktionen str * () bearbeiten, bereiten Sie sich auf eine Katastrophe vor
quelle
Sprintf nicht vergessen - es ist die Ursache vieler Probleme. Dies ist richtig, da die Alternative snprintf manchmal unterschiedliche Implementierungen hat, die dazu führen können, dass Sie nicht portierbar sind.
Linux: http://linux.die.net/man/3/snprintf
Windows: http://msdn.microsoft.com/en-us/library/2ts7cx93%28VS.71%29.aspx
In Fall 1 (Linux) ist der Rückgabewert die Datenmenge, die zum Speichern des gesamten Puffers benötigt wird (wenn er kleiner als die Größe des angegebenen Puffers ist, wurde die Ausgabe abgeschnitten).
In Fall 2 (Fenster) ist der Rückgabewert eine negative Zahl, falls die Ausgabe abgeschnitten wird.
Im Allgemeinen sollten Sie Funktionen vermeiden, die nicht:
Pufferüberlauf sicher (viele Funktionen werden hier bereits erwähnt)
thread sicher / nicht wiedereintrittsfähig (strtok zum Beispiel)
Im Handbuch der einzelnen Funktionen sollten Sie nach Schlüsselwörtern wie "Safe", "Sync", "Async", "Thread", "Buffer" und "Bugs" suchen
quelle
_sprintf()
wurde von Microsoft erstellt, bevor der Standardsnprintf()
IIRC eintraf. ´StringCbPrintf () ´ ist allerdings ziemlich ähnlichsnprintf()
.sprintf
in einigen Fällen irgendwie sicher:sprintf(buffer,"%10s",input);
begrenzt die kopiert nb bis 10 Bytes (wennbuffer
istchar buffer[11]
es sicher ist, selbst wenn die Daten abgeschnitten aufzuwickeln kann.Es ist sehr schwer
scanf
sicher zu verwenden . Durch eine gute Verwendung vonscanf
können Pufferüberläufe vermieden werden. Sie sind jedoch weiterhin anfällig für undefiniertes Verhalten, wenn Sie Zahlen lesen, die nicht in den angeforderten Typ passen. In den meisten Fällen ,fgets
gefolgt von Selbst Parsing (unter Verwendungsscanf
,strchr
etc.) ist eine bessere Option.Aber ich würde nicht sagen "die
scanf
ganze Zeit vermeiden ".scanf
hat seine Verwendung. Angenommen, Sie möchten Benutzereingaben in einemchar
10 Byte langen Array lesen . Sie möchten gegebenenfalls die nachfolgende neue Zeile entfernen. Wenn der Benutzer mehr als 9 Zeichen vor einer neuen Zeile eingibt, möchten Sie die ersten 9 Zeichen im Puffer speichern und alles bis zur nächsten neuen Zeile verwerfen. Du kannst tun:Sobald Sie sich an diese Redewendung gewöhnt haben, ist sie kürzer und in gewisser Weise sauberer als:
quelle
In allen Szenarien zum Kopieren / Verschieben von Zeichenfolgen - strcat (), strncat (), strcpy (), strncpy () usw. - läuft es viel besser ( sicherer ), wenn ein paar einfache Heuristiken erzwungen werden:
1. Immer NUL-füllen Ihre Puffer vor dem Hinzufügen von Daten.
2. Deklarieren Sie Zeichenpuffer als [GRÖSSE + 1] mit einer Makrokonstante.
Zum Beispiel gegeben:
Wir können Code verwenden wie:
relativ sicher. Das memset () sollte vor dem strncpy () erscheinen, obwohl wir Buffer zur Kompilierungszeit initialisiert haben, da wir nicht wissen, welchen Müll anderer Code darin abgelegt hat, bevor unsere Funktion aufgerufen wurde. Strncpy () schneidet die kopierten Daten auf "1234567890" ab und beendet sie nicht mit NUL. Da wir jedoch bereits den gesamten Puffer mit NUL gefüllt haben - sizeof (Buffer) anstelle von BUFSIZE -, wird garantiert, dass NUL endgültig "außerhalb des Gültigkeitsbereichs" endet, solange wir unsere Schreibvorgänge mit BUFSIZE einschränken konstant anstelle von sizeof (Buffer).
Buffer und BUFSIZE funktionieren ebenfalls gut für snprintf ():
Obwohl snprintf () speziell nur BUFIZE-1-Zeichen gefolgt von NUL schreibt, funktioniert dies sicher. Wir "verschwenden" also ein fremdes NUL-Byte am Ende von Buffer ... wir verhindern sowohl Pufferüberlauf als auch nicht abgeschlossene String-Bedingungen für einen relativ geringen Speicheraufwand.
Mein Aufruf von strcat () und strncat () ist schwieriger: Verwenden Sie sie nicht. Es ist schwierig, strcat () sicher zu verwenden, und die API für strncat () ist so kontraintuitiv, dass der Aufwand für die ordnungsgemäße Verwendung jeden Vorteil zunichte macht. Ich schlage folgendes Drop-In vor:
Es ist verlockend, ein Drop-In für strcat () zu erstellen, aber keine gute Idee:
da das Ziel möglicherweise ein Zeiger ist (daher gibt sizeof () nicht die benötigten Informationen zurück). Ich habe keine gute "universelle" Lösung für Instanzen von strcat () in Ihrem Code.
Ein Problem, auf das ich häufig von "strFunc () - fähigen" Programmierern stoße, ist der Versuch, mit strlen () vor Pufferüberläufen zu schützen. Dies ist in Ordnung, wenn garantiert ist, dass der Inhalt NUL-terminiert ist. Andernfalls kann strlen () selbst einen Pufferüberlauffehler verursachen (der normalerweise zu einer Segmentierungsverletzung oder einer anderen Core-Dump-Situation führt), bevor Sie jemals den "problematischen" Code erreichen, den Sie schützen möchten.
quelle
atoi ist nicht threadsicher. Ich verwende stattdessen strtol gemäß der Empfehlung auf der Manpage.
quelle
strtol()
es threadsicheratoi()
wäre und nicht.man atoi
(sollte es aber geben).