Warum kann ich fopen nicht verwenden?

Lesezeit: 9 Minuten

Benutzer-Avatar
Jamie H

In Anlehnung an eine frühere Frage, die ich zu den sogenannten Abwertungen von sicheren Bibliotheken gestellt habe, bin ich ähnlich verwirrt darüber, warum fopen() sollte verworfen werden.

Die Funktion nimmt zwei C-Strings und gibt ein FILE* ptr oder NULL bei einem Fehler zurück. Wo sind die Thread-Sicherheitsprobleme / String-Overrun-Probleme? Oder ist es etwas anderes?

Danke im Voraus

  • Werfen Sie einen Blick auf: stackoverflow.com/questions/14386/fopen-deprecated-warning

    – davidag

    25. Mai 2009 um 12:50 Uhr

  • @DavidA, ich sehe das nicht als Duplikat. Diese Frage wollte wissen, wie man die Warnungen verhindern kann. Dieser möchte wissen, WARUM er veraltet ist.

    – paxdiablo

    25. Mai 2009 um 14:13 Uhr

Benutzer-Avatar
paxdiablo

Du kann verwenden fopen(). Im Ernst, nehmen Sie hier keine Notiz von Microsoft, sie erweisen Programmierern einen echten Bärendienst, indem sie von den ISO-Standards abweichen. Sie scheinen zu glauben, dass Leute, die Code schreiben, irgendwie hirntot sind und nicht wissen, wie man Parameter überprüft, bevor man Bibliotheksfunktionen aufruft.

Wenn jemand nicht bereit ist, die Feinheiten der C-Programmierung zu lernen, hat er wirklich nichts damit zu tun. Sie sollten zu einer sichereren Sprache übergehen.

Dies scheint nur ein weiterer Versuch zu sein, Entwickler von Microsoft an einen Anbieter zu binden (obwohl sie nicht die einzigen sind, die es versuchen, also beschimpfe ich sie nicht ausdrücklich). Ich füge normalerweise hinzu:

#define _CRT_SECURE_NO_WARNINGS

(oder der "-D" Variante auf der Kommandozeile) für die meisten meiner Projekte, um sicherzustellen, dass ich nicht vom Compiler gestört werde, wenn ich absolut gültigen, legalen C-Code schreibe.

Microsoft hat zusätzliche Funktionen in der bereitgestellt fopen_s() Funktion (z. B. Dateikodierungen) sowie die Art und Weise, wie Dinge zurückgegeben werden, ändern. Dies mag es für Windows-Programmierer besser machen, macht den Code jedoch von Natur aus nicht portierbar.

Wenn Sie immer nur für Windows programmieren, verwenden Sie es auf jeden Fall. Ich selbst bevorzuge die Möglichkeit, meinen Code überall (mit so wenig Änderung wie möglich) zu kompilieren und auszuführen.


Ab C11 gehören diese sicheren Funktionen nun zum Standard, sind aber optional. Sehen Sie in Anhang K nach, um alle Einzelheiten zu erfahren.

  • Völlig einverstanden. Verwenden Sie stattdessen den Standard, aber kennen Sie die Einschränkungen dessen, was Sie verwenden.

    – Zügel

    25. Mai 2009 um 13:12 Uhr

  • Ich muss wirklich zustimmen. Sie können alles tun, um Sie daran zu hindern, unsichere Funktionen aufzurufen, aber es gibt nicht viel, was Sie daran hindern kann, Ihre eigene Routine zu schreiben, die über das Ende eines Strings hinausgeht. Wenn Sie in C programmieren möchten, gibt es inhärente Komplexitäten und Unsicherheiten, denen Sie sich bewusst sein müssen. Ich denke, dass MS die Leute viel besser dazu drängen würde, Sprachen wie C# zu verwenden, wenn es die geeignetere Sprache ist, als zu versuchen, die Art und Weise zu ändern, wie Leute C schreiben.

    – Kibbee

    25. Mai 2009 um 13:16 Uhr

  • Ich dachte Microsoft tat #define errno als Funktionsaufruf definieren, sodass es sich um eine Thread-lokale Variable handelt? Ich bin im Moment nicht vor einer Windows-Box, daher kann ich das nicht überprüfen.

    – Adam Rosenfield

    25. Mai 2009 um 13:25 Uhr

  • Nun, das tun sie (zumindest auf VC++ 2005 SP1).

    – Raphaël Saint-Pierre

    25. Mai 2009 um 13:29 Uhr

  • Ich denke, es ist eine gute Idee, sicherere strcmp/strcpy-Methoden usw. bereitzustellen. Das gilt also für MS. Aber sie haben versucht, sichere Methoden sicherer zu machen (fopen_s, strncpy_s), was völlig verrückt ist, und sie haben alle Probleme mit Standards/Protabilität ignoriert. Also +1 für MS und -2 => -1 für MS

    – mmmmmmmm

    25. Mai 2009 um 19:06 Uhr

Benutzer-Avatar
Jonathan Leffler

Es gibt einen offiziellen technischen ISO/IEC JTC1/SC22/WG14-Bericht (Sprache C). TR24731-1 (Bounds Checking Interfaces) und seine Begründung verfügbar unter:

Es wird auch an TR24731-2 (dynamische Zuordnungsfunktionen) gearbeitet.

Die angegebene Begründung für fopen_s() ist:

6.5.2 Dateizugriffsfunktionen

Beim Erstellen einer Datei wird die fopen_s und freopen_s Funktionen verbessern die Sicherheit, indem sie die Datei vor unbefugtem Zugriff schützen, indem sie ihren Dateischutz einstellen und die Datei mit exklusivem Zugriff öffnen.

Die Spezifikation sagt:

6.5.2.1 Die Funktion fopen_s

Zusammenfassung

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
errno_t fopen_s(FILE * restrict * restrict streamptr,
                const char * restrict filename,
                const char * restrict mode);

Laufzeitbeschränkungen

Keiner von streamptr, filenameoder mode soll ein Nullzeiger sein.

Wenn eine Laufzeitbeschränkungsverletzung vorliegt, fopen_s versucht nicht, eine Datei zu öffnen. Außerdem, wenn streamptr ist kein Nullzeiger, fopen_s setzt *streamptr zum Nullzeiger.

Beschreibung

Das fopen_s Die Funktion öffnet die Datei, deren Name die Zeichenfolge ist, auf die gezeigt wird
filenameund ordnet ihm einen Stream zu.

Der Mode-String muss wie für beschrieben sein fopenmit dem Zusatz, dass Modi, die mit dem Zeichen ‘w’ oder ‘a’ beginnen, das Zeichen ‘u’ vorangestellt werden kann, siehe unten:

  • uw auf Nulllänge kürzen oder Textdatei zum Schreiben erstellen, Standardberechtigungen
  • ua anhängen; Öffnen oder erstellen Sie eine Textdatei zum Schreiben am Dateiende, Standardberechtigungen
  • uwb auf Nulllänge kürzen oder Binärdatei zum Schreiben erstellen, Standardberechtigungen
  • uab anhängen; Öffnen oder Erstellen einer Binärdatei zum Schreiben am Dateiende, Standardberechtigungen
  • uw+ auf Nulllänge kürzen oder Textdatei zum Aktualisieren erstellen, Standardberechtigungen
  • ua+ anhängen; Öffnen oder Erstellen einer Textdatei zum Aktualisieren, Schreiben am Dateiende, Standardberechtigungen
  • uw+b oder uwb+ auf Nulllänge kürzen oder Binärdatei zum Update erstellen, Standardberechtigungen
  • ua+b oder uab+ anhängen; Öffnen oder Erstellen einer Binärdatei zum Aktualisieren, Schreiben am Dateiende, Standardberechtigungen

Soweit das zugrunde liegende System die Konzepte unterstützt, werden zum Schreiben geöffnete Dateien mit exklusivem (auch als nicht gemeinsam genutztem) Zugriff geöffnet. Wenn die Datei erstellt wird und das erste Zeichen der Moduszeichenfolge nicht „u“ ist, muss die Datei, sofern das zugrunde liegende System dies unterstützt, eine Dateiberechtigung haben, die andere Benutzer des Systems daran hindert, auf die Datei zuzugreifen. Wenn die Datei erstellt wird und das erste Zeichen der Moduszeichenfolge „u“ ist, dann soll die Datei zu dem Zeitpunkt, an dem sie geschlossen wurde, die standardmäßigen Dateizugriffsberechtigungen des Systems haben10).

Wenn die Datei erfolgreich geöffnet wurde, dann der Zeiger auf FILE darauf hingewiesen von streamptr
wird auf den Zeiger auf das Objekt gesetzt, das die geöffnete Datei steuert. Andernfalls ist der Zeiger auf FILE darauf hingewiesen von streamptr wird auf einen Nullzeiger gesetzt.

Kehrt zurück

Das fopen_s Die Funktion gibt Null zurück, wenn sie die Datei geöffnet hat. Wenn die Datei nicht geöffnet wurde oder eine Laufzeitbeschränkungsverletzung aufgetreten ist, fopen_s gibt einen Wert ungleich Null zurück.

10) Dies sind dieselben Berechtigungen, mit denen die Datei von fopen erstellt worden wäre.

  • Es gibt auch einen Vorschlag, es aufzugeben: open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm (Siehe insbesondere den Abschnitt zur Liste der Adoptierenden.)

    – Deduplizierer

    9. November 2015 um 20:22 Uhr

  • @Deduplicator: Danke für den Link – sehr interessante Lektüre. Ich stimme seiner Empfehlung zu.

    – Jonathan Leffler

    9. November 2015 um 20:44 Uhr

  • Siehe auch Verwenden Sie die „sicheren“ Funktionen von TR-24731? — aktualisiert, um einen Link zu und einen Kommentar zu N1967 aufzunehmen.

    – Jonathan Leffler

    9. November 2015 um 21:28 Uhr

Benutzer-Avatar
Michael Burr

Das fopen_s() Funktion wurde von Microsoft zur C-Laufzeit mit den folgenden grundlegenden Unterschieden hinzugefügt fopen():

  • wenn die Datei zum Schreiben geöffnet wird (“w” oder “a” im Modus angegeben), dann wird die Datei für exklusiven (nicht freigegebenen) Zugriff geöffnet (sofern die Plattform dies unterstützt).
  • wenn der “u”-Spezifizierer im Modusargument mit den “w”- oder “a”-Spezifizierern verwendet wird, hat die Datei zum Zeitpunkt des Schließens standardmäßige Systemberechtigungen für andere Benutzer, um auf die Datei zuzugreifen (was möglicherweise Nr zugreifen, wenn dies die Systemvorgabe ist).
  • wenn das “u” angegeben ist nicht in diesen Fällen verwendet wird, werden beim Schließen der Datei (oder davor) die Berechtigungen für die Datei so festgelegt, dass andere Benutzer keinen Zugriff auf die Datei haben.

Im Wesentlichen bedeutet dies, dass Dateien, die die Anwendung schreibt, standardmäßig vor anderen Benutzern geschützt sind.

Sie taten dies nicht fopen() aufgrund der Wahrscheinlichkeit, dass vorhandener Code brechen würde.

Microsoft hat sich entschieden, veraltet zu sein fopen() um Entwickler für Windows zu ermutigen, bewusste Entscheidungen darüber zu treffen, ob die von ihren Anwendungen verwendeten Dateien lose Berechtigungen haben oder nicht.

Die Antwort von Jonathan Leffler enthält die vorgeschlagene Standardisierungssprache für fopen_s(). Ich habe diese Antwort hinzugefügt, in der Hoffnung, die Begründung zu verdeutlichen.

Benutzer-Avatar
veefu

Oder ist es etwas anderes?

Bei einigen Implementierungen der von ‘fopen’ verwendeten FILE-Struktur ist der Dateideskriptor als ‘unsigned short’ definiert. Damit bleiben maximal 255 gleichzeitig geöffnete Dateien abzüglich stdin, stdout und stderr.

Während der Wert von 255 geöffneten Dateien natürlich umstritten ist, materialisiert sich dieses Implementierungsdetail auf der Solaris 8-Plattform, wenn Sie mehr als haben 252 Socket-Verbindungen! Was zuerst als scheinbar zufälliger Fehler beim Herstellen einer SSL-Verbindung mit libcurl in meiner Anwendung erschien, stellte sich als Ursache heraus, aber es bedurfte der Bereitstellung von Debug-Versionen von libcurl und openssl und der schrittweisen Anleitung des Kunden durch das Debugger-Skript, um es endlich herauszufinden.

Obwohl es nicht ausschließlich die Schuld von ‘fopen’ ist, kann man die Vorzüge erkennen, die Fesseln alter Schnittstellen abzuwerfen; Die Entscheidung, es zu verwerfen, könnte auf dem Schmerz beruhen, die Binärkompatibilität mit einer veralteten Implementierung aufrechtzuerhalten.

Benutzer-Avatar
Zügel

Die neuen Versionen tun es Parametervalidierung während die alten es nicht taten.

Weitere Informationen finden Sie in diesem SO-Thread.

  • Welche Validierung macht fopen_s, die fopen nicht kann? Wenn Sie sich ansehen opengroup.org/onlinepubs/009695399/functions/fopen.html Es gibt eine lange Liste von definierten Fehlercodes. Andere Leute haben bereits erwähnt, dass errno Thread-sicher implementiert werden kann (und vielleicht sogar auf MS ist).

    – Matthäus Flaschen

    25. Mai 2009 um 17:22 Uhr

Fadensicherheit. fopen() verwendet eine globale Variable, errnowährend fopen_s() Ersatz gibt ein errno_t und nimmt ein FILE** Argument zum Speichern des Dateizeigers.

  • Welche Validierung macht fopen_s, die fopen nicht kann? Wenn Sie sich ansehen opengroup.org/onlinepubs/009695399/functions/fopen.html Es gibt eine lange Liste von definierten Fehlercodes. Andere Leute haben bereits erwähnt, dass errno Thread-sicher implementiert werden kann (und vielleicht sogar auf MS ist).

    – Matthäus Flaschen

    25. Mai 2009 um 17:22 Uhr

1344600cookie-checkWarum kann ich fopen nicht verwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy