summaryrefslogtreecommitdiff
path: root/win32/win32.c
diff options
context:
space:
mode:
Diffstat (limited to 'win32/win32.c')
-rw-r--r--win32/win32.c153
1 files changed, 118 insertions, 35 deletions
diff --git a/win32/win32.c b/win32/win32.c
index c2d12a79f4..c51d53595f 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -622,21 +622,24 @@ init_env(void)
if (!GetEnvironmentVariableW(L"HOME", env, numberof(env))) {
f = FALSE;
- if (GetEnvironmentVariableW(L"HOMEDRIVE", env, numberof(env)))
- len = lstrlenW(env);
- else
- len = 0;
- if (GetEnvironmentVariableW(L"HOMEPATH", env + len, numberof(env) - len) || len) {
- f = TRUE;
- }
- else if (GetEnvironmentVariableW(L"USERPROFILE", env, numberof(env))) {
- f = TRUE;
- }
- else if (get_special_folder(CSIDL_PROFILE, env, numberof(env))) {
+ if (GetEnvironmentVariableW(L"USERPROFILE", env, numberof(env))) {
f = TRUE;
}
- else if (get_special_folder(CSIDL_PERSONAL, env, numberof(env))) {
- f = TRUE;
+ else {
+ if (GetEnvironmentVariableW(L"HOMEDRIVE", env, numberof(env)))
+ len = lstrlenW(env);
+ else
+ len = 0;
+
+ if (GetEnvironmentVariableW(L"HOMEPATH", env + len, numberof(env) - len) || len) {
+ f = TRUE;
+ }
+ else if (get_special_folder(CSIDL_PROFILE, env, numberof(env))) {
+ f = TRUE;
+ }
+ else if (get_special_folder(CSIDL_PERSONAL, env, numberof(env))) {
+ f = TRUE;
+ }
}
if (f) {
regulate_path(env);
@@ -1537,7 +1540,8 @@ rb_w32_uspawn(int mode, const char *cmd, const char *prog)
/* License: Artistic or GPL */
static rb_pid_t
-w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags, UINT cp)
+w32_spawn_process(int mode, const char *prog, char *const *argv,
+ int in_fd, int out_fd, int err_fd, DWORD flags, UINT cp)
{
int c_switch = 0;
size_t len;
@@ -1548,9 +1552,20 @@ w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags, UIN
int e = 0;
rb_pid_t ret = -1;
VALUE v = 0;
+ HANDLE in_handle = NULL, out_handle = NULL, err_handle = NULL;
if (check_spawn_mode(mode)) return -1;
+ if (in_fd >= 0) {
+ in_handle = (HANDLE)rb_w32_get_osfhandle(in_fd);
+ }
+ if (out_fd >= 0) {
+ out_handle = (HANDLE)rb_w32_get_osfhandle(out_fd);
+ }
+ if (err_fd >= 0) {
+ err_handle = (HANDLE)rb_w32_get_osfhandle(err_fd);
+ }
+
if (!prog) prog = argv[0];
if ((shell = w32_getenv("COMSPEC", cp)) &&
internal_cmd_match(prog, tmpnt = !is_command_com(shell))) {
@@ -1598,7 +1613,7 @@ w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags, UIN
if (!e) {
struct ChildRecord *child = FindFreeChildSlot();
- if (CreateChild(child, wcmd, wprog, NULL, NULL, NULL, flags)) {
+ if (CreateChild(child, wcmd, wprog, in_handle, out_handle, err_handle, flags)) {
ret = child_result(child, mode);
}
}
@@ -1613,21 +1628,21 @@ rb_pid_t
rb_w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
{
/* assume ACP */
- return w32_aspawn_flags(mode, prog, argv, flags, filecp());
+ return w32_spawn_process(mode, prog, argv, -1, -1, -1, flags, filecp());
}
/* License: Ruby's */
rb_pid_t
rb_w32_uaspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
{
- return w32_aspawn_flags(mode, prog, argv, flags, CP_UTF8);
+ return w32_spawn_process(mode, prog, argv, -1, -1, -1, flags, CP_UTF8);
}
/* License: Ruby's */
rb_pid_t
rb_w32_aspawn(int mode, const char *prog, char *const *argv)
{
- return w32_aspawn_flags(mode, prog, argv, 0, filecp());
+ return w32_spawn_process(mode, prog, argv, -1, -1, -1, 0, filecp());
}
/* License: Ruby's */
@@ -1637,6 +1652,15 @@ rb_w32_uaspawn(int mode, const char *prog, char *const *argv)
return rb_w32_uaspawn_flags(mode, prog, argv, 0);
}
+/* License: Ruby's */
+rb_pid_t
+rb_w32_uspawn_process(int mode, const char *prog, char *const *argv,
+ int in_fd, int out_fd, int err_fd, DWORD flags)
+{
+ return w32_spawn_process(mode, prog, argv, in_fd, out_fd, err_fd,
+ flags, CP_UTF8);
+}
+
/* License: Artistic or GPL */
typedef struct _NtCmdLineElement {
struct _NtCmdLineElement *next;
@@ -2369,10 +2393,8 @@ readdir_internal(DIR *dirp, BOOL (*conv)(const WCHAR *, const WCHAR *, struct di
//
// first set up the structure to return
//
- if (dirp->dirstr.d_name)
- free(dirp->dirstr.d_name);
- if (dirp->dirstr.d_altname)
- free(dirp->dirstr.d_altname);
+ free(dirp->dirstr.d_name);
+ free(dirp->dirstr.d_altname);
dirp->dirstr.d_altname = 0;
dirp->dirstr.d_altlen = 0;
conv(dirp->curr, dirp->curr + lstrlenW(dirp->curr) + 1, &dirp->dirstr, enc);
@@ -2478,14 +2500,10 @@ void
rb_w32_closedir(DIR *dirp)
{
if (dirp) {
- if (dirp->dirstr.d_name)
- free(dirp->dirstr.d_name);
- if (dirp->dirstr.d_altname)
- free(dirp->dirstr.d_altname);
- if (dirp->start)
- free(dirp->start);
- if (dirp->bits)
- free(dirp->bits);
+ free(dirp->dirstr.d_name);
+ free(dirp->dirstr.d_altname);
+ free(dirp->start);
+ free(dirp->bits);
free(dirp);
}
}
@@ -2597,9 +2615,73 @@ set_pioinfo_extra(void)
* * https://bugs.ruby-lang.org/issues/18605
*/
char *p = (char*)get_proc_address(UCRTBASE, "_isatty", NULL);
- char *pend = p;
/* _osfile(fh) & FDEV */
+#ifdef _M_ARM64
+#define IS_INSN(pc, name) ((*(pc) & name##_mask) == name##_id)
+ const int max_num_inst = 500;
+ uint32_t *start = (uint32_t*)p;
+ uint32_t *end_limit = (start + max_num_inst);
+ uint32_t *pc = start;
+
+ if (!p) {
+ fprintf(stderr, "_isatty proc not found in " UCRTBASE "\n");
+ _exit(1);
+ }
+
+ /* end of function */
+ const uint32_t ret_id = 0xd65f0000;
+ const uint32_t ret_mask = 0xfffffc1f;
+ for(; pc < end_limit; pc++) {
+ if (IS_INSN(pc, ret)) {
+ break;
+ }
+ }
+ if (pc == end_limit) {
+ fprintf(stderr, "end of _isatty not found in " UCRTBASE "\n");
+ _exit(1);
+ }
+
+ /* pioinfo instruction mark */
+ const uint32_t adrp_id = 0x90000000;
+ const uint32_t adrp_mask = 0x9f000000;
+ const uint32_t add_id = 0x11000000;
+ const uint32_t add_mask = 0x3fc00000;
+ for(; pc > start; pc--) {
+ if (IS_INSN(pc, adrp) && IS_INSN(pc + 1, add)) {
+ break;
+ }
+ }
+ if(pc == start) {
+ fprintf(stderr, "pioinfo mark not found in " UCRTBASE "\n");
+ _exit(1);
+ }
+
+ /* We now point to instructions that load address of __pioinfo:
+ * adrp x8, 0x1801d8000
+ * add x8, x8, #0xdb0
+ * https://devblogs.microsoft.com/oldnewthing/20220809-00/?p=106955
+ * The last adrp/add sequence before ret is what we are looking for.
+ */
+ const uint32_t adrp_insn = *pc;
+ const uint32_t adrp_immhi = (adrp_insn & 0x00ffffe0) >> 5;
+ const uint32_t adrp_immlo = (adrp_insn & 0x60000000) >> (5 + 19 + 5);
+ /* imm = immhi:immlo:Zeros(12), 64 */
+ const uint64_t adrp_imm = ((adrp_immhi << 2) | adrp_immlo) << 12;
+ /* base = PC64<63:12>:Zeros(12) */
+ const uint64_t adrp_base = (uint64_t)pc & 0xfffffffffffff000;
+
+ const uint32_t add_insn = *(pc + 1);
+ const uint32_t add_sh = (add_insn & 0x400000) >> (12 + 5 + 5);
+ /* case sh of
+ when '0' imm = ZeroExtend(imm12, datasize);
+ when '1' imm = ZeroExtend(imm12:Zeros(12), datasize); */
+ const uint64_t add_imm = ((add_insn & 0x3ffc00) >> (5 + 5)) << (add_sh ? 12 : 0);
+
+ __pioinfo = (ioinfo**)(adrp_base + adrp_imm + add_imm);
+#else /* _M_ARM64 */
+ char *pend = p;
+
# ifdef _WIN64
int32_t rel;
char *rip;
@@ -2649,7 +2731,8 @@ set_pioinfo_extra(void)
#else
__pioinfo = *(ioinfo***)(p);
#endif
-#endif
+#endif /* _M_ARM64 */
+#endif /* RUBY_MSVCRT_VERSION */
int fd;
fd = _open("NUL", O_RDONLY);
@@ -4378,8 +4461,8 @@ freeifaddrs(struct ifaddrs *ifp)
{
while (ifp) {
struct ifaddrs *next = ifp->ifa_next;
- if (ifp->ifa_addr) ruby_xfree(ifp->ifa_addr);
- if (ifp->ifa_name) ruby_xfree(ifp->ifa_name);
+ ruby_xfree(ifp->ifa_addr);
+ ruby_xfree(ifp->ifa_name);
ruby_xfree(ifp);
ifp = next;
}
@@ -7593,7 +7676,7 @@ rb_w32_write_console(uintptr_t strarg, int fd)
}
}
RB_GC_GUARD(str);
- if (wbuffer) free(wbuffer);
+ free(wbuffer);
return (long)reslen;
}