Movatterモバイル変換


[0]ホーム

URL:


Document numberP2467R1
Date2022-01-28
AudienceLWG
Reply-toJonathan Wakely <cxx@kayari.org>

Support exclusive mode for fstreams

Revision History

Changes since R0

Introduction

Historically, C++ iostreams libraries had anoreplace open mode thatcorresponded to theO_EXCL flag for POSIXopen.That mode was not included in the C++98 standard,presumably for portability reasons, because it wasn't in ISO C90.

Since then, ISO C added support for "exclusive" mode tofopen,so now C++'s<fstream> is missing a feature that is present in bothISO C and POSIX. We should fix this for C++23.

Background

C11 added an 'x' modifier to thefopen flags for files opened in write mode.This opens the file in "exclusive" mode, meaning thefopen call fails if thefile already exists.This is quite an important feature for certain use cases.As theWG14 N1339proposal explained,"This is necessary to eliminatea time-of-creation to time-of-use race condition vulnerability. [...]fopen() does not indicate if an existing file has been opened for writingor a new file has been created.This may lead to a program overwriting or accessing an unintended file."See N1339 for additional rationale.

C++ already incorporates the C11 changes tofopen by reference,butstd::fstream has no way to achieve the same thing.To avoid the time-of-creation to time-of-use (TOCTTOU) problemit's necessary to usefopen andFILE*(or non-standard APIs to hand an existing file handle or file descriptorto an fstream).

The 'x' modifier is widely supported. It was already supported as an extension by Glibc'sfopen(since at least version 2.4 from 2006),and is in the draft for the next revision of POSIX(because it's rebasing on C11).

Support for opening an ofstream in exclusive mode isn't even a new idea,pre-ISO iostreams provided it. References to anoreplace flag can befound in texts such as:

The flag is still present in the MSVC library, asios_base::_Noreplace,and in the Apache stdcxx implementation, asios_base::noreplace.

Design Considerations

The historical name was "noreplace" but we could consider something likeios_base::excl to correspond more closely with POSIX and C. I originallypreferred that, but have since decided that it's better to be consistentwith the historicalnoreplace name, which is still present asios_base::_Noreplace in MSVC. I think that the meaning of "noreplace"is a bit more intuitable than "exclusive". If you don't already know whatPOSIX or C means by "exclusive mode" then the name doesn't help you.

We could also consider not using anios_base::openmode for this,but just add new constructors tobasic_filebuf,basic_ofstream etc.to request the file be opened in exclusive mode. This would be novel,as all existing options for opening files (such as binary mode) are doneviaopenmode flags. There was no interest in doing it any differently whenthe idea was discussed on the LEWG reflector.

Niall Douglas raised a concern related to the ISO C specification forfopen,which is vague about what "exclusive" mode means, and allows it to be ignored.I feel we should not deviate from C, so any fixes should be done "upstream"in the C standard. That makes it simpler to implement the C++ feature in termsoffopen, rather than having to do use OS-specific APIs.

Proposed wording

This is relative to theN4901working draft.

Add a feature test macro to [version.syn]:

#define __cpp_lib_ios_noreplace    YYYYDDL // also in <ios>

Add a newopenmode constant to theios_base synopsis in [ios.base.general]as indicated:

      // [ios.openmode], openmode      using openmode = T3;      static constexpr openmode app = unspecified;      static constexpr openmode ate = unspecified;      static constexpr openmode binary = unspecified;      static constexpr openmode in = unspecified;static constexpr openmode noreplace = unspecified;      static constexpr openmode out = unspecified;      static constexpr openmode trunc = unspecified;

Add a new row to Table 123 [tag:ios.openmode]:

Element Effect(s) if set
app seek to end before each write
ate open and seek to end immediately after opening
binary perform input and output in binary mode (as opposed to text mode)
in open for input
noreplaceopen in exclusive mode
out open for output
trunc truncate an existing stream when opening

Add a new column and several new rows to Table 130 [tab:filebuf.open.modes],as indicated:

binaryinouttruncappnoreplace  
+ "w"
++"wx"
+ + "w"
+++"wx"
+ + "a"
+ "a"
+ "r"
+ + "r+"
+ + + "w+"
++++"w+x"
+ + + "a+"
+ + "a+"
+ + "wb"
+++"wbx"
+ + + "wb"
++++"wbx"
+ + + "ab"
+ + "ab"
+ + "rb"
+ + + "r+b"
+ + + + "w+b"
+++++"w+bx"
+ + + + "a+b"
+ + + "a+b"

[8]ページ先頭

©2009-2025 Movatter.jp