__xpg_strerror_r should not clobber strerror buffer

2011-05-21 Thread Eric Blake
POSIX says that no other function in the standard should clobber the
strerror buffer.  Our strerror_r is a GNU extension, so it can get away
with clobbering the buffer (but if we wanted to fix it, we would have to
separate _my_tls.locals.strerror_buf into two different buffers).
perror() is still broken, but that needs to be fixed in newlib.  But
__xpg_strerror_r, which is our POSIX strerror_r variant, has to be fixed
in cygwin.

Meanwhile, glibc just patched strerror this week to print negative
errnum as a negative 32-bit int, rather than as a positive unsigned
long; cygwin should do likewise.

2011-05-21  Eric Blake  ebl...@redhat.com

* errno.cc (strerror): Print unknown errno as int.
(__xpg_strerror_r): Likewise, and don't clobber strerror buffer.

Index: errno.cc
===
RCS file: /cvs/src/src/winsup/cygwin/errno.cc,v
retrieving revision 1.82
diff -u -p -r1.82 errno.cc
--- errno.cc18 May 2011 01:25:41 -  1.82
+++ errno.cc22 May 2011 01:22:17 -
@@ -382,8 +382,8 @@ strerror (int errnum)
   char *errstr = strerror_worker (errnum);
   if (!errstr)
 {
-  __small_sprintf (errstr = _my_tls.locals.strerror_buf, Unknown
error %u,
-  (unsigned) errnum);
+  __small_sprintf (errstr = _my_tls.locals.strerror_buf, Unknown
error %d,
+   errnum);
   errno = _impure_ptr-_errno = EINVAL;
 }
   return errstr;
@@ -409,10 +409,10 @@ __xpg_strerror_r (int errnum, char *buf,
 return ERANGE;
   int result = 0;
   char *error = strerror_worker (errnum);
+  char tmp[sizeof Unknown error -2147483648];
   if (!error)
 {
-  __small_sprintf (error = _my_tls.locals.strerror_buf, Unknown
error %u,
-  (unsigned) errnum);
+  __small_sprintf (error = tmp, Unknown error %d, errnum);
   result = EINVAL;
 }
   if (strlen (error) = n)


-- 
Eric Blake   ebl...@redhat.com+1-801-349-2682
Libvirt virtualization library http://libvirt.org



signature.asc
Description: OpenPGP digital signature


Re: __xpg_strerror_r should not clobber strerror buffer

2011-05-21 Thread Christopher Faylor
On Sat, May 21, 2011 at 07:26:37PM -0600, Eric Blake wrote:
POSIX says that no other function in the standard should clobber the
strerror buffer.  Our strerror_r is a GNU extension, so it can get away
with clobbering the buffer (but if we wanted to fix it, we would have to
separate _my_tls.locals.strerror_buf into two different buffers).
perror() is still broken, but that needs to be fixed in newlib.  But
__xpg_strerror_r, which is our POSIX strerror_r variant, has to be fixed
in cygwin.

Meanwhile, glibc just patched strerror this week to print negative
errnum as a negative 32-bit int, rather than as a positive unsigned
long; cygwin should do likewise.

2011-05-21  Eric Blake  ebl...@redhat.com

   * errno.cc (strerror): Print unknown errno as int.
   (__xpg_strerror_r): Likewise, and don't clobber strerror buffer.

Looks good.  Please check in.

Thanks.

cgf


Re: Improvements to fork handling (1/5)

2011-05-21 Thread Christopher Faylor
On Wed, May 11, 2011 at 02:31:23PM -0400, Ryan Johnson wrote:
Hi all,

This is the first of a series of patches, sent in separate emails as 
requested.

The first patch allows a child which failed due to address space 
clobbers to report cleanly back to the parent. As a result, DLL_LINK 
which land wrong, DLL_LOAD whose space gets clobbered, and failure to 
replicate the cygheap, generate retries and dispense with the terminal 
spam. Handling of unexpected errors should not have changed. Further, 
the patch fixes several sources of access violations and crashes, 
including:
- accessing invalid state after failing to notice that a 
statically-linked dll loaded at the wrong location
- accessing invalid state while running dtors on a failed forkee. I 
follow cgf's approach of simply not running any dtors, based on the 
observation that dlls in the parent (gcc_s!) can store state about other 
dlls and crash trying to access that state in the child, even if they 
appeared to map properly in both processes.
- attempting to generate a stack trace when somebody in the call chain 
used alloca(). This one is only sidestepped here, because we eliminate 
the access violations and api_fatal calls which would have triggered the 
problematic stack traces. I have a separate patch which allows offending 
functions to disable stack traces, if folks are interested, but it was 
kind of noisy so I left it out for now (cygwin uses alloca pretty 
liberally!).

Ryan

diff --git a/child_info.h b/child_info.h
--- a/child_info.h
+++ b/child_info.h
@@ -92,6 +92,18 @@ public:
   void alloc_stack_hard_way (volatile char *);
 };
 
+/* Several well-known problems can prevent us from patching up a
+   forkee; when such errors arise the child should exit cleanly (with
+   a failure code for the parent) rather than dumping stack.  */
+#define fork_api_fatal(fmt, args...)  \
+  do  \
+{ \
+  sigproc_printf (fmt,## args);   \
+  fork_info-handle_failure (-1); \
+} \
+  while(0)
+
+
 class fhandler_base;
 
 class cygheap_exec_info
diff --git a/dll_init.cc b/dll_init.cc
--- a/dll_init.cc
+++ b/dll_init.cc
@@ -19,6 +19,7 @@ details. */
 #include dtable.h
 #include cygheap.h
 #include pinfo.h
+#include child_info.h
 #include cygtls.h
 #include exception.h
 #include wchar.h
@@ -131,10 +132,16 @@ dll_list::alloc (HINSTANCE h, per_proces
 {
   if (!in_forkee)
   d-count++; /* Yes.  Bump the usage count. */
+  else if (d-handle != h)
+  fork_api_fatal (Location of %W changed from %p (parent) to %p (child),
+  d-name, d-handle, h);

You seem to be guranteeing a failure in a condition which could conceivably work
ok for simple applications, i.e., if a dll loads in a different location that
is not necessarily going to cause a problem.

   d-p = p;
 }
   else
 {
+  if (in_forkee)
+  system_printf (Unexpected dll loaded during fork: %W, name);
+  
   /* FIXME: Change this to new at some point. */
   d = (dll *) cmalloc (HEAP_2_DLL, sizeof (*d) + (namelen * sizeof 
 (*name)));
 
@@ -371,7 +378,6 @@ dll_list::load_after_fork (HANDLE parent
 preferred_block = reserve_at (d-name, (DWORD) h);
 
   }
-  in_forkee = false;
 }
 
 struct dllcrt0_info
diff --git a/dll_init.h b/dll_init.h
--- a/dll_init.h
+++ b/dll_init.h
@@ -57,7 +57,7 @@ struct dll
   int init ();
   void run_dtors ()
   {
-if (has_dtors)
+if (has_dtors  !in_forkee)
   {
   has_dtors = 0;
   p.run_dtors ();

Isn't this already handled in dll_init.cc?

diff --git a/fork.cc b/fork.cc
--- a/fork.cc
+++ b/fork.cc
@@ -233,6 +233,7 @@ frok::child (volatile char * volatile he
   sync_with_parent (loaded dlls, true);
 }
 
+  in_forkee = false;
   init_console_handler (myself-ctty = 0);
   ForceCloseHandle1 (fork_info-forker_finished, forker_finished);
 
@@ -393,10 +394,13 @@ frok::parent (volatile char * volatile s
 if (!exit_code)
   continue;
 this_errno = EAGAIN;
-/* Not thread safe, but do we care? */
-__small_sprintf (errbuf, died waiting for longjmp before 
initialization, 
- retry %d, exit code %p, ch.retry, exit_code);
-error = errbuf;
+if (exit_code != EXITCODE_FORK_FAILED)
+  {
+/* Not thread safe, but do we care? */
+__small_sprintf (errbuf, died waiting for longjmp before 
initialization, 
+ retry %d, exit code %p, ch.retry, exit_code);
+error = errbuf;
+  }
 goto cleanup;
   }
   break;
@@ -515,7 +519,8 @@ frok::parent (volatile char * volatile s
   if (!ch.sync (child-pid, pi.hProcess, 

Re: Improvements to fork handling (2/5)

2011-05-21 Thread Christopher Faylor
On Wed, May 11, 2011 at 02:31:37PM -0400, Ryan Johnson wrote:
Hi all,

This patch has the parent sort its dll list topologically by 
dependencies. Previously, attempts to load a DLL_LOAD dll risked pulling 
in dependencies automatically, and the latter would then not benefit 
from the code which encourages them to land in the right places.  The 
dependency tracking is achieved using a simple class which allows to 
introspect a mapped dll image and pull out the dependencies it lists. 
The code currently rebuilds the dependency list at every fork rather 
than attempt to update it properly as modules are loaded and unloaded. 
Note that the topsort optimization affects only cygwin dlls, so any 
windows dlls which are pulled in dynamically (directly or indirectly) 
will still impose the usual risk of address space clobbers.

This seems CPU and memory intensive during a time for which we already
know is very slow.  Is the benefit really worth it?  How much more robust
does it make forking?

cgf