https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=4889f730c1fa5db8cea2780eaa1d2156c92b298a

commit 4889f730c1fa5db8cea2780eaa1d2156c92b298a
Author: Corinna Vinschen <[email protected]>
Date:   Sun Jul 19 22:38:30 2015 +0200

    Reduce stack pressure throughout Cygwin
    
            * dcrt0.cc (initial_env): Reduce size of local path buffers to
            PATH_MAX.  Allocate debugger_command from process heap.
            (init_windows_system_directory): Very early initialize new global
            variable global_progname.
            * dll_init.cc (dll_list::alloc): Make path buffer static.  Explain 
why.
            (dll_list::populate_deps): Use tmp_pathbuf for local path buffer.
            * exceptions.cc (debugger_command): Convert to PWCHAR.
            (error_start_init): Allocate debugger_command and fill with wide 
char
            strings.  Only allocate if NULL.
            (try_to_debug): Just check if debugger_command is a NULL pointer to
            return.  Drop conversion from char to WCHAR and drop local variable
            dbg_cmd.
            * globals.cc (global_progname): New global variable to store Windows
            application path.
            * pinfo.cc (pinfo_basic::pinfo_basic): Just copy progname over from
            global_progname.
            (pinfo::status_exit): Let path_conv create the POSIX path to
            avoid local buffer.
            * pseudo_reloc.cc (__report_error): Utilize global_progname, drop 
local
            buffer.
            * smallprint.cc (__small_vsprintf): Just utilize global_progname for
            %P format specifier.
            (__small_vswprintf): Ditto.
            * strace.cc (PROTECT): Change to reflect x being a pointer.  
Reformat.
            (CHECK): Ditto.  Reformat.
            (strace::activate): Utilize global_progname, drop local buffer.
            Fix formatting.
            (strace::vsprntf): Reduce size of local progname buffer to NAME_MAX.
            Copy and, if necessary, convert only the last path component to
            progname.
            (strace_buf_guard): New muto.
            (buf): New static pointer.
            (strace::vprntf): Use buf under strace_buf_guard lock only.  
Allocate
            buffer space for buf on Windows heap.
            * wow64.cc (wow64_respawn_process): Utilize global_progname, drop
            local path buffer.
    
    Signed-off-by: Corinna Vinschen <[email protected]>

Diff:
---
 winsup/cygwin/ChangeLog       | 39 ++++++++++++++++++++
 winsup/cygwin/dcrt0.cc        | 14 +++++--
 winsup/cygwin/dll_init.cc     |  9 ++++-
 winsup/cygwin/exceptions.cc   | 38 +++++++++----------
 winsup/cygwin/globals.cc      |  1 +
 winsup/cygwin/pinfo.cc        | 12 +++---
 winsup/cygwin/pseudo-reloc.cc |  8 ++--
 winsup/cygwin/smallprint.cc   | 14 ++-----
 winsup/cygwin/strace.cc       | 85 +++++++++++++++++++++++++------------------
 winsup/cygwin/wow64.cc        |  6 +--
 10 files changed, 141 insertions(+), 85 deletions(-)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 4342929..a606cca 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,42 @@
+2015-07-19  Corinna Vinschen  <[email protected]>
+
+       * dcrt0.cc (initial_env): Reduce size of local path buffers to
+       PATH_MAX.  Allocate debugger_command from process heap.
+       (init_windows_system_directory): Very early initialize new global
+       variable global_progname.
+       * dll_init.cc (dll_list::alloc): Make path buffer static.  Explain why.
+       (dll_list::populate_deps): Use tmp_pathbuf for local path buffer.
+       * exceptions.cc (debugger_command): Convert to PWCHAR.
+       (error_start_init): Allocate debugger_command and fill with wide char
+       strings.  Only allocate if NULL.
+       (try_to_debug): Just check if debugger_command is a NULL pointer to
+       return.  Drop conversion from char to WCHAR and drop local variable
+       dbg_cmd.
+       * globals.cc (global_progname): New global variable to store Windows
+       application path.
+       * pinfo.cc (pinfo_basic::pinfo_basic): Just copy progname over from
+       global_progname.
+       (pinfo::status_exit): Let path_conv create the POSIX path to
+       avoid local buffer.
+       * pseudo_reloc.cc (__report_error): Utilize global_progname, drop local
+       buffer.
+       * smallprint.cc (__small_vsprintf): Just utilize global_progname for
+       %P format specifier.
+       (__small_vswprintf): Ditto.
+       * strace.cc (PROTECT): Change to reflect x being a pointer.  Reformat.
+       (CHECK): Ditto.  Reformat.
+       (strace::activate): Utilize global_progname, drop local buffer.
+       Fix formatting.
+       (strace::vsprntf): Reduce size of local progname buffer to NAME_MAX.
+       Copy and, if necessary, convert only the last path component to
+       progname.
+       (strace_buf_guard): New muto.
+       (buf): New static pointer.
+       (strace::vprntf): Use buf under strace_buf_guard lock only.  Allocate
+       buffer space for buf on Windows heap.
+       * wow64.cc (wow64_respawn_process): Utilize global_progname, drop
+       local path buffer.
+
 2015-07-18  Corinna Vinschen  <[email protected]>
 
        * gendef: Remove unused 64 bit versions of __sjfault and __ljfault.
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
index 1874fe5..d7f5494 100644
--- a/winsup/cygwin/dcrt0.cc
+++ b/winsup/cygwin/dcrt0.cc
@@ -509,11 +509,11 @@ initial_env ()
     _cygwin_testing = 1;
 
 #ifdef DEBUGGING
-  char buf[NT_MAX_PATH];
+  char buf[PATH_MAX];
   if (GetEnvironmentVariableA ("CYGWIN_DEBUG", buf, sizeof (buf) - 1))
     {
-      char buf1[NT_MAX_PATH];
-      GetModuleFileName (NULL, buf1, NT_MAX_PATH);
+      char buf1[PATH_MAX];
+      GetModuleFileName (NULL, buf1, PATH_MAX);
       char *p = strpbrk (buf, ":=");
       if (!p)
        p = (char *) "gdb.exe -nw";
@@ -521,6 +521,13 @@ initial_env ()
        *p++ = '\0';
       if (strcasestr (buf1, buf))
        {
+         extern PWCHAR debugger_command;
+
+         debugger_command = (PWCHAR) HeapAlloc (GetProcessHeap (), 0,
+                                                (2 * NT_MAX_PATH + 20)
+                                                * sizeof (WCHAR));
+         if (!debugger_command)
+           return;
          error_start_init (p);
          jit_debug = true;
          try_to_debug ();
@@ -736,6 +743,7 @@ void
 dll_crt0_0 ()
 {
   wincap.init ();
+  GetModuleFileNameW (NULL, global_progname, NT_MAX_PATH);
   child_proc_info = get_cygwin_startup_info ();
   init_windows_system_directory ();
   initial_env ();
diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc
index 51ef186..313b0ff 100644
--- a/winsup/cygwin/dll_init.cc
+++ b/winsup/cygwin/dll_init.cc
@@ -25,6 +25,7 @@ details. */
 #include <wchar.h>
 #include <sys/reent.h>
 #include <assert.h>
+#include <tls_pbuf.h>
 
 extern void __stdcall check_sanity_and_sync (per_process *);
 
@@ -178,7 +179,9 @@ dll_list::find_by_modname (const PWCHAR modname)
 dll *
 dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
 {
-  WCHAR buf[NT_MAX_PATH];
+  /* Called under loader lock conditions so this function can't be called
+     multiple times in parallel.  A static buffer is safe. */
+  static WCHAR buf[NT_MAX_PATH];
   GetModuleFileNameW (h, buf, NT_MAX_PATH);
   PWCHAR name = buf;
   if (!wcsncmp (name, L"\\\\?\\", 4))
@@ -264,7 +267,9 @@ dll_list::append (dll* d)
 
 void dll_list::populate_deps (dll* d)
 {
-  WCHAR wmodname[NT_MAX_PATH];
+  tmp_pathbuf tp;
+
+  PWCHAR wmodname = tp.w_get ();
   pefile* pef = (pefile*) d->handle;
   PIMAGE_DATA_DIRECTORY dd = pef->idata_dir (IMAGE_DIRECTORY_ENTRY_IMPORT);
   /* Annoyance: calling crealloc with a NULL pointer will use the
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 0025be6..c4b0761 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -46,7 +46,7 @@ details. */
 #define CALL_HANDLER_RETRY_OUTER 10
 #define CALL_HANDLER_RETRY_INNER 10
 
-char debugger_command[2 * NT_MAX_PATH + 20];
+PWCHAR debugger_command;
 extern u_char _sigbe;
 extern u_char _sigdelayed_end;
 
@@ -112,18 +112,19 @@ extern "C" void
 error_start_init (const char *buf)
 {
   if (!buf || !*buf)
-    {
-      debugger_command[0] = '\0';
-      return;
-    }
-
-  char pgm[NT_MAX_PATH];
-  if (!GetModuleFileName (NULL, pgm, NT_MAX_PATH))
-    strcpy (pgm, "cygwin1.dll");
-  for (char *p = strchr (pgm, '\\'); p; p = strchr (p, '\\'))
-    *p = '/';
+    return;
+  if (!debugger_command &&
+      !(debugger_command = (PWCHAR) malloc ((2 * NT_MAX_PATH + 20)
+                                           * sizeof (WCHAR))))
+    return;
 
-  __small_sprintf (debugger_command, "%s \"%s\"", buf, pgm);
+  PWCHAR cp = debugger_command
+             + sys_mbstowcs (debugger_command, NT_MAX_PATH, buf) - 1;
+  cp = wcpcpy (cp, L" \"");
+  wcpcpy (cp, global_progname);
+  for (PWCHAR p = wcschr (cp, L'\\'); p; p = wcschr (p, L'\\'))
+    *p = L'/';
+  wcscat (cp, L"\"");
 }
 
 void
@@ -474,9 +475,9 @@ cygwin_stackdump ()
 extern "C" int
 try_to_debug (bool waitloop)
 {
-  debug_printf ("debugger_command '%s'", debugger_command);
-  if (*debugger_command == '\0')
+  if (!debugger_command)
     return 0;
+  debug_printf ("debugger_command '%W'", debugger_command);
   if (being_debugged ())
     {
       extern void break_here ();
@@ -484,8 +485,8 @@ try_to_debug (bool waitloop)
       return 0;
     }
 
-  __small_sprintf (strchr (debugger_command, '\0'), " %u",
-                  GetCurrentProcessId ());
+  PWCHAR dbg_end = wcschr (debugger_command, L'\0');
+  __small_swprintf (dbg_end, L" %u", GetCurrentProcessId ());
 
   LONG prio = GetThreadPriority (GetCurrentThread ());
   SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
@@ -529,10 +530,8 @@ try_to_debug (bool waitloop)
   console_printf ("*** starting debugger for pid %u, tid %u\n",
                  cygwin_pid (GetCurrentProcessId ()), GetCurrentThreadId ());
   BOOL dbg;
-  WCHAR dbg_cmd[strlen(debugger_command) + 1];
-  sys_mbstowcs (dbg_cmd, strlen(debugger_command) + 1, debugger_command);
   dbg = CreateProcessW (NULL,
-                       dbg_cmd,
+                       debugger_command,
                        NULL,
                        NULL,
                        FALSE,
@@ -542,6 +541,7 @@ try_to_debug (bool waitloop)
                        &si,
                        &pi);
 
+  *dbg_end = L'\0';
   if (!dbg)
     system_printf ("Failed to start debugger, %E");
   else
diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc
index 92f9acc..3897419 100644
--- a/winsup/cygwin/globals.cc
+++ b/winsup/cygwin/globals.cc
@@ -31,6 +31,7 @@ UINT windows_system_directory_length;
 WCHAR system_wow64_directory[MAX_PATH];
 UINT system_wow64_directory_length;
 #endif /* !__x86_64__ */
+WCHAR global_progname[NT_MAX_PATH];
 
 /* program exit the program */
 
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index 038937e..d0b4cd9 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -38,7 +38,9 @@ public:
 pinfo_basic::pinfo_basic ()
 {
   pid = dwProcessId = GetCurrentProcessId ();
-  GetModuleFileNameW (NULL, progname, sizeof (progname) / sizeof (WCHAR));
+  PWCHAR pend = wcpncpy (progname, global_progname,
+                        sizeof (progname) / sizeof (WCHAR) - 1);
+  *pend = L'\0';
   /* Default uid/gid are needed very early to initialize shared user info. */
   uid = ILLEGAL_UID;
   gid = ILLEGAL_GID;
@@ -120,20 +122,18 @@ pinfo::status_exit (DWORD x)
     {
     case STATUS_DLL_NOT_FOUND:
       {
-       char posix_prog[NT_MAX_PATH];
        path_conv pc;
        if (!procinfo)
-          pc.check ("/dev/null");
+          pc.check ("/dev/null", PC_NOWARN | PC_POSIX);
        else
          {
            UNICODE_STRING uc;
            RtlInitUnicodeString(&uc, procinfo->progname);
-           pc.check (&uc, PC_NOWARN);
+           pc.check (&uc, PC_NOWARN | PC_POSIX);
          }
-       mount_table->conv_to_posix_path (pc.get_win32 (), posix_prog, 1);
        small_printf ("%s: error while loading shared libraries: %s: cannot "
                      "open shared object file: No such file or directory\n",
-                     posix_prog, find_first_notloaded_dll (pc));
+                     pc.get_posix (), find_first_notloaded_dll (pc));
        x = 127 << 8;
       }
       break;
diff --git a/winsup/cygwin/pseudo-reloc.cc b/winsup/cygwin/pseudo-reloc.cc
index bdcde2a..f374d22 100644
--- a/winsup/cygwin/pseudo-reloc.cc
+++ b/winsup/cygwin/pseudo-reloc.cc
@@ -85,20 +85,18 @@ __report_error (const char *msg, ...)
    * cygwin ptys.
    */
   char buf[128];
-  WCHAR module[PATH_MAX];
-  char * posix_module = NULL;
+  char *posix_module = NULL;
   static const char UNKNOWN_MODULE[] = "<unknown module>: ";
   static const char CYGWIN_FAILURE_MSG[] = "Cygwin runtime failure: ";
   HANDLE errh = GetStdHandle (STD_ERROR_HANDLE);
-  ssize_t modulelen = GetModuleFileNameW (NULL, module, PATH_MAX);
   va_list args;
 
   /* FIXME: cleanup further to avoid old use of cygwin_internal */
   if (errh == INVALID_HANDLE_VALUE)
     cygwin_internal (CW_EXIT_PROCESS, STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION, 1);
 
-  if (modulelen > 0)
-    posix_module = (char *) cygwin_create_path (CCP_WIN_W_TO_POSIX, module);
+  posix_module = (char *) cygwin_create_path (CCP_WIN_W_TO_POSIX,
+                                             global_progname);
 
   va_start (args, msg);
   vsnprintf (buf, sizeof (buf), msg, args);
diff --git a/winsup/cygwin/smallprint.cc b/winsup/cygwin/smallprint.cc
index a1e0f70..2a8b1ce 100644
--- a/winsup/cygwin/smallprint.cc
+++ b/winsup/cygwin/smallprint.cc
@@ -284,12 +284,6 @@ gen_decimalLL:
                  dst = rnarg (dst, 16, 0, len, pad);
 #endif
                  break;
-               case 'P':
-                 if (!GetModuleFileName (NULL, tmp, NT_MAX_PATH))
-                   s = "cygwin program";
-                 else
-                   s = tmp;
-                 goto fillin;
                case '.':
                  n = strtol (fmt, (char **) &fmt, 10);
                  if (*fmt++ != 's')
@@ -311,6 +305,9 @@ gen_decimalLL:
                    else
                      *dst++ = *s++;
                  break;
+               case 'P':
+                 RtlInitUnicodeString (us = &uw, global_progname);
+                 goto wfillin;
                case 'W':
                  w = va_arg (ap, PWCHAR);
                  RtlInitUnicodeString (us = &uw, w ?: L"(null)");
@@ -613,10 +610,7 @@ gen_decimalLL:
 #endif
                  break;
                case L'P':
-                 if (!GetModuleFileNameW (NULL, tmp, NT_MAX_PATH))
-                   RtlInitUnicodeString (us = &uw, L"cygwin program");
-                 else
-                   RtlInitUnicodeString (us = &uw, tmp);
+                 RtlInitUnicodeString (us = &uw, global_progname);
                  goto fillin;
                case L'.':
                  n = wcstoul (fmt, (wchar_t **) &fmt, 10);
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index 9d1c3c2..434f92d 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -21,9 +21,13 @@ details. */
 #include "dtable.h"
 #include "cygheap.h"
 #include "child_info.h"
+#include "sync.h"
 
-#define PROTECT(x) x[sizeof (x)-1] = 0
-#define CHECK(x) if (x[sizeof (x)-1] != 0) { small_printf ("array bound 
exceeded %d\n", __LINE__); ExitProcess (1); }
+#define PROTECT(x) {x[NT_MAX_PATH - 1] = '\0';}
+#define CHECK(x) if (x[NT_MAX_PATH - 1] != '\0') \
+                  { small_printf ("array bound exceeded %d\n", __LINE__); \
+                    ExitProcess (1); \
+                  }
 
 class strace NO_COPY strace;
 
@@ -35,25 +39,25 @@ strace::activate (bool isfork)
   if (!_active && being_debugged ())
     {
       char buf[30];
-      __small_sprintf (buf, "cYg%8x %lx %d", _STRACE_INTERFACE_ACTIVATE_ADDR, 
&_active, isfork);
+      __small_sprintf (buf, "cYg%8x %lx %d",
+                      _STRACE_INTERFACE_ACTIVATE_ADDR, &_active, isfork);
       OutputDebugString (buf);
       if (_active)
        {
          char pidbuf[80];
-         WCHAR progname_buf[NT_MAX_PATH - 512];
-         WCHAR *progname;
+         PWCHAR progname;
          if (myself)
            {
-             __small_sprintf (pidbuf, "(pid %d, ppid %d, windows pid %u)", 
myself->pid,
-                              myself->ppid ?: 1, GetCurrentProcessId ());
+             __small_sprintf (pidbuf, "(pid %d, ppid %d, windows pid %u)",
+                              myself->pid, myself->ppid ?: 1,
+                              GetCurrentProcessId ());
              progname = myself->progname;
            }
          else
            {
-             GetModuleFileNameW (NULL, progname_buf,
-                                 sizeof progname_buf / sizeof (WCHAR));
-             __small_sprintf (pidbuf, "(windows pid %u)", GetCurrentProcessId 
());
-             progname = progname_buf;
+             __small_sprintf (pidbuf, "(windows pid %u)",
+                              GetCurrentProcessId ());
+             progname = global_progname;
            }
          prntf (1, NULL, "**********************************************");
          prntf (1, NULL, "Program name: %W %s", progname, pidbuf);
@@ -151,32 +155,32 @@ strace::vsprntf (char *buf, const char *func, const char 
*infmt, va_list ap)
   else
     {
       PWCHAR pn = NULL;
-      WCHAR progname[NT_MAX_PATH];
-      if (!cygwin_finished_initializing)
-       pn = (myself) ? myself->progname : NULL;
-      else if (__progname)
-       sys_mbstowcs(pn = progname, NT_MAX_PATH, __progname);
-
-      WCHAR empty[1] = {};
-      PWCHAR p;
-      if (!pn)
-       GetModuleFileNameW (NULL, pn = progname, sizeof (progname));
-      if (!pn)
-       p = empty;
-      else if ((p = wcsrchr (pn, L'\\')) != NULL)
-       p++;
-      else if ((p = wcsrchr (pn, L'/')) != NULL)
-       p++;
+      WCHAR progname[NAME_MAX];
+      if (cygwin_finished_initializing && __progname)
+       {
+         char *p = strrchr (__progname, '/');
+         if (p)
+           ++p;
+         else
+           p = __progname;
+         char *pe = strrchr (p, '.');
+         if (!pe || !ascii_strcasematch (pe, ".exe"))
+           pe = strrchr (p, '\0');
+         sys_mbstowcs (pn = progname, NAME_MAX, p, pe - p);
+       }
       else
-       p = pn;
-      if (p != progname)
-       wcscpy (progname, p);
-      if ((p = wcsrchr (progname, '.')) != NULL
-         && !wcscasecmp (p, L".exe"))
-       *p = '\000';
-      p = progname;
+       {
+         PWCHAR p = wcsrchr (global_progname, L'\\');
+         ++p;
+         PWCHAR pe = wcsrchr (p, '.');
+         if (!pe || wcscasecmp (pe, L".exe"))
+           pe = wcsrchr (p, L'\0');
+         pe = wcpncpy (progname, p, pe - p);
+         *pe = L'\0';
+         pn = progname;
+       }
       char tmpbuf[20];
-      count = __small_sprintf (buf, fmt, *p ? p : L"?", mypid (tmpbuf),
+      count = __small_sprintf (buf, fmt, pn, mypid (tmpbuf),
                               execing ? "!" : "");
       if (func)
        count += getfunc (buf + count, func);
@@ -235,14 +239,22 @@ strace::write_childpid (pid_t pid)
 
 /* Printf function used when tracing system calls.
    Warning: DO NOT SET ERRNO HERE! */
+static NO_COPY muto strace_buf_guard;
+static NO_COPY char *buf;
 
 void
 strace::vprntf (unsigned category, const char *func, const char *fmt, va_list 
ap)
 {
   DWORD err = GetLastError ();
   int len;
-  char buf[NT_MAX_PATH];
 
+  strace_buf_guard.init ("smallprint_buf")->acquire ();
+  /* Creating buffer on Windows process heap to drop stack pressure and
+     keeping our .bss small. */
+  if (!buf)
+    buf = (char *) HeapAlloc (GetProcessHeap (), 0, NT_MAX_PATH);
+  if (!buf)
+    return;
   PROTECT (buf);
   SetLastError (err);
 
@@ -272,6 +284,7 @@ strace::vprntf (unsigned category, const char *func, const 
char *fmt, va_list ap
   if (active ())
     write (category, buf, len);
 #endif
+  strace_buf_guard.release ();
   SetLastError (err);
 }
 
diff --git a/winsup/cygwin/wow64.cc b/winsup/cygwin/wow64.cc
index 070b9c2..098d6c2 100644
--- a/winsup/cygwin/wow64.cc
+++ b/winsup/cygwin/wow64.cc
@@ -192,19 +192,17 @@ wow64_revert_to_original_stack (PVOID &allocationbase)
 void
 wow64_respawn_process ()
 {
-  WCHAR path[PATH_MAX];
   PROCESS_INFORMATION pi;
   STARTUPINFOW si;
   DWORD ret = 0;
 
-  GetModuleFileNameW (NULL, path, PATH_MAX);
   GetStartupInfoW (&si);
-  if (!CreateProcessW (path, GetCommandLineW (), NULL, NULL, TRUE,
+  if (!CreateProcessW (global_progname, GetCommandLineW (), NULL, NULL, TRUE,
                       CREATE_DEFAULT_ERROR_MODE
                       | GetPriorityClass (GetCurrentProcess ()),
                       NULL, NULL, &si, &pi))
     api_fatal ("Failed to create process <%W> <%W>, %E",
-              path, GetCommandLineW ());
+              global_progname, GetCommandLineW ());
   CloseHandle (pi.hThread);
   if (WaitForSingleObject (pi.hProcess, INFINITE) == WAIT_FAILED)
     api_fatal ("Waiting for process %u failed, %E", pi.dwProcessId);

Reply via email to