Почему я не могу использовать fopen?

В форме предыдущий вопрос, который я задал о так называемых стихах безопасной библиотеки, я также смущен тем, что fopen() должен быть устаревшим.

Функция принимает две строки C и возвращает FILE * ptr или NULL при сбое. Где проблемы с потоковой безопасностью/проблемы переполнения строк? Или это что-то еще?

Заранее спасибо

Ответ 1

Существует официальный технический отчет ISO/IEC JTC1/SC22/WG14 (C Language) TR24731-1 (интерфейсы проверки границ) и его обоснование доступно по адресу:

Существует также работа с TR24731-2 (функции динамического распределения).

Утвержденное обоснование для fopen_s():

6.5.2 Функции доступа к файлам

При создании файла функции fopen_s и freopen_s улучшают безопасность, защищая файл от несанкционированного доступа, устанавливая его защиту файлов и открывая файл с эксклюзивным доступом.

В спецификации указано:

6.5.2.1 Функция fopen_s

Сводка

#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);

Runtime-ограничения

Ни один из streamptr, filename или mode не должен быть нулевым указателем.

Если есть нарушение ограничения времени выполнения, fopen_s не пытается открыть файл. Кроме того, если streamptr не является нулевым указателем, fopen_s устанавливает *streamptr в нулевой указатель.

Описание

Функция fopen_s открывает файл, имя которого является строкой, на которую указывает filename и связывает поток с ним.

Строка режима должна быть такой, как описано для fopen, с добавлением, что режимы, начинающиеся с символом w или может предшествовать символ u, см. ниже:

  • uw обрезать до нулевой длины или создать текстовый файл для записи, разрешения по умолчанию
  • ua append; открыть или создать текстовый файл для записи в конце файла, разрешения по умолчанию
  • uwb обрезать до нулевой длины или создать двоичный файл для записи, разрешения по умолчанию
  • uab append; открыть или создать двоичный файл для записи в конце файла, по умолчанию разрешения
  • uw+ обрезать до нулевой длины или создать текстовый файл для обновления, разрешения по умолчанию
  • ua+ append; открыть или создать текстовый файл для обновления, записать в конец файла, по умолчанию разрешения
  • uw+b или uwb+ обрезать до нулевой длины или создать двоичный файл для обновления, по умолчанию разрешения
  • ua+b или uab+ append; открыть или создать двоичный файл для обновления, записать в конец файла, разрешения по умолчанию

В той мере, в какой базовая система поддерживает концепции, файлы, открытые для записи должны быть открыты с использованием эксклюзивного (также известного как не общий) доступа. Если файл находится и первый символ строки режима не равен u, в той степени, в которой базовая система поддерживает его, файл должен иметь разрешение файла, которое предотвращает другие пользователи в системе получают доступ к файлу. Если файл создается и первый символ строки режима - u, то к тому моменту, когда файл был закрыт, он должен иметь системные разрешения доступа к файлу по умолчанию 10).

Если файл был успешно открыт, указатель на FILE указал на streamptrбудет установлен указатель на объект, управляющий открытым файлом. В противном случае указатель на FILE, на которое указывает streamptr, будет установлен нулевой указатель.

Возвращает

Функция fopen_s возвращает ноль, если она открыла файл. Если он не открыл файл или если было нарушение ограничений времени выполнения, fopen_s возвращает ненулевое значение.

10) Это те же разрешения, что файл был создан с помощью fopen.

Ответ 2

Вы можете использовать fopen(). Серьезно, не обращайте внимания на Microsoft здесь, они делают программистов настоящим плохим сервисом, отклоняясь от стандартов ISO. Кажется, они думают, что люди, пишущие код, как-то мертвы мозги и не знают, как проверить параметры перед вызовом библиотечных функций.

Если кто-то не хочет изучать тонкости программирования на С, у них действительно нет бизнеса. Они должны перейти к более безопасному языку.

Это, по-видимому, еще одна попытка блокировки вендора разработчиками Microsoft (хотя они не единственные, кто ее пробовал, поэтому я их специально не обманываю). Обычно я добавляю:

#define _CRT_SECURE_NO_WARNINGS

(или вариант "-D" в командной строке) для большинства моих проектов, чтобы гарантировать, что компилятор не будет беспокоиться при написании совершенно допустимого правового кода C.

Microsoft предоставила дополнительные функции в функции fopen_s() (кодирование файлов для одного), а также изменение способа возврата. Это может сделать его лучше для программистов Windows, но делает код неотъемлемым.

Если вы только собираетесь кодировать Windows, обязательно используйте его. Я сам предпочитаю возможность компилировать и запускать код в любом месте (с минимальными изменениями).


Начиная с C11, эти безопасные функции теперь являются частью стандарта, хотя и необязательны. Изучите Приложение K для получения полной информации.

Ответ 3

Функция fopen_s() была добавлена ​​Microsoft в среду выполнения C со следующими фундаментальными отличиями от fopen():

  • если файл открыт для записи ( "w" или "a", указанный в этом режиме), тогда файл открывается для эксклюзивного (не общего) доступа (если платформа поддерживает его).
  • если спецификатор "u" используется в аргументе mode с спецификаторами "w" или "a", то к моменту закрытия файла он будет иметь разрешения по умолчанию для системы для других пользователей для доступа к файлу (который может быть недоступен, если эта система по умолчанию).
  • если указанное значение "u" не используется в этих случаях, тогда, когда файл закрыт (или раньше), разрешения для файла будут установлены таким образом, чтобы другие пользователи не имели доступа к файлу.

По существу это означает, что файлы, которые записи приложений защищают от других пользователей по умолчанию.

Они не сделали этого с fopen() из-за того, что существующий код сломался.

Microsoft решила отказаться от fopen(), чтобы побудить разработчиков для Windows принимать осознанные решения о том, будут ли файлы, используемые их приложениями, иметь свободные разрешения или нет.

Ответ Джонатана Леффлера предоставляет предлагаемый язык стандартизации для fopen_s(). Я добавил этот ответ, надеясь разъяснить обоснование.

Ответ 4

Или это что-то еще?

Некоторые реализации структуры FILE, используемые "fopen", имеют дескриптор файла, который определяется как "unsigned short". Это дает вам максимум 255 одновременно открытых файлов, минус stdin, stdout и stderr.

Хотя значение возможности иметь 255 открытых файлов является спорным, конечно, эта информация о реализации материализуется на платформе Solaris 8, когда у вас есть более 252 разъемов! То, что впервые появилось как казалось бы случайный отказ установить SSL-соединение с использованием libcurl в моем приложении, вызвано этим, но потребовалось развертывание отладочных версий libcurl и openssl и отключение клиента через отладчик script, чтобы наконец понять это.

В то время как это не совсем ошибка "fopen", можно увидеть достоинства сбрасывания кандалов старых интерфейсов; выбор для отказа может быть основан на боли в поддержании бинарной совместимости с устаревшей реализацией.

Ответ 6

Безопасность резьбы. fopen() использует глобальную переменную errno, а замена fopen_s() возвращает errno_t и принимает аргумент FILE** для хранения указателя на файл.