This is the mail archive of the cygwin-developers mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: CFA: pseudo-reloc v2


Corinna wrote:
> Here's another idea.  At one point Brian Dessent proposed a patch to
> detect a missing DLL.  Hmm, yes, here's the checkin of your patch
> implementing that, back on 2008-03-26.
> 
> I was wondering if a similar technique could be used to print an error
> message in the parent process, if the relocation failed in the child
> process.  The idea would be to generate a specific status code which
> would then catched in status_exit, just like STATUS_DLL_NOT_FOUND.

There are three error cases under consideration:
#1)  invalid pseudo_reloc version number. Right now, this uses printf
(ick!).  If we go Corinna's route (with or without also using
WriteConsole) -- how about STATUS_ILLEGAL_DLL_RELOCATION?

#2) invalid address (we can't access the specified page), which is
currently checked by 'assert (VirtualQuery (addr, &b, sizeof(b)));'.

For this, how about STATUS_NOT_MAPPED_VIEW (0xC0000019, which needs to
be added to ntdll.h). Aocording to:
http://msdn.microsoft.com/en-us/library/cc704588(PROT.10).aspx
this code means "The address range to unmap is not a mapped view." (Ok,
we're not actually trying to unmap, but VirtualQuery doesn't set an
error number on 'error' -- it just returns 0. But the only way that
would happen, I think, is if the address itself isn't mapped --
hence...NOT_MAPPED_VIEW.

Unless we want to use STATUS_ILLEGAL_DLL_RELOCATION for this, too --
which might be the smarter way to go, since then we can catch both cases
with the same code in sigproc.c and pinfo.c.

#3) there's also a non-fatal DEBUG printf.



One downside of using WriteConsole[W] is that you'll never see the
message if you're running in a terminal other than cmd.exe, nor if
you're launching the app via a shortcut. The output will go to the
"invisible" console allocated by cygwin, right?

> I'm just not sure how to generate that specific status code...

Yeah, that...

cgf suggests ExitProcess. I tried that, but the process hangs when it
calls that function. I think this has to do with the fact that
ExitProcess goes back thru the loaded DLL list and tries to call the
entry points with DLL_PROCESS_DETACH. But, since the (current) DLL is
fubared...

Now, TerminateProcess seems to work -- but then NONE of the DLLs get
notified. Oh -- and it hangs if you strace within any terminal except
cmd.exe; the strace output is identical in the two cases, but the
non-cmd one has this extra line at the end:
29661   30435 [sig] crtest_v1 4692 wait_sig: entering ReadFile loop,
my_readsig 0x17C, my_sendsig 0x180
and then it hangs.

Wierd.

> Other than that, I have no problems to use WriteConsole.

So...maybe something like the following?  This is a diff against the
current mingw/pseudo-reloc.c.  The "normal" code path (that is, none of
the error conditions are hit) works fine.

The rest of this email is about the error cases.

I tested the error path by reversing the test at line 110. In an rxvt
window, I got the following behavior:

$ ./crtest_v2.exe
$ echo $?
0

In a cmd.exe window, this is what I observerd:

$ ./crtest_v2.exe
Relocation error: bad address specified 0x00401139.
$ echo $?
0

I also attempted to modify pinfo.cc and sigproc.cc bits following Dave's
suggestion, partly so that these reloc errors would result in a 127 exit
code, just like cgf/brian's mod for STATUS_DLL_NOT_FOUND.  But I
couldn't get it to "trigger" -- I didn't get the error message I
specified in pinfo.cc, and I still got an exit code 0, not 127.  Then, I
tried this:

--------------- foo.c -----------------
#include <stdio.h>
#include <windows.h>
#include <ntdef.h>

#define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS) 0xc0000269)
#define STATUS_DLL_NOT_FOUND          ((NTSTATUS) 0xc0000135)

int main(int argc, char* argv[])
{
  TerminateProcess (GetCurrentProcess(), STATUS_ILLEGAL_DLL_RELOCATION);
  exit (1);
}
---------------------------------------

With cygwin1.dll having the modified pinfo/sigproc, and launching this
test program from bash, I would *expect* to see the message from my
patched pinfo.cc: "foo.exe: error while loading shared libraries: ?:
cannot open shared object file: illegal relocation" (there's a '?'
because this silly test program doesn't have an 'unloaded DLL' name to
put there).

If I understand the pinfo code, it's actually the *parent* process that
receives the err code >= 0xc0000000, and prints the
DLL_NOT_FOUND/ILLEGAL_DLL_RELOCATION error message.  That is, bash.

However:
$ gcc -o foo.exe foo.c
$ ./foo.exe
$ echo $?
0
(NOT 127, and NOT 1 !)

But, if I use gcc-3 -mno-cygwin:
$ gcc-3 -mno-cygwin -o foo.exe  foo.c
$ ./foo.exe
/usr/src/devel/kernel/pseudo-reloc-tests/test-app/foo.exe: error while
loading shared libraries: ?: cannot open shared object file: illegal
relocation
$ echo $?
127

which is what I expected to see in all cases.  Just to verify that it is
not a gcc-3/gcc-4 thing:

$ gcc-3 -o foo.exe  foo.c
$ ./foo.exe
$ echo $?
0

So, it's a "cygwin" thing: if the child is a cygwin app, then the
pinfo::maybe_set_exit_code_from_windows --> status_exit() code path is
NOT hit at all.  That's just weird. Help?

--
Chuck

--- winsup/mingw/pseudo-reloc.c	2009-03-17 09:18:08.463300000 -0400
+++ winsup/cygwin/lib/pseudo-reloc.c	2009-10-05 01:00:31.362000000 -0400
@@ -20,6 +20,17 @@
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+
+#if defined(__CYGWIN__)
+#include <wchar.h>
+#include <ntdef.h>
+#include <stdarg.h>
+/* copied from winsup.h */
+# define NO_COPY __attribute__((nocommon)) __attribute__((section(".data_cygwin_nocopy")))
+#define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS) 0xc0000269)
+#else
+# define NO_COPY
+#endif
  
  extern char __RUNTIME_PSEUDO_RELOC_LIST__;
  extern char __RUNTIME_PSEUDO_RELOC_LIST_END__;
@@ -42,6 +53,51 @@
   DWORD version;
 } runtime_pseudo_reloc_v2;
 
+#if defined(__CYGWIN__)
+#define MAX_WRITE_CHARS 16384
+
+/* This function is adapted from cygwin fhandler_console.cc, so
+ * I'm not sure it can be included in this "not copyrighted" file
+ */
+static int
+__write_console (HANDLE h, PWCHAR buf, DWORD len, DWORD *done)
+{
+  while (len > 0)
+    {
+      DWORD nbytes = len > MAX_WRITE_CHARS ? MAX_WRITE_CHARS : len;
+      if (!WriteConsoleW (h, buf, nbytes, done, 0))
+        {
+          /* don't bother with errno here; no-one will check it */
+          return FALSE;
+        }
+      len -= *done;
+      buf += *done;
+    }
+  return TRUE;
+}
+
+#define SHORT_MSG_BUF_SZ 64
+static int
+__print_reloc_error (const wchar_t *fmt, ...)
+{
+  WCHAR buf[SHORT_MSG_BUF_SZ];
+  DWORD len;
+  DWORD done;
+  va_list args;
+  HANDLE e = GetStdHandle (STD_ERROR_HANDLE);
+
+  if (e == INVALID_HANDLE_VALUE)
+    return 0;
+
+  va_start (args, fmt);
+  len = (DWORD) vswprintf (buf, SHORT_MSG_BUF_SZ, fmt, args);
+  va_end (args);
+
+  buf[SHORT_MSG_BUF_SZ-1] = L'\0'; /* paranoia */
+  return __write_console (e, buf, len, &done);
+}
+#endif /* __CYGWIN__ */
+
 static void
 __write_memory (void *addr,const void *src,size_t len)
 {
@@ -49,7 +105,19 @@
   DWORD oldprot;
   if (!len)
     return;
+
+#if defined(__CYGWIN__)
+  if (!VirtualQuery (addr, &b, sizeof(b)))
+    {
+      __print_reloc_error (
+        L"Relocation error: bad address specified 0x%08x.",
+        addr);
+      TerminateProcess (GetCurrentProcess(), STATUS_ILLEGAL_DLL_RELOCATION);
+    }
+#else
   assert (VirtualQuery (addr, &b, sizeof(b)));
+#endif
+
   /* Temporarily allow write access to read-only protected memory.  */
   if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE)
     VirtualProtect (b.BaseAddress, b.RegionSize, PAGE_EXECUTE_READWRITE,
@@ -95,10 +163,17 @@
   /* Check if this is a known version.  */
   if (v2_hdr->version != RP_VERSION_V2)
     {
-#ifdef DEBUG
+#if defined(__CYGWIN__)
+      __print_reloc_error (
+        L"Relocation error: invalid pseudo_reloc version %d.",
+        (int) v2_hdr->version);
+      TerminateProcess (GetCurrentProcess(), STATUS_ILLEGAL_DLL_RELOCATION);
+#else
+# if defined(DEBUG)
       fprintf (stderr, "internal mingw runtime error:"
 	       "psuedo_reloc version %d is unknown to this runtime.\n",
 	       (int) v2_hdr->version);
+# endif
 #endif
       return;
     }
@@ -139,9 +214,15 @@
 	  default:
 	    reldata=0;
 #ifdef DEBUG
+# if defined(__CYGWIN__)
+            __print_reloc_error (
+              L"Relocation error: unknown pseudo_reloc bit size %d.",
+              (int) (r->flags & 0xff));
+# else
     	    fprintf(stderr, "internal mingw runtime error: "
 		    "unknown pseudo_reloc bit size %d\n",
 		    (int) (r->flags & 0xff));
+# endif
 #endif
 	    break;
         }
@@ -170,7 +251,7 @@
 void
  _pei386_runtime_relocator ()
 {
-  static int was_init = 0;
+  static NO_COPY int was_init = 0;
   if (was_init)
     return;
   ++was_init;
Index: pinfo.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/pinfo.cc,v
retrieving revision 1.253
diff -u -p -r1.253 pinfo.cc
--- pinfo.cc	12 Jul 2009 21:15:47 -0000	1.253
+++ pinfo.cc	5 Oct 2009 05:05:35 -0000
@@ -128,6 +128,16 @@ status_exit (DWORD x)
 	x = 127;
       }
       break;
+    case STATUS_ILLEGAL_DLL_RELOCATION:
+      {
+	char posix_prog[NT_MAX_PATH];
+	path_conv pc (myself->progname, PC_NOWARN);
+	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: illegal relocation\n",
+		      posix_prog, find_first_notloaded_dll (pc));
+	x = 127;
+      }
+      break;
     default:
       x = 127;
     }
Index: sigproc.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/sigproc.cc,v
retrieving revision 1.317
diff -u -p -r1.317 sigproc.cc
--- sigproc.cc	2 Aug 2009 21:38:40 -0000	1.317
+++ sigproc.cc	5 Oct 2009 05:05:35 -0000
@@ -923,6 +923,8 @@ child_info::proc_retry (HANDLE h)
       break;
     case STATUS_DLL_NOT_FOUND:
       return exit_code;
+    case STATUS_ILLEGAL_DLL_RELOCATION:
+      return exit_code;
     case STATUS_CONTROL_C_EXIT:
       if (saw_ctrl_c ())
 	return EXITCODE_OK;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]