Skip to content

Commit 3190223

Browse files
authored
Enhance socket and process handling in Windows platform (#1234)
- Added noexcept specifier to constructors in `ip` struct for improved exception safety. - Updated function signatures in `apis.h` for better clarity and consistency. - Introduced new exception handling structures in `win32_definitions.h` to support enhanced error management. - Improved DNS iterator functionality in `win32_9xa_dns.h` by adding a new method to convert to `ip_address`. - Refactored `posix.h` to improve execveat handling, including better path resolution and error management. - Cleaned up thread handling in `wasi.h` by ensuring proper pragma usage.
1 parent a90b08f commit 3190223

File tree

6 files changed

+153
-81
lines changed

6 files changed

+153
-81
lines changed

include/fast_io_core_impl/socket/ip.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ struct ip
4040
}
4141

4242
inline explicit constexpr ip() noexcept = default;
43-
inline explicit constexpr ip(ipv4 add)
43+
inline explicit constexpr ip(ipv4 add) noexcept
4444
: address{.address = {.v4 = add.address}, .isv4 = true}, port(add.port)
4545
{}
46-
inline explicit constexpr ip(ipv6 add)
46+
inline explicit constexpr ip(ipv6 add) noexcept
4747
: address{.address = {.v6 = add.address}}, port(add.port)
4848
{}
49-
inline explicit constexpr ip(ip_address addr, ::std::uint_least16_t prt)
49+
inline explicit constexpr ip(ip_address addr, ::std::uint_least16_t prt) noexcept
5050
: address{addr}, port{prt}
5151
{}
5252
};

include/fast_io_hosted/platforms/win32/apis.h

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL SetWaitableTimer(void *, ::std::int_lea
172172
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL CancelWaitableTimer(void *) noexcept FAST_IO_WINSTDCALL_RENAME(CancelWaitableTimer, 4);
173173
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL LookupPrivilegeValueA(char const *__restrict, char const *__restrict, ::std::int_least64_t *) noexcept FAST_IO_WINSTDCALL_RENAME(LookupPrivilegeValueA, 12);
174174
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL LookupPrivilegeValueW(char16_t const *__restrict, char16_t const *__restrict, ::std::int_least64_t *) noexcept FAST_IO_WINSTDCALL_RENAME(LookupPrivilegeValueW, 12);
175-
FAST_IO_DLLIMPORT void *FAST_IO_WINSTDCALL CreateThread(security_attributes *, ::std::size_t, ::std::uint_least32_t (FAST_IO_WINSTDCALL*)(void*), void*, ::std::uint_least32_t, ::std::uint_least32_t*) noexcept FAST_IO_WINSTDCALL_RENAME(CreateThread, 24);
175+
FAST_IO_DLLIMPORT void *FAST_IO_WINSTDCALL CreateThread(security_attributes *, ::std::size_t, ::std::uint_least32_t(FAST_IO_WINSTDCALL *)(void *), void *, ::std::uint_least32_t, ::std::uint_least32_t *) noexcept FAST_IO_WINSTDCALL_RENAME(CreateThread, 24);
176176
FAST_IO_DLLIMPORT char16_t **FAST_IO_WINSTDCALL CommandLineToArgvW(char16_t const *, int *) noexcept FAST_IO_WINSTDCALL_RENAME(CommandLineToArgvW, 8);
177177
FAST_IO_DLLIMPORT void *FAST_IO_WINSTDCALL LocalFree(void *) noexcept FAST_IO_WINSTDCALL_RENAME(LocalFree, 4);
178178
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL PrefetchVirtualMemory(void *, ::std::size_t, ::fast_io::win32::win32_memory_range_entry *, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(PrefetchVirtualMemory, 16);
@@ -182,16 +182,17 @@ FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL Sleep(::std::uint_least32_t) noexcept
182182
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL SwitchToThread() noexcept FAST_IO_WINSTDCALL_RENAME(SwitchToThread, 0);
183183
FAST_IO_DLLIMPORT char16_t *FAST_IO_WINSTDCALL GetEnvironmentStringsW() noexcept FAST_IO_WINSTDCALL_RENAME(GetEnvironmentStringsW, 0);
184184
FAST_IO_DLLIMPORT char *FAST_IO_WINSTDCALL GetEnvironmentStringsA() noexcept FAST_IO_WINSTDCALL_RENAME(GetEnvironmentStringsA, 0);
185-
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL FreeEnvironmentStringsW(char16_t*) noexcept FAST_IO_WINSTDCALL_RENAME(FreeEnvironmentStringsW, 4);
186-
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL FreeEnvironmentStringsA(char*) noexcept FAST_IO_WINSTDCALL_RENAME(FreeEnvironmentStringsA, 4);
187-
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL getsockopt(::std::size_t, int, int, char*, int*) noexcept FAST_IO_WINSTDCALL_RENAME(getsockopt, 20);
188-
FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL GetFullPathNameW(char16_t const*, ::std::uint_least32_t, char16_t*, char16_t**) noexcept FAST_IO_WINSTDCALL_RENAME(GetFullPathNameW, 16);
189-
FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL GetFullPathNameA(char const*, ::std::uint_least32_t, char*, char**) noexcept FAST_IO_WINSTDCALL_RENAME(GetFullPathNameA, 16);
190-
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL GetVolumeInformationW(char16_t const*, char16_t*, ::std::uint_least32_t, ::std::uint_least32_t*, ::std::uint_least32_t*, ::std::uint_least32_t*, char16_t*, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(GetVolumeInformationW, 32);
191-
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL GetVolumeInformationA(char const*, char*, ::std::uint_least32_t, ::std::uint_least32_t*, ::std::uint_least32_t*, ::std::uint_least32_t*, char*, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(GetVolumeInformationA, 32);
192-
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL GetDiskFreeSpaceW(char16_t const*, ::std::uint_least32_t*, ::std::uint_least32_t*, ::std::uint_least32_t*, ::std::uint_least32_t*) noexcept FAST_IO_WINSTDCALL_RENAME(GetDiskFreeSpaceW, 20);
193-
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL GetDiskFreeSpaceA(char const*, ::std::uint_least32_t*, ::std::uint_least32_t*, ::std::uint_least32_t*, ::std::uint_least32_t*) noexcept FAST_IO_WINSTDCALL_RENAME(GetDiskFreeSpaceA, 20);
185+
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL FreeEnvironmentStringsW(char16_t *) noexcept FAST_IO_WINSTDCALL_RENAME(FreeEnvironmentStringsW, 4);
186+
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL FreeEnvironmentStringsA(char *) noexcept FAST_IO_WINSTDCALL_RENAME(FreeEnvironmentStringsA, 4);
187+
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL getsockopt(::std::size_t, int, int, char *, int *) noexcept FAST_IO_WINSTDCALL_RENAME(getsockopt, 20);
188+
FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL GetFullPathNameW(char16_t const *, ::std::uint_least32_t, char16_t *, char16_t **) noexcept FAST_IO_WINSTDCALL_RENAME(GetFullPathNameW, 16);
189+
FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL GetFullPathNameA(char const *, ::std::uint_least32_t, char *, char **) noexcept FAST_IO_WINSTDCALL_RENAME(GetFullPathNameA, 16);
190+
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL GetVolumeInformationW(char16_t const *, char16_t *, ::std::uint_least32_t, ::std::uint_least32_t *, ::std::uint_least32_t *, ::std::uint_least32_t *, char16_t *, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(GetVolumeInformationW, 32);
191+
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL GetVolumeInformationA(char const *, char *, ::std::uint_least32_t, ::std::uint_least32_t *, ::std::uint_least32_t *, ::std::uint_least32_t *, char *, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(GetVolumeInformationA, 32);
192+
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL GetDiskFreeSpaceW(char16_t const *, ::std::uint_least32_t *, ::std::uint_least32_t *, ::std::uint_least32_t *, ::std::uint_least32_t *) noexcept FAST_IO_WINSTDCALL_RENAME(GetDiskFreeSpaceW, 20);
193+
FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL GetDiskFreeSpaceA(char const *, ::std::uint_least32_t *, ::std::uint_least32_t *, ::std::uint_least32_t *, ::std::uint_least32_t *) noexcept FAST_IO_WINSTDCALL_RENAME(GetDiskFreeSpaceA, 20);
194194
FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL RaiseException(::std::uint_least32_t, ::std::uint_least32_t, ::std::uint_least32_t, ::std::size_t const *) noexcept FAST_IO_WINSTDCALL_RENAME(RaiseException, 16);
195195
FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL ExitProcess(::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(ExitProcess, 4);
196+
FAST_IO_DLLIMPORT void *FAST_IO_WINSTDCALL AddVectoredExceptionHandler(::std::uint_least32_t, pvectored_exception_handler) noexcept FAST_IO_WINSTDCALL_RENAME(AddVectoredExceptionHandler, 8);
196197

197198
} // namespace fast_io::win32

include/fast_io_hosted/platforms/win32/win32_definitions.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,4 +459,46 @@ struct win32_memory_range_entry
459459
void* VirtualAddress;
460460
::std::size_t NumberOfBytes;
461461
};
462+
463+
inline constexpr ::std::size_t exception_maximum_parameters{15u};
464+
465+
struct exception_record
466+
{
467+
::std::uint_least32_t ExceptionCode;
468+
::std::uint_least32_t ExceptionFlags;
469+
exception_record* ExceptionRecord;
470+
void* ExceptionAddress;
471+
::std::uint_least32_t NumberParameters;
472+
::std::size_t ExceptionInformation[exception_maximum_parameters];
473+
};
474+
475+
struct exception_record32
476+
{
477+
::std::uint_least32_t ExceptionCode;
478+
::std::uint_least32_t ExceptionFlags;
479+
::std::uint_least32_t ExceptionRecord;
480+
::std::uint_least32_t ExceptionAddress;
481+
::std::uint_least32_t NumberParameters;
482+
::std::uint_least32_t ExceptionInformation[exception_maximum_parameters];
483+
};
484+
485+
struct exception_record64
486+
{
487+
::std::uint_least32_t ExceptionCode;
488+
::std::uint_least32_t ExceptionFlags;
489+
::std::uint_least64_t ExceptionRecord;
490+
::std::uint_least64_t ExceptionAddress;
491+
::std::uint_least32_t NumberParameters;
492+
::std::uint_least32_t UnusedAlignment;
493+
::std::uint_least64_t ExceptionInformation[exception_maximum_parameters];
494+
};
495+
496+
struct exception_pointers
497+
{
498+
exception_record* ExceptionRecord;
499+
void* ContextRecord;
500+
};
501+
502+
using pvectored_exception_handler = ::std::int_least32_t(FAST_IO_WINSTDCALL *)(exception_pointers *) noexcept;
503+
462504
} // namespace fast_io::win32

include/fast_io_hosted/platforms/win32_network/win32_9xa_dns.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ struct win32_9xa_dns_iterator
114114

115115
inline constexpr win32_9xa_dns_iterator operator*(win32_9xa_dns_iterator d) noexcept
116116
{
117-
return {d.res};
117+
return {d.res, d.pos};
118118
}
119119

120120
inline constexpr win32_9xa_dns_iterator &operator++(win32_9xa_dns_iterator &d) noexcept
@@ -159,11 +159,16 @@ inline constexpr bool operator!=(win32_9xa_dns_iterator a, ::std::default_sentin
159159
return !(a == b);
160160
}
161161

162-
inline constexpr ::fast_io::ip to_ip(win32_9xa_dns_iterator d, ::std::uint_least16_t port)
162+
inline constexpr ::fast_io::ip to_ip(win32_9xa_dns_iterator d, ::std::uint_least16_t port) noexcept
163163
{
164164
return ::fast_io::details::hostent_to_ip_impl(d.res, d.pos, port);
165165
}
166166

167+
inline constexpr ::fast_io::ip_address to_ip_address(win32_9xa_dns_iterator d) noexcept
168+
{
169+
return ::fast_io::details::hostent_to_ip_address_impl(d.res, d.pos);
170+
}
171+
167172
namespace details
168173
{
169174
inline ::fast_io::win32::hostent *win32_9xa_gethostbyname_impl(char const *name)

include/fast_io_hosted/process/process/posix.h

Lines changed: 89 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ namespace posix
1313
// 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
1414
// function points, but this would disallow existing correct code. Instead, only the array of pointers is noted as constant.
1515

16-
#if defined(__DARWIN_C_LEVEL) || defined(__MSDOS__)
16+
#if (defined(__APPLE__) || defined(__DARWIN_C_LEVEL)) || (defined(__MSDOS__) || defined(__DJGPP__))
17+
extern int libc_execve(char const *pathname, char *const *argv, char *const *envp) noexcept __asm__("_execve");
1718
extern int libc_fexecve(int fd, char *const *argv, char *const *envp) noexcept __asm__("_fexecve");
1819
extern int libc_execveat(int dirfd, char const *pathname, char *const *argv, char *const *envp, int flags) noexcept __asm__("_execveat");
1920
extern int libc_kill(pid_t pid, int sig) noexcept __asm__("_kill");
@@ -24,6 +25,7 @@ extern pid_t libc_waitpid(pid_t pid, int *status, int options) noexcept __asm__(
2425
[[noreturn]] extern void libc_exit(int status) noexcept __asm__("__Exit");
2526
[[noreturn]] extern void libc_exit2(int status) noexcept __asm__("__exit");
2627
#else
28+
extern int libc_execve(char const *pathname, char *const *argv, char *const *envp) noexcept __asm__("execve");
2729
extern int libc_fexecve(int fd, char *const *argv, char *const *envp) noexcept __asm__("fexecve");
2830
extern int libc_execveat(int dirfd, char const *pathname, char *const *argv, char *const *envp, int flags) noexcept __asm__("execveat");
2931
extern int libc_kill(pid_t pid, int sig) noexcept __asm__("kill");
@@ -403,20 +405,102 @@ inline void posix_waitpid_noexcept(pid_t pid) noexcept
403405

404406
inline int posix_execveat(int dirfd, char const *cstr, char const *const *args, char const *const *envp, process_mode mode) noexcept
405407
{
406-
bool const follow{(mode & process_mode::follow) == process_mode::follow};
408+
[[maybe_unused]] bool const follow{(mode & process_mode::follow) == process_mode::follow};
407409

408410
#if defined(__linux__) && defined(__NR_execveat)
411+
// linux execveat
412+
409413
int flags{};
410414
if (!follow)
411415
{
412416
flags |= AT_SYMLINK_NOFOLLOW;
413417
}
414418
return -(system_call<__NR_execveat, int>(dirfd, cstr, args, envp, flags));
419+
420+
#elif defined(__APPLE__) || defined(__DARWIN_C_LEVEL)
421+
// macOS / Darwin: no public execveat/fexecve
422+
// Fallback: emulate execveat(dirfd, path, ...) using execve() and F_GETPATH.
423+
// Limitations:
424+
// - AT_SYMLINK_NOFOLLOW is ignored (no equivalent execve flag).
425+
// - AT_EMPTY_PATH / other execveat-specific flags are not supported.
426+
427+
if (cstr == nullptr)
428+
{
429+
errno = EFAULT;
430+
return errno;
431+
}
432+
433+
#if defined(AT_FDCWD)
434+
constexpr int fdcwd_val{AT_FDCWD};
435+
#else
436+
constexpr int fdcwd_val{-2};
437+
#endif
438+
439+
// Absolute path: ignore dirfd, behave like execve()
440+
if (cstr[0] == '/')
441+
{
442+
::fast_io::posix::libc_execve(cstr, const_cast<char *const *>(args), const_cast<char *const *>(envp));
443+
return errno;
444+
}
445+
446+
// Relative path and "current working directory" dirfd: just use execve()
447+
if (dirfd == fdcwd_val)
448+
{
449+
::fast_io::posix::libc_execve(cstr, const_cast<char *const *>(args), const_cast<char *const *>(envp));
450+
return errno;
451+
}
452+
453+
// dirfd refers to a directory: resolve its absolute path via F_GETPATH and
454+
// append the relative filename to form an absolute pathname.
455+
#if defined(PATH_MAX)
456+
constexpr ::std::size_t path_max{PATH_MAX};
457+
#elif defined(MAXPATHLEN)
458+
constexpr ::std::size_t path_max{MAXPATHLEN};
459+
#else
460+
constexpr ::std::size_t path_max{1024u};
461+
#endif
462+
463+
constexpr ::std::size_t dirbuf_sz{path_max + 1u};
464+
465+
char dirbuf[dirbuf_sz]{};
466+
auto ret_dir{::fast_io::details::posix::fcntl(dirfd, F_GETPATH, dirbuf)};
467+
if (ret_dir == -1) [[unlikely]]
468+
{
469+
return errno;
470+
}
471+
472+
auto dir_len{::fast_io::cstr_nlen(dirbuf, path_max)};
473+
auto name_len{::fast_io::cstr_len(cstr)};
474+
475+
// Ensure combined path fits into our fixed buffer
476+
if (dir_len + 1u + name_len >= path_max) [[unlikely]]
477+
{
478+
errno = ENAMETOOLONG;
479+
return errno;
480+
}
481+
482+
char fullpath[dirbuf_sz];
483+
auto it{fullpath};
484+
for (::std::size_t i{}; i < dir_len; ++i)
485+
{
486+
it[i] = dirbuf[i];
487+
}
488+
it[dir_len] = '/';
489+
for (::std::size_t i{}; i < name_len; ++i)
490+
{
491+
it[dir_len + 1u + i] = cstr[i];
492+
}
493+
fullpath[dir_len + 1u + name_len] = '\0';
494+
495+
::fast_io::posix::libc_execve(fullpath, const_cast<char *const *>(args), const_cast<char *const *>(envp));
496+
return errno;
415497
#else
498+
// POSIX 2008: openat + fexecve
499+
416500
int flags{O_RDONLY};
417501
if (!follow)
418502
{
419-
flags |= AT_SYMLINK_NOFOLLOW;
503+
flags |= O_NOFOLLOW;
420504
}
421505
int fd{::fast_io::details::my_posix_openat_noexcept(dirfd, cstr, flags, 0644)};
422506
if (fd != -1) [[likely]]
@@ -716,7 +800,7 @@ struct fd_remapper
716800
};
717801

718802
// only used in vfork_execveat_common_impl()
719-
inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char const *const *args, char const *const *envp, unsigned volatile &t_errno, process_mode mode) noexcept
803+
inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char const *const *args, char const *const *envp, unsigned volatile &t_errno, process_mode mode)
720804
{
721805
// vfork can only be called through libc wrapper
722806
pid = ::fast_io::posix::libc_vfork();
@@ -741,68 +825,8 @@ inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char con
741825
}
742826
#endif
743827

744-
bool const follow{(mode & process_mode::follow) == process_mode::follow};
745-
746-
#if defined(__linux__)
747-
748-
#if defined(__NR_execveat)
749-
int flags{};
750-
if (!follow)
751-
{
752-
flags |= AT_SYMLINK_NOFOLLOW;
753-
}
754-
755-
auto ret{system_call<__NR_execveat, int>(dirfd, cstr, args, envp, flags)};
756-
if (::fast_io::linux_system_call_fails(ret))
757-
{
758-
t_errno = -ret;
759-
}
760-
else
761-
{
762-
t_errno = 0;
763-
}
764-
#else
765-
int flags{};
766-
if (!follow)
767-
{
768-
flags |= AT_SYMLINK_NOFOLLOW;
769-
}
770-
771-
auto ret{::fast_io::posix::libc_execveat(dirfd, cstr, const_cast<char *const *>(args), const_cast<char *const *>(envp), flags)};
772-
if (ret == -1)
773-
{
774-
t_errno = errno;
775-
}
776-
else
777-
{
778-
t_errno = 0;
779-
}
780-
#endif
781-
782-
#if defined(__NR_exit_group)
783-
::fast_io::system_call_no_return<__NR_exit_group>(127);
784-
#else
785-
::fast_io::system_call_no_return<__NR_exit>(127);
786-
#endif
787-
#else
788-
int flags{};
789-
if (!follow)
790-
{
791-
flags |= AT_SYMLINK_NOFOLLOW;
792-
}
793-
794-
auto ret{::fast_io::posix::libc_execveat(dirfd, cstr, const_cast<char *const *>(args), const_cast<char *const *>(envp), flags)};
795-
if (ret == -1)
796-
{
797-
t_errno = errno;
798-
}
799-
else
800-
{
801-
t_errno = 0;
802-
}
803-
828+
t_errno = posix_execveat(dirfd, cstr, args, envp, mode);
804829
::fast_io::posix::libc_exit2(127);
805-
#endif
806830

807831
__builtin_unreachable();
808832
}

include/fast_io_hosted/threads/thread/wasi.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#pragma once
1+
#pragma once
22

33
#if defined(__wasi__)
44

0 commit comments

Comments
 (0)