Почему я не могу использовать 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", можно увидеть достоинства сбрасывания кандалов старых интерфейсов; выбор для отказа может быть основан на боли в поддержании бинарной совместимости с устаревшей реализацией.
Ответ 5
В новых версиях проверка параметров, тогда как старые не сделали.
Подробнее см. этот поток SO.
Ответ 6
Безопасность резьбы. fopen()
использует глобальную переменную errno
, а замена fopen_s()
возвращает errno_t
и принимает аргумент FILE**
для хранения указателя на файл.