Welche Funktion(en) von strtok
ist unsicher (in Bezug auf Pufferüberlauf), auf die ich achten muss?
Was mir ein bisschen komisch vorkommt ist das strtok_s
(was “sicher” ist) in Visual C++ hat einen zusätzlichen “Kontext”-Parameter, aber es sieht so aus, als wäre es auf andere Weise gleich … ist es das gleiche oder ist es tatsächlich anders?
Gemäß dem Abschnitt strtok_s von dieses Dokument:
6.7.3.1 Die Funktion strtok_s Die Funktion strtok_s behebt zwei Probleme in der Funktion strtok:
- Ein neuer Parameter, s1max, verhindert, dass strtok_s außerhalb der tokenisierten Zeichenfolge gespeichert wird. (Die in Token unterteilte Zeichenfolge ist sowohl eine Eingabe als auch eine Ausgabe der Funktion, da strtok_s Nullzeichen in der Zeichenfolge speichert.)
- Ein neuer Parameter, ptr, eliminiert den statischen internen Zustand, der verhindert, dass strtok wiedereintrittsfähig ist (Unterabschnitt 1.1.12). (Die ISO/IEC 9899-Funktion wcstok und die ISO/IEC 9945 (POSIX)-Funktion strtok_r beheben dieses Problem auf identische Weise.)
Daran ist nichts unsicher. Sie müssen nur verstehen, wie es funktioniert und wie man es benutzt. Nachdem Sie Ihren Code und Komponententest geschrieben haben, dauert es nur ein paar zusätzliche Minuten, um den Komponententest mit valgrind erneut auszuführen, um sicherzustellen, dass Sie innerhalb der Speichergrenzen arbeiten. Die Manpage sagt alles:
FEHLER
Seien Sie vorsichtig, wenn Sie diese Funktionen verwenden. Wenn Sie sie verwenden, beachten Sie Folgendes:
- Diese Funktionen ändern ihr erstes Argument.
- Diese Funktionen können nicht auf konstante Zeichenfolgen angewendet werden.
- Die Identität des begrenzenden Charakters geht verloren.
- Das
strtok()
-Funktion verwendet beim Parsen einen statischen Puffer, ist also nicht Thread-sicher. Verwenden strtok_r()
wenn dir das wichtig ist.
strtok ist sicher in Visual C++ (aber nirgendwo anders), da es lokalen Threadspeicher verwendet, um seinen Zustand zwischen Aufrufen zu speichern. Überall sonst wird die globale Variable verwendet, um den strtok()-Zustand zu speichern.
Aber selbst in VC++, wo strtok Thread-sicher ist, ist es immer noch etwas seltsam – Sie können strtok()s nicht gleichzeitig auf verschiedene Strings im selben Thread anwenden. Dies würde zum Beispiel nicht gut funktionieren:
token = strtok( string, seps );
while(token)
{
printf("token=%s\n", token)
token2 = strtok(string2, seps);
while(token2)
{
printf("token2=%s", token2);
token2 = strtok( NULL, seps );
}
token = strtok( NULL, seps );
}
Der Grund, warum es nicht gut funktionieren würde, ist, dass für jeden Thread nur ein Zustand im lokalen Speicher des Threads gespeichert werden kann, und hier würde man 2 Zustände benötigen – für die erste Zeichenfolge und für die zweite Zeichenfolge. Während also strtok mit VC++ Thread-sicher ist, ist es nicht reentrant.
Was strtok_s (oder strtok_r überall sonst) bietet – einen expliziten Zustand, und damit wird strtok wiedereintrittsfähig.
Wenn Sie keine ordnungsgemäß nullterminierte Zeichenfolge haben; Sie werden in einem Pufferüberlauf enden. Beachten Sie auch (das habe ich auf die harte Tour gelernt), dass sich strtok anscheinend NICHT um interne Zeichenfolgen kümmert. IE mit “hello”https://stackoverflow.com/”world” wird “hello”https://stackoverflow.com/”world” analysieren, während “hello/world” in “hello world” analysiert wird. Beachten Sie, dass es am / geteilt wird und die Tatsache ignoriert, dass es sich in einer Klammer befindet.
Vielleicht, weil beide Argumente von strtok Zeiger auf char sind, sodass strtok möglicherweise kein Abschlusszeichen erreicht, das einen lokalen Puffer überläuft?
– Heisenbug
14. Mai 2011 um 2:21 Uhr
@0verbose: Hm … aber gilt das nicht für alle C-Saiten?
– Benutzer541686
14. Mai 2011 um 2:22 Uhr
Sie können sich die Implementierung ansehen: openbsd.org/cgi-bin/cvsweb/src/lib/libc/string/… . Werde ich mir auch ansehen.
– Heisenbug
14. Mai 2011 um 2:28 Uhr
Nebenbei bemerkt, warum sollte man das immer noch verwenden, wenn es das gibt Strep
– Mel
14. Mai 2011 um 2:33 Uhr
Ich denke, der Kontext in strtok_s besteht darin, es Thread-sicher zu machen, wie strtok_r
– Platsch
14. Mai 2011 um 2:34 Uhr