emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: SIGTRAP in kill emulation on Windows


From: Alain Schneble
Subject: Re: SIGTRAP in kill emulation on Windows
Date: Thu, 25 Aug 2016 22:02:37 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.4 (windows-nt)

Eli Zaretskii <address@hidden> writes:

> Thanks.  I think this needs an entry in NEWS.

Done.

> We don't put in Emacs sources compile-time conditionals that depend on
> the version of the OS on which Emacs is built: that would preclude the
> (very popular on Windows) practice of building Emacs on one system,
> and then using it on many others, possibly running other versions of
> the OS.

Thanks for this explanation and sorry that I didn't thought about this.
I changed it to use run-time dynamic linking.

> When the function is not available, you should assign ENOTSUP to
> errno, not EINVAL, to make the error message more accurate.

Done.

> Please test what this functionality does when PID specifies a child
> process of Emacs (which is tracked via the child_procs[] array), and
> also when it specifies the calling Emacs process itself.  If any of
> these use cases cause any kind of trouble, we may wish to disallow
> such usage, to prevent users from shooting themselves in the foot.

Sending SIGTRAP to a process -- whether it's an unrelated, child or the
calling Emacs process itself -- does not seem to have any effect as long
as no debugger is attached to the receiving process.  At least this is
what I observe on Windows 10.  Shall I test on other OS versions as
well?  If so, I would have to install say an Win XP first as I do not
have one available right now.  Unfortunately, on MSDN the remark on
DebugBreakProcess says it causes the receiving process to terminate in
most cases, see
https://msdn.microsoft.com/en-us/library/windows/desktop/ms679298(v=vs.85).aspx

But with all processes I tried, none of them was ever terminated.

Many thanks for your help.
Alain

>From ecf00b52957bb0bf15735180a67cc9ce7027ff19 Mon Sep 17 00:00:00 2001
From: Alain Schneble <address@hidden>
Date: Thu, 25 Aug 2016 21:31:48 +0200
Subject: [PATCH] Support SIGTRAP in kill emulation on Windows

* src/w32proc.c (sys_kill): Translate SIGTRAP signal into a call to
DebugBreakProcess to cause a breakpoint exception to occur in the
specified process.  Windows versions prior to Windows XP that do not
support DebugBreakProcess return -1 and errno set to ENOTSUP (as opposed
to EINVAL before this change).
* src/w32proc.c: Add typedef for DebugBreakProcess function pointer and
global variable to track state of run-time dynamic linking of this
function.
* etc/NEWS: Add entry to document that 'signal-process' now supports
SIGTRAP.
---
 etc/NEWS      |  8 ++++++++
 src/w32.c     |  3 +++
 src/w32proc.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 60 insertions(+), 3 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 494a091..3d055fc 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -599,6 +599,14 @@ still apply.)
 Previously, on MS-Windows this function converted slash characters in
 file names into backslashes.  It no longer does that.
 
+---
+** 'signal-process' supports SIGTRAP on Windows XP and later.
+The 'kill' emulation on Windows now maps SIGTRAP to a call to Win32
+'DebugBreakProcess'.  This causes the receiving process to break
+execution and return control to the debugger.  If no debugger is
+attached to the receiving process, the call is typically ignored by
+the receiving process.
+
 
 * Installation Changes in Emacs 25.1
 
diff --git a/src/w32.c b/src/w32.c
index 1db3426..355e7ca 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -330,6 +330,7 @@ static BOOL g_b_init_set_named_security_info_a;
 static BOOL g_b_init_get_adapters_info;
 
 BOOL g_b_init_compare_string_w;
+BOOL g_b_init_debug_break_process;
 
 /*
   BEGIN: Wrapper functions around OpenProcessToken
@@ -9636,6 +9637,7 @@ globals_of_w32 (void)
   g_b_init_get_process_working_set_size = 0;
   g_b_init_global_memory_status = 0;
   g_b_init_global_memory_status_ex = 0;
+  g_b_init_debug_break_process = 0;
   g_b_init_equal_sid = 0;
   g_b_init_copy_sid = 0;
   g_b_init_get_length_sid = 0;
@@ -9653,6 +9655,7 @@ globals_of_w32 (void)
   g_b_init_set_named_security_info_a = 0;
   g_b_init_get_adapters_info = 0;
   g_b_init_compare_string_w = 0;
+  g_b_init_debug_break_process = 0;
   num_of_processors = 0;
   /* The following sets a handler for shutdown notifications for
      console apps. This actually applies to Emacs in both console and
diff --git a/src/w32proc.c b/src/w32proc.c
index 11a121f..bb637bc 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -66,6 +66,8 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
            + (filedata).file_base))
 
 extern BOOL g_b_init_compare_string_w;
+extern BOOL g_b_init_debug_break_process;
+
 int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
                struct timespec *, void *);
 
@@ -2494,6 +2496,9 @@ find_child_console (HWND hwnd, LPARAM arg)
   return TRUE;
 }
 
+typedef BOOL (WINAPI * DebugBreakProcess_Proc) (
+    HANDLE hProcess);
+
 /* Emulate 'kill', but only for other processes.  */
 int
 sys_kill (pid_t pid, int sig)
@@ -2507,9 +2512,9 @@ sys_kill (pid_t pid, int sig)
   if (pid < 0)
     pid = -pid;
 
-  /* Only handle signals that will result in the process dying */
+  /* Only handle signals that can be mapped to a similar behavior on Windows */
   if (sig != 0
-      && sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP)
+      && sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP && 
sig != SIGTRAP)
     {
       errno = EINVAL;
       return -1;
@@ -2552,7 +2557,11 @@ sys_kill (pid_t pid, int sig)
         close the selected frame, which does not necessarily
         terminates Emacs.  But then we are not supposed to call
         sys_kill with our own PID.  */
-      proc_hand = OpenProcess (PROCESS_TERMINATE, 0, pid);
+
+      DWORD desiredAccess =
+       (sig == SIGTRAP) ? PROCESS_ALL_ACCESS : PROCESS_TERMINATE;
+
+      proc_hand = OpenProcess (desiredAccess, 0, pid);
       if (proc_hand == NULL)
         {
          errno = EPERM;
@@ -2648,6 +2657,43 @@ sys_kill (pid_t pid, int sig)
          rc = -1;
        }
     }
+  else if (sig == SIGTRAP)
+    {
+      static DebugBreakProcess_Proc s_pfn_Debug_Break_Process = NULL;
+
+      if (g_b_init_debug_break_process == 0)
+       {
+         g_b_init_debug_break_process = 1;
+         s_pfn_Debug_Break_Process = (DebugBreakProcess_Proc)
+           GetProcAddress (GetModuleHandle ("kernel32.dll"),
+                           "DebugBreakProcess");
+       }
+
+      if (s_pfn_Debug_Break_Process == NULL)
+       {
+         errno = ENOTSUP;
+         rc = -1;
+       }
+      else if (!s_pfn_Debug_Break_Process (proc_hand))
+       {
+         DWORD err = GetLastError ();
+
+         DebPrint (("sys_kill.DebugBreakProcess return %d "
+                    "for pid %lu\n", err, pid));
+
+         switch (err)
+           {
+           case ERROR_ACCESS_DENIED:
+             errno = EPERM;
+             break;
+           default:
+             errno = EINVAL;
+             break;
+           }
+
+         rc = -1;
+       }
+    }
   else
     {
       if (NILP (Vw32_start_process_share_console) && cp && cp->hwnd)
-- 
2.8.1.windows.1


reply via email to

[Prev in Thread] Current Thread [Next in Thread]