diff --git a/newlib/libc/stdio/fclose.c b/newlib/libc/stdio/fclose.c index 983ae2cc40..4c81cbf4b7 100644 --- a/newlib/libc/stdio/fclose.c +++ b/newlib/libc/stdio/fclose.c @@ -72,6 +72,7 @@ _fclose_r (struct _reent *rptr, int __oldcancel; pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &__oldcancel); #endif + __sfp_lock_acquire (); if (!(fp->_flags2 & __SNLK)) _flockfile (fp); @@ -79,6 +80,7 @@ _fclose_r (struct _reent *rptr, { if (!(fp->_flags2 & __SNLK)) _funlockfile (fp); + __sfp_lock_release (); #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT pthread_setcancelstate (__oldcancel, &__oldcancel); #endif @@ -101,7 +103,6 @@ _fclose_r (struct _reent *rptr, FREEUB (rptr, fp); if (HASLB (fp)) FREELB (rptr, fp); - __sfp_lock_acquire (); fp->_flags = 0; /* release this FILE for reuse */ if (!(fp->_flags2 & __SNLK)) _funlockfile (fp); diff --git a/newlib/libc/stdlib/mbtowc_r.c b/newlib/libc/stdlib/mbtowc_r.c index 6c3bd3d267..cab8333d70 100644 --- a/newlib/libc/stdlib/mbtowc_r.c +++ b/newlib/libc/stdlib/mbtowc_r.c @@ -677,21 +677,6 @@ __utf8_mbtowc (struct _reent *r, state->__count = 3; else if (n < (size_t)-1) ++n; - if (n < 4) - return -2; - ch = t[i++]; - if (ch < 0x80 || ch > 0xbf) - { - _REENT_ERRNO(r) = EILSEQ; - return -1; - } - /* Note: Originally we created the low surrogate pair on systems with - wchar_t == UTF-16 *before* checking the 4th byte. This was utterly - wrong, because this failed to check the last byte for being a valid - value for a complete UTF-8 4 byte sequence. As a result, calling - functions happily digested the low surrogate and then got an entirely - different character and handled this separately, thus generating - invalid UTF-16 values. */ if (state->__count == 3 && sizeof(wchar_t) == 2) { /* On systems which have wchar_t being UTF-16 values, the value @@ -710,7 +695,15 @@ __utf8_mbtowc (struct _reent *r, | (wint_t)((state->__value.__wchb[2] & 0x3f) << 6); state->__count = 4; *pwc = 0xd800 | ((tmp - 0x10000) >> 10); - return 3; + return i; + } + if (n < 4) + return -2; + ch = t[i++]; + if (ch < 0x80 || ch > 0xbf) + { + _REENT_ERRNO(r) = EILSEQ; + return -1; } tmp = (wint_t)((state->__value.__wchb[0] & 0x07) << 18) | (wint_t)((state->__value.__wchb[1] & 0x3f) << 12) diff --git a/winsup/cygwin/clock.cc b/winsup/cygwin/clock.cc index 2a4e86922b..dc940906ed 100644 --- a/winsup/cygwin/clock.cc +++ b/winsup/cygwin/clock.cc @@ -32,22 +32,19 @@ system_tickcount_period () void inline clk_t::init () { - if (!period) - InterlockedExchange64 (&period, system_tickcount_period ()); + InterlockedCompareExchange64 (&period, system_tickcount_period (), 0); } void inline clk_realtime_t::init () { - if (!ticks_per_sec) - InterlockedExchange64 (&ticks_per_sec, system_qpc_tickspersec ()); + InterlockedCompareExchange64 (&ticks_per_sec, system_qpc_tickspersec (), 0); } void inline clk_monotonic_t::init () { - if (!ticks_per_sec) - InterlockedExchange64 (&ticks_per_sec, system_qpc_tickspersec ()); + InterlockedCompareExchange64 (&ticks_per_sec, system_qpc_tickspersec (), 0); } int diff --git a/winsup/cygwin/fhandler/base.cc b/winsup/cygwin/fhandler/base.cc index 64a5f6aea8..beebd710c5 100644 --- a/winsup/cygwin/fhandler/base.cc +++ b/winsup/cygwin/fhandler/base.cc @@ -474,6 +474,9 @@ fhandler_base::open_with_arch (int flags, mode_t mode) if (!open_setup (flags)) api_fatal ("open_setup failed, %E"); } + /* For pty and console, PATH_OPEN flag has not been set in open(). + So set it here unconditionally. */ + pc.set_isopen (); close_on_exec (flags & O_CLOEXEC); /* A unique ID is necessary to recognize fhandler entries which are diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc index 8154fcc35b..d97e604e90 100644 --- a/winsup/cygwin/fhandler/pty.cc +++ b/winsup/cygwin/fhandler/pty.cc @@ -693,8 +693,7 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on termios_printf ("bytes read %u", n); - if (!buf || ((get_ttyp ()->ti.c_lflag & FLUSHO) - && !get_ttyp ()->mask_flusho)) + if (!buf || (get_ttyp ()->ti.c_lflag & FLUSHO)) continue; /* Discard read data */ memcpy (optr, outbuf, n); @@ -714,8 +713,6 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on } out: - if (buf) - set_mask_flusho (false); termios_printf ("returning %d", rc); return rc; } @@ -2258,7 +2255,6 @@ fhandler_pty_master::write (const void *ptr, size_t len) nlen--; i--; } - process_stop_start (buf[i], get_ttyp ()); } DWORD n; diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index f88acdbbf7..2aa52737ca 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -329,6 +329,7 @@ frok::parent (volatile char * volatile stack_here) /* NEVER, EVER, call a function which in turn calls malloc&friends while this malloc lock is active! */ __malloc_lock (); + cygheap->lock (); bool locked = true; /* Remove impersonation */ @@ -483,6 +484,7 @@ frok::parent (volatile char * volatile stack_here) impure, impure_beg, impure_end, NULL); + cygheap->unlock (); __malloc_unlock (); locked = false; if (!rc) @@ -568,7 +570,10 @@ frok::parent (volatile char * volatile stack_here) if (fix_impersonation) cygheap->user.reimpersonate (); if (locked) - __malloc_unlock (); + { + cygheap->unlock (); + __malloc_unlock (); + } /* Remember to de-allocate the fd table. */ if (hchild) diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index b85e8c33ba..e0f87a31f6 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -11,7 +11,7 @@ details. */ changes to the DLL and is mainly informative in nature. */ #define CYGWIN_VERSION_DLL_MAJOR 3006 -#define CYGWIN_VERSION_DLL_MINOR 4 +#define CYGWIN_VERSION_DLL_MINOR 5 /* CYGWIN_VERSION_DLL_COMBINED gives us a single number representing the combined DLL major and minor numbers. */ diff --git a/winsup/cygwin/include/sys/termios.h b/winsup/cygwin/include/sys/termios.h index d1b4a0af5b..75e0c53482 100644 --- a/winsup/cygwin/include/sys/termios.h +++ b/winsup/cygwin/include/sys/termios.h @@ -282,6 +282,12 @@ struct termios speed_t c_ospeed; }; +struct winsize +{ + unsigned short ws_row, ws_col; + unsigned short ws_xpixel, ws_ypixel; +}; + #define termio termios #ifdef __cplusplus @@ -313,13 +319,6 @@ int tcsetwinsize(int fd, const struct winsize *winsz); #define cfgetospeed(tp) ((tp)->c_ospeed) #endif -/* Extra stuff to make porting stuff easier. */ -struct winsize -{ - unsigned short ws_row, ws_col; - unsigned short ws_xpixel, ws_ypixel; -}; - #define TIOCGWINSZ (('T' << 8) | 1) #define TIOCSWINSZ (('T' << 8) | 2) #define TIOCLINUX (('T' << 8) | 3) diff --git a/winsup/cygwin/local_includes/child_info.h b/winsup/cygwin/local_includes/child_info.h index 2da62ffaa3..25d99fa7de 100644 --- a/winsup/cygwin/local_includes/child_info.h +++ b/winsup/cygwin/local_includes/child_info.h @@ -33,7 +33,7 @@ enum child_status #define EXEC_MAGIC_SIZE sizeof(child_info) /* Change this value if you get a message indicating that it is out-of-sync. */ -#define CURR_CHILD_INFO_MAGIC 0xacbf4682U +#define CURR_CHILD_INFO_MAGIC 0x77f25a01U #include "pinfo.h" struct cchildren @@ -149,6 +149,7 @@ class child_info_spawn: public child_info void cleanup (); child_info_spawn () {}; + child_info_spawn (child_info_types); child_info_spawn (child_info_types, bool); void record_children (); void reattach_children (); diff --git a/winsup/cygwin/local_includes/cygheap.h b/winsup/cygwin/local_includes/cygheap.h index 821ccf702c..0b3fed297a 100644 --- a/winsup/cygwin/local_includes/cygheap.h +++ b/winsup/cygwin/local_includes/cygheap.h @@ -499,6 +499,9 @@ struct threadlist_t struct init_cygheap: public mini_cygheap { +private: + static SRWLOCK cygheap_protect; +public: _cmalloc_entry *chain; char *buckets[NBUCKETS]; UNICODE_STRING installation_root; @@ -542,6 +545,8 @@ struct init_cygheap: public mini_cygheap threadlist_t *find_tls (int, bool&); sigset_t compute_sigblkmask (); void unlock_tls (threadlist_t *t) { if (t) ReleaseMutex (t->mutex); } + inline void lock () { AcquireSRWLockExclusive (&cygheap_protect); } + inline void unlock () { ReleaseSRWLockExclusive (&cygheap_protect); } }; diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h index 94f4bc5521..5e8f3d30f3 100644 --- a/winsup/cygwin/local_includes/fhandler.h +++ b/winsup/cygwin/local_includes/fhandler.h @@ -2622,7 +2622,6 @@ class fhandler_pty_master: public fhandler_pty_common } void get_master_thread_param (master_thread_param_t *p); void get_master_fwd_thread_param (master_fwd_thread_param_t *p); - void set_mask_flusho (bool m) { get_ttyp ()->mask_flusho = m; } bool need_send_ctrl_c_event (); }; diff --git a/winsup/cygwin/local_includes/path.h b/winsup/cygwin/local_includes/path.h index 1fd542c96b..a9ce2c7e4b 100644 --- a/winsup/cygwin/local_includes/path.h +++ b/winsup/cygwin/local_includes/path.h @@ -244,6 +244,7 @@ class path_conv int isopen () const {return path_flags & PATH_OPEN;} int isctty_capable () const {return path_flags & PATH_CTTY;} int follow_fd_symlink () const {return path_flags & PATH_RESOLVE_PROCFD;} + void set_isopen () {path_flags |= PATH_OPEN;} void set_cygexec (bool isset) { if (isset) diff --git a/winsup/cygwin/local_includes/tty.h b/winsup/cygwin/local_includes/tty.h index 2a047d73f9..754ee900e7 100644 --- a/winsup/cygwin/local_includes/tty.h +++ b/winsup/cygwin/local_includes/tty.h @@ -135,7 +135,6 @@ class tty: public tty_min bool master_is_running_as_service; bool req_xfer_input; xfer_dir pty_input_state; - bool mask_flusho; bool discard_input; bool stop_fwd_thread; diff --git a/winsup/cygwin/mm/cygheap.cc b/winsup/cygwin/mm/cygheap.cc index 5409a6b396..4a60995c44 100644 --- a/winsup/cygwin/mm/cygheap.cc +++ b/winsup/cygwin/mm/cygheap.cc @@ -35,7 +35,7 @@ static mini_cygheap NO_COPY cygheap_dummy = init_cygheap NO_COPY *cygheap = (init_cygheap *) &cygheap_dummy; void NO_COPY *cygheap_max; -static NO_COPY SRWLOCK cygheap_protect = SRWLOCK_INIT; +SRWLOCK NO_COPY init_cygheap::cygheap_protect = SRWLOCK_INIT; struct cygheap_entry { @@ -377,7 +377,7 @@ _cmalloc (unsigned size) if (b >= NBUCKETS) return NULL; - AcquireSRWLockExclusive (&cygheap_protect); + cygheap->lock (); if (cygheap->buckets[b]) { rvc = (_cmalloc_entry *) cygheap->buckets[b]; @@ -389,7 +389,7 @@ _cmalloc (unsigned size) rvc = (_cmalloc_entry *) _csbrk (bucket_val[b] + sizeof (_cmalloc_entry)); if (!rvc) { - ReleaseSRWLockExclusive (&cygheap_protect); + cygheap->unlock (); return NULL; } @@ -397,19 +397,19 @@ _cmalloc (unsigned size) rvc->prev = cygheap->chain; cygheap->chain = rvc; } - ReleaseSRWLockExclusive (&cygheap_protect); + cygheap->unlock (); return rvc->data; } static void _cfree (void *ptr) { - AcquireSRWLockExclusive (&cygheap_protect); + cygheap->lock (); _cmalloc_entry *rvc = to_cmalloc (ptr); unsigned b = rvc->b; rvc->ptr = cygheap->buckets[b]; cygheap->buckets[b] = (char *) rvc; - ReleaseSRWLockExclusive (&cygheap_protect); + cygheap->unlock (); } static void * diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 21f3baaa12..f89df7d72f 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -2071,7 +2071,10 @@ symlink_native (const char *oldpath, path_conv &win32_newpath) e_old = wcpcpy (e_old, L"..\\"), num--; if (num > 0) e_old = wcpcpy (e_old, L".."); - wcpcpy (e_old, c_old); + if (e_old == final_oldpath->Buffer && c_old[0] == L'\0') + wcpcpy (e_old, L"."); + else + wcpcpy (e_old, c_old); } } diff --git a/winsup/cygwin/posix_timer.cc b/winsup/cygwin/posix_timer.cc index a336b2bc2d..14694a87dd 100644 --- a/winsup/cygwin/posix_timer.cc +++ b/winsup/cygwin/posix_timer.cc @@ -349,7 +349,9 @@ timer_tracker::settime (int flags, const itimerspec *new_value, / (NSPERSEC / NS100PERSEC); if (flags & TIMER_ABSTIME) { - if (clock_id == CLOCK_REALTIME) + if (clock_id == CLOCK_REALTIME_COARSE + || clock_id == CLOCK_REALTIME + || clock_id == CLOCK_REALTIME_ALARM) DueTime.QuadPart = ts + FACTOR; else /* non-REALTIME clocks require relative DueTime. */ { diff --git a/winsup/cygwin/release/3.6.5 b/winsup/cygwin/release/3.6.5 new file mode 100644 index 0000000000..8a4eff051a --- /dev/null +++ b/winsup/cygwin/release/3.6.5 @@ -0,0 +1,33 @@ +Fixes: +------ + +- Fix two minor bugs in clock and POSIX timer handling. + +- Fix an ordering problem in sys/termios.h. + Addresses: https://cygwin.com/pipermail/cygwin/2025-July/258474.html + +- Fix doxygen hang due to a deadlock between fclose() and fork(). + Addresses: https://cygwin.com/pipermail/cygwin-apps/2025-May/044318.html + Addresses: https://cygwin.com/pipermail/cygwin/2025-June/258323.html + +- Fix multi-thread safety of system(). + Addresses: https://cygwin.com/pipermail/cygwin/2025-June/258324.html + +- Revert fix handling of invalid 4 byte UTF-8 sequence. It was broken. + Addresses: https://cygwin.com/pipermail/cygwin/2025-July/258513.html + +- Instead, fix internal conversion of filenames in case of an invalid + 4 byte UTF-8 sequence. + Addresses: https://cygwin.com/pipermail/cygwin/2025-June/258358.html + +- Make process_fd correctly handle pty and console. + Addresses: https://cygwin.com/pipermail/cygwin/2025-May/258167.html + +- Fix Ctrl-O (FLUSHO) handling. + Addresses: https://cygwin.com/pipermail/cygwin/2025-August/258717.html + +- Fix multi-thread safety of fork()/exec() by adding the same locking as was + done for spawn. + Addresses: https://cygwin.com/pipermail/cygwin/2025-September/258801.html + +- Fix native symlink to '.' (a regresison in 3.6.4) diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index a7e82a0241..8a94ac0761 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -689,6 +689,8 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, int mode) return 0; } +SRWLOCK ptym_peek_lock = SRWLOCK_INIT; + static int peek_pipe (select_record *s, bool from_select) { @@ -730,10 +732,19 @@ peek_pipe (select_record *s, bool from_select) gotone = s->read_ready = true; goto out; } + if (fh->get_major () == DEV_PTYM_MAJOR) + AcquireSRWLockExclusive (&ptym_peek_lock); ssize_t n = pipe_data_available (s->fd, fh, h, PDA_READ); /* On PTY masters, check if input from the echo pipe is available. */ if (n == 0 && fh->get_echo_handle ()) n = pipe_data_available (s->fd, fh, fh->get_echo_handle (), PDA_READ); + if (fh->get_major () == DEV_PTYM_MAJOR) + { + fhandler_pty_master *fhm = (fhandler_pty_master *) fh; + while (n > 0 && (fhm->tc ()->ti.c_lflag & FLUSHO)) + n = fhm->process_slave_output (NULL, n, 0); /* Discard pipe data */ + ReleaseSRWLockExclusive (&ptym_peek_lock); + } if (n == PDA_ERROR) { @@ -759,11 +770,6 @@ peek_pipe (select_record *s, bool from_select) } out: - if (fh->get_major () == DEV_PTYM_MAJOR) - { - fhandler_pty_master *fhm = (fhandler_pty_master *) fh; - fhm->set_mask_flusho (s->read_ready); - } h = fh->get_output_handle (); if (s->write_selected && dev != FH_PIPER) { diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 3ee7c886a2..5caf97e7a6 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -895,7 +895,8 @@ child_info::child_info (unsigned in_cb, child_info_types chtype, msv_count (0), cb (in_cb), intro (PROC_MAGIC_GENERIC), magic (CHILD_INFO_MAGIC ^ MSYS2_RUNTIME_COMMIT_HEX), type (chtype), cygheap (::cygheap), cygheap_max (::cygheap_max), flag (0), retry (child_info::retry_count), - rd_proc_pipe (NULL), wr_proc_pipe (NULL), sigmask (_my_tls.sigmask) + rd_proc_pipe (NULL), wr_proc_pipe (NULL), subproc_ready (NULL), + sigmask (_my_tls.sigmask) { fhandler_union_cb = sizeof (fhandler_union); user_h = cygwin_user_h; @@ -946,6 +947,12 @@ child_info_fork::child_info_fork () : { } +child_info_spawn::child_info_spawn (child_info_types chtype) : + child_info (sizeof *this, chtype, false), hExeced (NULL), ev (NULL), + sem (NULL), moreinfo (NULL) +{ +} + child_info_spawn::child_info_spawn (child_info_types chtype, bool need_subproc_ready) : child_info (sizeof *this, chtype, need_subproc_ready) { diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 854c25a31a..2cc5716882 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -572,7 +572,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, ::cygheap->ctty ? ::cygheap->ctty->tc_getpgid () : 0; if (!iscygwin () && ctty_pgid && ctty_pgid != myself->pgid) c_flags |= CREATE_NEW_PROCESS_GROUP; - refresh_cygheap (); if (mode == _P_DETACH) /* all set */; @@ -641,6 +640,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, cygpid = (mode != _P_OVERLAY) ? create_cygwin_pid () : myself->pid; + cygheap->lock (); + refresh_cygheap (); wchar_t wcmd[(size_t) cmd]; if (!::cygheap->user.issetuid () || (::cygheap->user.saved_uid == ::cygheap->user.real_uid @@ -758,6 +759,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, ::cygheap->user.reimpersonate (); res = -1; + cygheap->unlock (); __leave; } @@ -794,8 +796,6 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, NtClose (old_winpid_hdl); real_path.get_wide_win32_path (myself->progname); // FIXME: race? sigproc_printf ("new process name %W", myself->progname); - if (!iscygwin ()) - close_all_files (); } else { @@ -811,6 +811,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, if (get_errno () != ENOMEM) set_errno (EAGAIN); res = -1; + cygheap->unlock (); __leave; } child->dwProcessId = pi.dwProcessId; @@ -846,6 +847,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, CloseHandle (pi.hProcess); ForceCloseHandle (pi.hThread); res = -1; + cygheap->unlock (); __leave; } } @@ -874,6 +876,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, /* Just mark a non-cygwin process as 'synced'. We will still eventually wait for it to exit in maybe_set_exit_code_from_windows(). */ synced = iscygwin () ? sync (pi.dwProcessId, pi.hProcess, INFINITE) : true; + cygheap->unlock (); switch (mode) { @@ -890,8 +893,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, } else { - if (iscygwin ()) - close_all_files (true); + close_all_files (iscygwin ()); if (!my_wr_proc_pipe && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT) wait_for_myself (); @@ -978,6 +980,7 @@ spawnve (int mode, const char *path, const char *const *argv, if (!envp) envp = empty_env; + child_info_spawn ch_spawn_local (_CH_NADA); switch (_P_MODE (mode)) { case _P_OVERLAY: @@ -991,7 +994,7 @@ spawnve (int mode, const char *path, const char *const *argv, case _P_WAIT: case _P_DETACH: case _P_SYSTEM: - ret = ch_spawn.worker (path, argv, envp, mode); + ret = ch_spawn_local.worker (path, argv, envp, mode); break; default: set_errno (EINVAL); diff --git a/winsup/cygwin/strfuncs.cc b/winsup/cygwin/strfuncs.cc index a022b61951..4542003cfc 100644 --- a/winsup/cygwin/strfuncs.cc +++ b/winsup/cygwin/strfuncs.cc @@ -965,8 +965,17 @@ _sys_wcstombs (char *dst, size_t len, const wchar_t *src, size_t nwc, /* Convert UNICODE private use area. Reverse functionality for the ASCII area <= 0x7f (only for path names) is transform_chars above. + Reverse functionality for invalid bytes in a multibyte sequence is - in _sys_mbstowcs below. */ + in _sys_mbstowcs below. + + FIXME? The conversion of invalid bytes from the private use area + like we do here is not actually necessary. If we skip it, the + generated multibyte string is not identical to the original multibyte + string, but it's equivalent in the sense, that another mbstowcs will + generate the same wide-char string. It would also be identical to + the same string converted by wcstombs. And while the original + multibyte string can't be converted by mbstowcs, this string can. */ if (is_path && (pw & 0xff00) == 0xf000 && (((cwc = (pw & 0xff)) <= 0x7f && tfx_rev_chars[cwc] >= 0xf000) || (cwc >= 0x80 && MB_CUR_MAX > 1))) @@ -1071,6 +1080,7 @@ _sys_mbstowcs (mbtowc_p f_mbtowc, wchar_t *dst, size_t dlen, const char *src, { wchar_t *ptr = dst; unsigned const char *pmbs = (unsigned const char *) src; + unsigned const char *got_high_surrogate = NULL; size_t count = 0; size_t len = dlen; int bytes; @@ -1142,20 +1152,62 @@ _sys_mbstowcs (mbtowc_p f_mbtowc, wchar_t *dst, size_t dlen, const char *src, Invalid bytes in a multibyte sequence are converted to the private use area which is already used to store ASCII - chars invalid in Windows filenames. This technque allows + chars invalid in Windows filenames. This technique allows to store them in a symmetric way. */ - bytes = 1; - if (dst) + + /* Special case high surrogate: if we already converted the first + 3 bytes of a sequence to a high surrogate, and only then encounter + a non-matching forth byte, the sequence is simply cut short. In + that case not the currently handled 4th byte is the invalid + sequence, but the 3 bytes converted to the high surrogate. So we + have to backtrack to the high surrogate and convert it to a + sequence of bytes in the private use area. Next, reset the + mbstate and retry to convert starting at the current byte. */ + if (got_high_surrogate) + { + if (dst) + { + --ptr; + *ptr++ = L'\xf000' | *got_high_surrogate++; + /* we know len > 0 at this point */ + *ptr++ = L'\xf000' | *got_high_surrogate++; + } + --len; + if (len > 0) + { + if (dst) + *ptr++ = L'\xf000' | *got_high_surrogate++; + --len; + } + count += 2; /* Actually 3, but we already counted one when + generating the high surrogate. */ + memset (&ps, 0, sizeof ps); + continue; + } + /* Never convert ASCII NUL */ + if (*pmbs) + { + bytes = 1; + if (dst) #ifdef STRICTLY_7BIT_ASCII - *ptr = L'\xf000' | *pmbs; + *ptr = L'\xf000' | *pmbs; #else - *ptr = *pmbs; + *ptr = *pmbs; #endif + } memset (&ps, 0, sizeof ps); } + got_high_surrogate = NULL; if (bytes > 0) { + /* Check if we got the high surrogate from a UTF-8 4 byte sequence. + This is used above to handle an invalid 4 byte sequence cut short + at byte 3. */ + /* FIXME: do we need an equivalent check for gb18030? */ + if (bytes == 3 && ps.__count == 4 && f_mbtowc == __utf8_mbtowc) + got_high_surrogate = pmbs; + pmbs += bytes; nms -= bytes; ++count; diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 76b37d6e9d..32959229b7 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -4535,8 +4535,9 @@ popen (const char *command, const char *in_type) fcntl (stdchild, F_SETFD, stdchild_state | FD_CLOEXEC); /* Start a shell process to run the given command without forking. */ - pid_t pid = ch_spawn.worker ("/usr/bin/sh", argv, environ, _P_NOWAIT, - __std[0], __std[1]); + child_info_spawn ch_spawn_local (_CH_NADA); + pid_t pid = ch_spawn_local.worker ("/usr/bin/sh", argv, environ, _P_NOWAIT, + __std[0], __std[1]); /* Reinstate the close-on-exec state */ fcntl (stdchild, F_SETFD, stdchild_state); diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc index a4b7167217..0c49dc2bdf 100644 --- a/winsup/cygwin/tty.cc +++ b/winsup/cygwin/tty.cc @@ -253,7 +253,6 @@ tty::init () req_xfer_input = false; pty_input_state = to_cyg; last_sig = 0; - mask_flusho = false; discard_input = false; stop_fwd_thread = false; }