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

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

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

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

6 ответов

Решение

Официальный технический отчет ISO/IEC JTC1/SC22/WG14 (язык C) 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);

Время воспроизведения-ограничение

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

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

Описание

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

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

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

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

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

Возвращает

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

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

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

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

Похоже, что это просто очередная попытка Microsoft заблокировать вендора разработчиками (хотя они не единственные, кто пытается это сделать, поэтому я специально не ругаю их). Я обычно добавляю:

#define _CRT_SECURE_NO_WARNINGS

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

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

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


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

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

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

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

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

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

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

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

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

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

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

Новые версии делают проверку параметров, а старые - нет.

Смотрите эту ветку SO для получения дополнительной информации.

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

Другие вопросы по тегам