Skip to content

Commit 6543931

Browse files
authored
Change argv and envp types in execveat declaration (#1218)
* Change argv and envp types in execveat declaration The POSIX API is poorly designed, allowing modifiable parameters that are never actually changed in practice. * Update posix.h * Refactor execveat function signatures in posix.h to improve const correctness Updated the parameter types for `libc_execveat` to accept non-const pointers for `argv` and `envp`, enhancing compatibility with existing code. Adjusted calls to `libc_execveat` in `vfork_and_execveat` to use `const_cast` for proper type handling. * Update bsd.h * Update nt_at.h * update * update * Enforce no-follow mode for unlinkat operations in nt_at.h to match POSIX semantics - Updated `calculate_nt_delete_flag` to unconditionally set `FILE_FLAG_OPEN_REPARSE_POINT` flag. - Removed conditional check for `symlink_nofollow` flag as POSIX requires unlinkat() to always operate in no-follow mode. - Added comment explaining that symlinks must be unlinked as directory entries and never resolved, matching POSIX behavior. * fix
1 parent 8166cf8 commit 6543931

File tree

4 files changed

+49
-27
lines changed

4 files changed

+49
-27
lines changed

include/fast_io_driver/install_path/bsd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ inline ::fast_io::install_path get_module_install_path()
2727
char buffer1[PATH_MAX + 1];
2828
char buffer2[PATH_MAX + 1];
2929
char *resolved{};
30-
int length = -1;
30+
// int length = -1;
3131

3232
#if defined(__NetBSD__)
3333
int mib[4]{CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME};

include/fast_io_driver/install_path/linux.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ inline ::fast_io::install_path get_module_install_path()
2424
char buffer[path_max + 1];
2525
::fast_io::install_path ret;
2626

27-
using my_ssize_t = ::std::make_signed_t<::std::size_t>;
27+
using my_ssize_t [[maybe_unused]] = ::std::make_signed_t<::std::size_t>;
2828
#if defined(__linux__) && defined(__NR_readlink)
2929
auto resolved{::fast_io::system_call<__NR_readlink, my_ssize_t>("/proc/self/exe", buffer, path_max)};
3030
system_call_throw_error(resolved);

include/fast_io_hosted/filesystem/nt_at.h

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -56,35 +56,52 @@ namespace win32::nt::details
5656

5757
inline constexpr nt_open_mode calculate_nt_delete_flag(nt_at_flags flags) noexcept
5858
{
59+
// FILE_DELETE_ON_CLOSE is not used here. Instead, use FILE_DISPOSITION_INFORMATION to control deletion!
60+
61+
// FILE_DELETE_ON_CLOSE schedules deletion at handle close.
62+
// The actual delete operation happens inside NtClose, which does not provide detailed error codes.
63+
// Therefore, you cannot reliably retrieve the actual delete failure reason.
64+
65+
// POSIX requires unlinkat() to always operate in no-follow mode (symlinks are
66+
// unconditionally unlinked as directory entries and never resolved). Therefore,
67+
// we must enforce the same no-follow behavior here.
68+
5969
nt_open_mode mode{
60-
.DesiredAccess = 0x00010000, // FILE_GENERIC_READ
61-
.FileAttributes = 0x80, // FILE_ATTRIBUTE_NORMAL
62-
.ShareAccess = 0x00000007, // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
63-
.CreateDisposition = 0x00000001, /*OPEN_EXISTING => FILE_OPEN*/
64-
.CreateOptions = 0x00001000 /*FILE_DELETE_ON_CLOSE*/
70+
.DesiredAccess = 0x00010000 | 0x00100000, // DELETE | SYNCHRONIZE
71+
.FileAttributes = 0x80, // FILE_ATTRIBUTE_NORMAL
72+
.ShareAccess = 0x00000007, // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
73+
.CreateDisposition = 0x00000001, // OPEN_EXISTING => FILE_OPEN
74+
.CreateOptions = 0x00000020 | 0x00004000 | 0x00200000 // FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_FLAG_OPEN_REPARSE_POINT
6575
};
66-
if ((flags & nt_at_flags::symlink_nofollow) == nt_at_flags::symlink_nofollow)
67-
{
68-
mode.CreateOptions |= 0x00200000; // FILE_FLAG_OPEN_REPARSE_POINT => FILE_OPEN_REPARSE_POINT (0x00200000)
69-
}
76+
7077
if ((flags & nt_at_flags::removedir) == nt_at_flags::removedir)
7178
{
72-
mode.CreateOptions |= 0x00004000; // FILE_OPEN_FOR_BACKUP_INTENT
7379
mode.CreateOptions |= 0x00000001; // FILE_DIRECTORY_FILE
7480
}
7581
else
7682
{
77-
mode.CreateOptions |= 0x00000040; // FILE_NON_DIRECTORY_FILE 0x00000040
83+
mode.CreateOptions |= 0x00000040; // FILE_NON_DIRECTORY_FILE
7884
}
85+
7986
return mode;
8087
}
8188

8289
template <bool zw>
8390
inline void nt_unlinkat_impl(void *dirhd, char16_t const *path_c_str, ::std::size_t path_size, nt_at_flags flags, bool kernel)
8491
{
85-
auto status{nt_close<zw>(
86-
nt_call_determine_kernel_callback(dirhd, path_c_str, path_size, kernel, nt_create_callback<zw>{calculate_nt_delete_flag(flags)}))};
87-
if (status)
92+
::fast_io::basic_nt_family_file<(zw ? nt_family::zw : nt_family::nt), char> file{
93+
nt_call_determine_kernel_callback(dirhd, path_c_str, path_size, kernel, nt_create_callback<zw>{calculate_nt_delete_flag(flags)})};
94+
95+
::fast_io::win32::nt::io_status_block IoStatusBlock; // no initialization needed
96+
::fast_io::win32::nt::file_disposition_information fdi{.DeleteFile = true};
97+
98+
auto status{::fast_io::win32::nt::nt_set_information_file<zw>(file.native_handle(),
99+
__builtin_addressof(IoStatusBlock),
100+
__builtin_addressof(fdi),
101+
static_cast<::std::uint_least32_t>(sizeof(fdi)),
102+
::fast_io::win32::nt::file_information_class::FileDispositionInformation)};
103+
104+
if (status) [[unlikely]]
88105
{
89106
throw_nt_error(status);
90107
}
@@ -107,7 +124,7 @@ inline void nt_mkdirat_impl(void *dirhd, char16_t const *path_c_str, ::std::size
107124
}
108125

109126
auto status{nt_close<zw>(nt_call_determine_kernel_callback(dirhd, path_c_str, path_size, kernel, nt_create_callback<zw>{m_dir_mode}))};
110-
127+
111128
if (status)
112129
{
113130
throw_nt_error(status);
@@ -777,10 +794,10 @@ inline ::fast_io::details::basic_ct_string<char_type> nt_readlinkat_impl(void *d
777794
{
778795
#if !defined(_WIN32_WINNT) || _WIN32_WINNT > 0x0600
779796
constexpr ::fast_io::win32::nt::details::nt_open_mode md{
780-
.DesiredAccess = 0x00100000 | 0x0080, // SYNCHRONIZE | FILE_READ_ATTRIBUTES
781-
.FileAttributes = 0x80, // FILE_ATTRIBUTE_NORMAL
782-
.ShareAccess = 0x00000007, // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
783-
.CreateDisposition = 0x00000001, // OPEN_EXISTING => FILE_OPEN
797+
.DesiredAccess = 0x00100000 | 0x0080, // SYNCHRONIZE | FILE_READ_ATTRIBUTES
798+
.FileAttributes = 0x80, // FILE_ATTRIBUTE_NORMAL
799+
.ShareAccess = 0x00000007, // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
800+
.CreateDisposition = 0x00000001, // OPEN_EXISTING => FILE_OPEN
784801
.CreateOptions = 0x00200000 | 0x00000020 // FILE_FLAG_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT
785802
};
786803

@@ -834,7 +851,7 @@ inline ::fast_io::details::basic_ct_string<char_type> nt_readlinkat_impl(void *d
834851
#endif
835852
else
836853
{
837-
throw_nt_error(0xC0000002);
854+
throw_nt_error(0xC0000275u /*STATUS_NOT_A_REPARSE_POINT*/);
838855
}
839856

840857
return {};
@@ -851,7 +868,7 @@ inline ::fast_io::details::basic_ct_string<char_type> nt_readlinkat_impl(void *d
851868
::fast_io::basic_nt_family_file<(zw ? nt_family::zw : nt_family::nt), char> file{
852869
nt_call_determine_kernel_callback(dirhd, path_c_str, path_size, kernel, nt_create_callback<zw>{md})};
853870

854-
throw_nt_error(0xC0000002);
871+
throw_nt_error(0xC0000275u /*STATUS_NOT_A_REPARSE_POINT*/);
855872

856873
return {};
857874
#endif

include/fast_io_hosted/process/process/posix.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ namespace fast_io
88

99
namespace posix
1010
{
11+
// The statement about argu[] and enopl] being constants is included to make explicit to future writers of language bindings that these objects are completely constant.
12+
// Due toa limitation of the ISOC standard, it is not possible to state that idea in standard C. Specifying two levels of const-qualification for the argol] and enopll
13+
// parameters for the exec functions may seem to be the natural choice, given that these functions do not modify either the array of pointers or the characters to which the
14+
// function points, but this would disallow existing correct code. Instead, only the array of pointers is noted as constant.
15+
1116
#if defined(__DARWIN_C_LEVEL) || defined(__MSDOS__)
1217
extern int libc_fexecve(int fd, char *const *argv, char *const *envp) noexcept __asm__("_fexecve");
1318
extern int libc_execveat(int dirfd, char const *pathname, char *const *argv, char *const *envp, int flags) noexcept __asm__("_execveat");
@@ -130,7 +135,7 @@ namespace details
130135
* - The returned path may differ from original open() argument due to symlinks or namespaces.
131136
*/
132137

133-
inline void portable_fd_path(int fd, char *buf, ::std::size_t bufsz)
138+
inline void portable_fd_path([[maybe_unused]] int fd, char *buf, ::std::size_t bufsz)
134139
{
135140
if (buf == nullptr || bufsz == 0u) [[unlikely]]
136141
{
@@ -179,7 +184,7 @@ inline void portable_fd_path(int fd, char *buf, ::std::size_t bufsz)
179184
::fast_io::obuffer_view linkpath_ov{linkpath, linkpath + all_sz};
180185
::fast_io::operations::print_freestanding<false>(linkpath_ov, path_str, fd, ::fast_io::mnp::chvw(::fast_io::char_literal_v<u8'\0', char>));
181186

182-
using my_ssize_t = ::std::make_signed_t<::std::size_t>;
187+
using my_ssize_t [[maybe_unused]] = ::std::make_signed_t<::std::size_t>;
183188

184189
#if defined(__linux__) && defined(__NR_readlink)
185190
auto resolved{::fast_io::system_call<__NR_readlink, my_ssize_t>(linkpath, buf, bufsz - 1u)};
@@ -763,7 +768,7 @@ inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char con
763768
flags |= AT_SYMLINK_NOFOLLOW;
764769
}
765770

766-
auto ret{::fast_io::posix::libc_execveat(dirfd, cstr, args, envp, flags)};
771+
auto ret{::fast_io::posix::libc_execveat(dirfd, cstr, const_cast<char *const *>(args), const_cast<char *const *>(envp), flags)};
767772
if (ret == -1)
768773
{
769774
t_errno = errno;
@@ -786,7 +791,7 @@ inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char con
786791
flags |= AT_SYMLINK_NOFOLLOW;
787792
}
788793

789-
auto ret{::fast_io::posix::libc_execveat(dirfd, cstr, args, envp, flags)};
794+
auto ret{::fast_io::posix::libc_execveat(dirfd, cstr, const_cast<char *const *>(args), const_cast<char *const *>(envp), flags)};
790795
if (ret == -1)
791796
{
792797
t_errno = errno;

0 commit comments

Comments
 (0)