Das ISO C-Komitee ( ISO / IEC JTC1 / SC21 / WG14 ) hat TR 24731-1 veröffentlicht und arbeitet an TR 24731-2 :
TR 24731-1: Erweiterungen der C-Bibliothek Teil I: Schnittstellen zur Überprüfung von Grenzen
WG14 arbeitet an einem TR für sicherere C-Bibliotheksfunktionen. Diese TR ist darauf ausgerichtet, vorhandene Programme zu ändern, häufig durch Hinzufügen eines zusätzlichen Parameters mit der Pufferlänge. Der neueste Entwurf befindet sich in Dokument N1225. Eine Begründung findet sich in Dokument N1173. Dies soll ein technischer Bericht Typ 2 werden.
TR 24731-2: Erweiterungen der C-Bibliothek - Teil II: Dynamische Zuordnungsfunktionen
WG14 arbeitet an einem TR für sicherere C-Bibliotheksfunktionen. Diese TR ist auf neue Programme ausgerichtet, die anstelle eines zusätzlichen Parameters für die Pufferlänge eine dynamische Zuordnung verwenden. Der neueste Entwurf befindet sich in Dokument N1337. Dies soll ein technischer Bericht Typ 2 werden.
Fragen
- Verwenden Sie eine Bibliothek oder einen Compiler mit Unterstützung für die Funktionen TR24731-1?
- Wenn ja, welcher Compiler oder welche Bibliothek und auf welcher Plattform?
- Haben Sie Fehler beim Korrigieren Ihres Codes zur Verwendung dieser Funktionen entdeckt?
- Welche Funktionen bieten den größten Wert?
- Gibt es welche, die keinen Wert oder negativen Wert liefern?
- Planen Sie, die Bibliothek in Zukunft zu nutzen?
- Verfolgen Sie die Arbeit des TR24731-2 überhaupt?
quelle
strlen()
Zum Code hinzufügen" meinen . Es gibt definitiv Zeiten, in denenstrlen()
die Antwort nicht richtig ist, z. B. wenn ein Puffer an eine E / A-Funktion übergeben wird (z. B.gets_s()
). Aber vielleicht können Sie näher darauf eingehen, woran Sie denken?realloc()
da die zu schützenden Funktionen nicht zugewiesen werden. Diestrcpy()
Funktion führt beispielsweise keine Speicherzuweisung durch. Sie können es nicht ordnungsgemäß ändern, um die Speicherzuweisung durchzuführen, selbst wenn Sie über eine Garbage Collection verfügen, da die Benutzer im Allgemeinen nicht den Rückgabewert verwenden, sondern den Wert, der als erstes Argument fürstrcpy()
weitere Vorgänge übergeben wird. Ähnliche Probleme treten beigets()
und aufstrcat()
. Diese geben zumindest ein zurückchar *
, das möglicherweise auf neu zugewiesenen Speicherplatz verweist (nicht, dass garantiert wird, dass die Argumente zugewiesen wurden). [… Fortsetzung…]sprintf()
denen, die kein a zurückgebenchar *
; Sie können dem aufrufenden Code nicht mitteilen, dass sie den Speicher, in dem das Ergebnis platziert wurde, neu zugewiesen haben. Beachten Sie, dass einer der Gründe, warum TR 24731-2 es nicht in C11 geschafft hat, darin bestand, dass sie die ersten Funktionen waren, die die Speicherzuweisung explizit durchführten - außermalloc()
et al. Bitte nehmen Sie sich Zeit, um zu untersuchen, was die Funktionen tun, was die Funktionen in Anhang K / TR 24731-1 tun, warum sie dies tun und so weiter. Es gibt einige gute Gründe für die getroffenen Entscheidungen.Antworten:
Ich bin seit ihrer Gründung (als es sich um eine einzelne TR handelte) ein lautstarker Kritiker dieser TRs und würde sie in keiner meiner Software verwenden. Sie maskieren Symptome, anstatt Ursachen anzusprechen, und ich bin der Meinung, dass sie sich, wenn überhaupt, negativ auf das Software-Design auswirken werden, da sie ein falsches Sicherheitsgefühl vermitteln, anstatt bestehende Praktiken zu fördern, mit denen dieselben Ziele viel effektiver erreicht werden können. Ich bin nicht allein, tatsächlich ist mir kein einziger wichtiger Befürworter außerhalb des Ausschusses bekannt, der diese TRs entwickelt.
Ich benutze glibc und weiß als solches, dass ich nicht mit diesem Unsinn umgehen muss, wie Ulrich Drepper, leitender Betreuer von glibc, über das Thema sagte :
Er geht weiter auf Probleme mit einer Reihe der vorgeschlagenen Funktionen ein und hat an anderer Stelle darauf hingewiesen, dass glibc dies niemals unterstützen würde.
Die Austin Group (verantwortlich für die Aufrechterhaltung von POSIX) hat eine sehr kritische Überprüfung der TR, ihrer Kommentare und der hier verfügbaren Antworten des Ausschusses vorgenommen . Die Überprüfung durch die Austin Group macht einen sehr guten Job und beschreibt viele der Probleme mit dem TR, so dass ich hier nicht auf einzelne Details eingehen werde.
Das Fazit lautet also: Ich verwende keine Implementierung, die dies unterstützt oder unterstützen wird, ich plane nicht, diese Funktionen jemals zu verwenden, und ich sehe keinen positiven Wert in der TR. Ich persönlich glaube, dass der einzige Grund, warum die TR in irgendeiner Form noch am Leben ist, darin besteht, dass sie von Microsoft hart vorangetrieben wird, das sich in letzter Zeit trotz weit verbreiteter Opposition als sehr fähig erwiesen hat, Dinge durch Standardausschüsse zu rammen. Wenn diese Funktionen jemals standardisiert werden, werden sie meiner Meinung nach nie weit verbreitet sein, da der Vorschlag bereits seit einigen Jahren besteht und keine echte Unterstützung durch die Community erhalten hat.
quelle
Direkte Antwort auf die Frage
Ich mag Roberts Antwort, aber ich habe auch einige Ansichten zu den Fragen, die ich aufgeworfen habe.
Verwenden Sie eine Bibliothek oder einen Compiler mit Unterstützung für die Funktionen TR24731-1?
Wenn ja, welcher Compiler oder welche Bibliothek und auf welcher Plattform?
Haben Sie Fehler beim Korrigieren Ihres Codes zur Verwendung dieser Funktionen entdeckt?
Welche Funktionen bieten den größten Wert?
Gibt es welche, die keinen Wert oder negativen Wert liefern?
Planen Sie, die Bibliothek in Zukunft zu nutzen?
Verfolgen Sie die Arbeit des TR24731-2 überhaupt?
Insgesamt bin ich von Teil 1 'Bounds-Checking Interfaces' nicht überzeugt. Das Material im Entwurf von Teil 2 'Dynamische Zuordnungsfunktionen' ist besser.
Wenn es nach mir ginge, würde ich mich etwas in Richtung von Teil 1 bewegen, aber ich hätte auch die Schnittstellen in der C99-Standard-C-Bibliothek überarbeitet, die a
char *
an den Anfang der Zeichenfolge zurückgeben (z. B.strcpy()
undstrcat()
), so dass anstelle von Wenn sie einen Zeiger auf den Start zurückgeben, geben sie einen Zeiger auf das Nullbyte am Ende der neuen Zeichenfolge zurück. Dies würde einige gängige Redewendungen (wie das wiederholte Verketten von Zeichenfolgen am Ende eines anderen) effizienter machen, da es trivial wäre, das quadratische Verhalten von Code zu vermeiden, der wiederholt verwendet wirdstrcat()
. Die Ersetzungen würden alle eine Nullterminierung von Ausgabezeichenfolgen sicherstellen, wie dies bei den TR24731-Versionen der Fall ist. Ich bin weder der Idee der Überprüfungsschnittstelle noch den Ausnahmebehandlungsfunktionen völlig abgeneigt. Es ist eine knifflige Angelegenheit.Die Implementierung von Microsoft entspricht nicht der Standardspezifikation
Update (08.05.2011)
Siehe auch diese Frage . Leider und fatal für die Nützlichkeit der TR24731-Funktionen unterscheiden sich die Definitionen einiger Funktionen zwischen der Microsoft-Implementierung und dem Standard, was sie (für mich) unbrauchbar macht. Meine Antwort dort zitiert
vsnprintf_s()
.Ebenso gibt es auch Probleme mit
scanf_s()
und seinen Verwandten. Microsoft gibt an, dass der Typ des Pufferlängenparametersunsigned
(explizit "Der Größenparameter ist vom Typunsigned
, nichtsize_t
") ist. Im Gegensatz dazu ist in Anhang K der Größenparameter vom Typrsize_t
, der die eingeschränkte Variante von istsize_t
(rsize_t
ist ein anderer Name fürsize_t
, ist aberRSIZE_MAX
kleiner alsSIZE_MAX
). Daherscanf_s()
müsste der Codeaufruf für Microsoft C und Standard C unterschiedlich geschrieben werden.Ursprünglich hatte ich vor, die "sicheren" Funktionen zu verwenden, um Code unter Windows und Unix sauber zu kompilieren, ohne bedingten Code schreiben zu müssen. Da dies nicht funktioniert, weil die Microsoft- und ISO-Funktionen nicht immer gleich sind, ist es ziemlich an der Zeit, aufzugeben.
Änderungen an Microsoft
vsnprintf()
in Visual Studio 2015In der Visual Studio 2015-Dokumentation für
vsnprintf()
wird darauf hingewiesen, dass sich die Benutzeroberfläche geändert hat:Die Microsoft-Oberfläche für
vsnprintf_s()
hat sich jedoch nicht geändert.Weitere Beispiele für Unterschiede zwischen Microsoft und Anhang K.
Die C11-Standardvariante von
localtime_s()
ist in ISO / IEC 9899: 2011 Anhang K.3.8.2.4 definiert als:struct tm *localtime_s(const time_t * restrict timer, struct tm * restrict result);
verglichen mit der MSDN-Variante
localtime_s()
definiert als:errno_t localtime_s(struct tm* _tm, const time_t *time);
und die POSIX-Variante
localtime_r()
definiert als:struct tm *localtime_r(const time_t *restrict timer, struct tm *restrict result);
Die C11-Standard- und POSIX-Funktionen sind bis auf den Namen gleichwertig. Die Microsoft-Funktion unterscheidet sich in der Benutzeroberfläche, obwohl sie einen Namen mit dem C11-Standard teilt.
Ein weiteres Beispiel für Unterschiede ist Microsoft ‚s
strtok_s()
und Anhang K diestrtok_s()
:char *strtok_s(char *strToken, const char *strDelimit, char **context);
vs:
char *strtok_s(char * restrict s1, rsize_t * restrict s1max, const char * restrict s2, char ** restrict ptr);
Beachten Sie, dass die Microsoft-Variante 3 Argumente hat, während die Annex K-Variante 4 hat. Dies bedeutet, dass die Argumentliste zu Microsoft
strtok_s()
mit POSIX kompatibel iststrtok_r()
Aufrufe an diese sind also effektiv austauschbar, wenn Sie den Funktionsnamen ändern (z. B. durch ein Makro) Die Version Standard C (Anhang K) unterscheidet sich von beiden mit dem zusätzlichen Argument.Die Frage Unterschiedliche Deklarationen von
qsort_r()
Mac und Linux hat eine Antwort, die auchqsort_s()
wie von Microsoft undqsort_s()
TR24731-1 definiert diskutiert wird - auch hier sind die Schnittstellen unterschiedlich.ISO / IEC 9899: 2011 - C11-Norm
Der C11-Standard ( Entwurf vom Dezember 2010 ; Sie können auf einmal eine PDF-Kopie des endgültigen Standards ISO / IEC 9899: 2011 vom ANSI-Webshop für 30 USD erhalten) enthält optional die TR24731-1-Funktionen Teil des Standards. Sie sind in Anhang K (Bounds-Checking Interfaces) definiert, der eher "normativ" als "informativ" ist, aber optional.
Der C11-Standard enthält keine TR24731-2-Funktionen - was traurig ist, da die
vasprintf()
Funktion und ihre Verwandten wirklich nützlich sein könnten.Kurze Zusammenfassung:
Vorschlag, Anhang K aus dem Nachfolger von C11 zu streichen
Deduplicator wies in einem Kommentar zu einer anderen Frage darauf hin, dass dem ISO C-Standardausschuss (ISO / IEC JTC1 / SC22 / WG14) ein Vorschlag vorliegt.
Es enthält Verweise auf einige der vorhandenen Implementierungen der Funktionen in Anhang K - keine davon ist weit verbreitet (Sie können sie jedoch bei Interesse über das Dokument finden).
Das Dokument endet mit der Empfehlung:
Daher schlagen wir vor, Anhang K entweder aus der nächsten Überarbeitung des C-Standards zu entfernen oder veraltet und dann zu entfernen.
Ich unterstütze diese Empfehlung.
Die C18-Norm hat den Status von Anhang K nicht geändert . Es gibt ein Papier N2336, in dem befürwortet wird, einige Änderungen an Anhang K vorzunehmen, um seine Mängel zu beheben , anstatt ihn vollständig zu beseitigen.
quelle
Ok, jetzt ein Stand für TR24731-2:
Ja, ich habe
asprintf()
/vasprintf()
seit ich sie in glibc gesehen habe, und ja, ich bin ein sehr starker Verfechter von ihnen.Warum?
Weil sie immer wieder genau das liefern, was ich brauche: Eine leistungsstarke, flexible, sichere und (relativ) benutzerfreundliche Methode, um Text in eine frisch zugewiesene Zeichenfolge zu formatieren.
Ich bin auch sehr für die
memstream
Funktionen: Wieasprintf()
,open_memstream()
(nichtfmemopen()
!!!) weist Ihnen einen ausreichend großen Puffer zu und gibt IhnenFILE*
die Möglichkeit, Ihre Druckvorgänge durchzuführen, sodass Ihre Druckfunktionen möglicherweise völlig unwissend sind, ob sie in eine Zeichenfolge gedruckt werden oder eine Datei, und Sie können einfach vergessen, wie viel Speicherplatz Sie benötigen.quelle
fmemopen()
Funktion in POSIX. Dieopen_memstream()
Funktion ist interessant. Ich vermute, es gibt einige Fallstricke bei der Verwendung, da Sie Zeiger an den Pufferzeiger und die Größenvariable übergeben. Aber insgesamt ist TR23731-2 gut.vasprintf
würde als eine "allgemeine" vformat-Funktion, die zusätzlich zu den üblichen vprintf-Argumenten einint(*func)(void*,size_t,char const*)
und ein akzeptiert undvoid*
die bereitgestellte Funktion für jede "Spanne" von Zeichen aufruft, die ausgegeben werden sollen [wird früh zurückgegeben, wenn die Funktion zurückkehrt ein Wert ungleich Null]. Man könnte aus einer solchen Funktion einen automatisch zuweisenden Sprintf synthetisieren, aber die allgemeine Version wäre auch mit benutzerdefinierten Zuweisern kompatibel.stdio
Varianten, mit denen Sie Ihre eigenen Lese- / Schreibfunktionen angeben können. So können Sie beispielsweise etwas tunFILE *fp = ffunopen(myreadfunc, mywritefunc)
und dannfprintf
oder eine beliebige stdio-Funktion aufrufen und Ihre Rückrufe aufrufen lassen . Ich habe auch mindestens eine Implementierung einerfmemopen
Variante gesehen, in die die automatische Zuordnung integriert war - was wiederum bedeutet, dass Sie die automatische Zuweisung für jede Folge von Ausgabeaufrufen erhalten können, nicht nur*printf
.FILE*
wäre sehr nützlich, einen Zeiger auf eine Funktionstabelle zu haben, aber mein Hauptpunkt war, dass Bibliotheksroutinen nicht abhängig sein sollten,malloc
sondern dass Benutzercode den Speicher mit den für den beabsichtigten Anwendungsfall am besten geeigneten Mitteln verwalten kann .Ja, Visual Studio 2005 und 2008 (für die Win32-Entwicklung natürlich).
Ich habe meine eigene Bibliothek sicherer Funktionen geschrieben (nur etwa 15, die wir häufig verwenden), die auf mehreren Plattformen verwendet werden - Linux, Windows, VxWorks, INtime, RTX und uItron. Der Grund für die Erstellung der sicheren Funktionen war:
Sobald die Funktionen geschrieben wurden, wurden weitere Fehler entdeckt. Ja, es war sinnvoll, die Funktionen zu verwenden.
Sicherere Versionen von vsnprintf, strncpy, strncat.
fopen_s und ähnliche Funktionen bieten für mich persönlich nur einen geringen Mehrwert. Ich bin in Ordnung, wenn fopen NULL zurückgibt. Sie sollten immer den Rückgabewert der Funktion überprüfen. Wenn jemand den Rückgabewert von fopen ignoriert, was veranlasst ihn dann, den Rückgabewert von fopen_s zu überprüfen? Ich verstehe, dass fopen_s spezifischere Fehlerinformationen zurückgibt, die in einigen Kontexten nützlich sein können. Aber für das, woran ich arbeite, spielt das keine Rolle.
Wir verwenden es jetzt - in unserer eigenen "sicheren" Bibliothek.
Nein.
quelle
Nein, diese Funktionen sind absolut nutzlos und dienen keinem anderen Zweck, als das Schreiben von Code zu fördern, sodass er nur unter Windows kompiliert werden kann.
snprintf ist absolut sicher (bei korrekter Implementierung), daher ist snprintf_s sinnlos. strcat_s zerstört Daten wenn der Puffer überläuft (durch Löschen der verketteten Zeichenfolge). Es gibt viele andere Beispiele für völlige Unkenntnis der Funktionsweise.
Die wirklich nützlichen Funktionen sind BSD strlcpy und strlcat. Aber sowohl Microsoft als auch Drepper haben diese aus eigenen egoistischen Gründen abgelehnt, zum Ärger der C-Programmierer überall.
quelle