emacs-diffs
[Top][All Lists]
Advanced

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

master de020255a5c: Fix crash backtraces on MS-Windows, broken by ASLR


From: Eli Zaretskii
Subject: master de020255a5c: Fix crash backtraces on MS-Windows, broken by ASLR
Date: Fri, 26 Jan 2024 08:02:58 -0500 (EST)

branch: master
commit de020255a5cef4349d786fceb19481352c49557b
Author: Eli Zaretskii <eliz@gnu.org>
Commit: Eli Zaretskii <eliz@gnu.org>

    Fix crash backtraces on MS-Windows, broken by ASLR
    
    * src/w32fns.c (DEFAULT_IMAGE_BASE): Define for 64-bit and 32-bit
    MinGW builds.
    (emacs_abort): Correct the callstack addresses for potential
    relocation of the image base due to ASLR.  This makes 'addr2line'
    be able to interpret emacs_backtrace.txt when ASLR is in effect,
    which it is on every modern version of MS-Windows.  (Bug#63365)
    
    * configure.ac (LD_SWITCH_SYSTEM_TEMACS) [mingw32]: Add comment
    about keeping the image-base values in sync with w32fns.c.
    
    * etc/DEBUG (How to disable ASLR): New section.
---
 configure.ac |  2 ++
 etc/DEBUG    | 33 ++++++++++++++++++++++++++++++++-
 src/w32fns.c | 26 +++++++++++++++++++++++---
 3 files changed, 57 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index 55f742ba8ef..fa8b04ec685 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7463,6 +7463,8 @@ case "$opsys" in
 
   mingw32)
    ## Is it any better under MinGW64 to relocate emacs into higher addresses?
+   ## If the values of -image-base are modified, the corresponding
+   ## values of DEFAULT_IMAGE_BASE in w32fns.c should be kept in sync.
    case "$canonical" in
      x86_64-*-*) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 
-Wl,-heap,0x00100000 -Wl,-image-base,0x400000000 -Wl,-entry,__start 
-Wl,-Map,./temacs.map" ;;
      *) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 
-Wl,-image-base,0x01000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;;
diff --git a/etc/DEBUG b/etc/DEBUG
index 1680aab4385..6c7f4040b8d 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -928,7 +928,10 @@ data that is modified only very rarely.)
 
 It is also useful to look at the corrupted object or data structure in
 a fresh Emacs session and compare its contents with a session that you
-are debugging.
+are debugging.  This might be somewhat harder on modern systems which
+randomize addresses of running executables (the so-called Address
+Space Layout Randomization, or ASLR, feature).  If you have this
+problem, see below under "How to disable ASLR".
 
 ** Debugging the TTY (non-windowed) version
 
@@ -1080,6 +1083,34 @@ suppresses some Valgrind false alarms during Emacs 
garbage collection:
 Unfortunately Valgrind suppression files tend to be system-dependent,
 so you will need to keep one around that matches your system.
 
+** How to disable ASLR
+
+Modern systems use the so-called Address Space Layout Randomization,
+(ASLR) feature, which randomizes the base address of running programs,
+making it harder for malicious software or hackers to find the address
+of some function or variable in a running program by looking at its
+executable file.  This causes the address of the same symbol to be
+different across rerunning of the same program.  Sometimes, it can be
+useful to disable ASLR, for example, if you want to compare objects in
+two different Emacs sessions.
+
+On GNU/Linux, you can disable ASLR temporarily with the following
+shell command:
+
+  echo 0 > /proc/sys/kernel/randomize_va_space
+
+or by running Emacs in an environment where ASLR is temporarily
+disabled:
+
+  setarch -R emacs [args...]
+
+To disable ASLR in Emacs on MS-Windows, you will have to rebuild Emacs
+while adding '-Wl,-disable-dynamicbase' to LD_SWITCH_SYSTEM_TEMACS
+variable defined in src/Makefile.  Alternatively, use some tool to
+edit the PE header of the Emacs executable file and reset the
+DYNAMIC_BASE (0x40) flag in the DllCharacteristics flags recorded by
+the PE header.
+
 ** How to recover buffer contents from an Emacs core dump file
 
 The file etc/emacs-buffer.gdb defines a set of GDB commands for
diff --git a/src/w32fns.c b/src/w32fns.c
index f8de45da7c9..f44460e52c0 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -11121,12 +11121,20 @@ my_exception_handler (EXCEPTION_POINTERS * 
exception_data)
     return prev_exception_handler (exception_data);
   return EXCEPTION_EXECUTE_HANDLER;
 }
-#endif
+#endif /* !CYGWIN */
 
 typedef USHORT (WINAPI * CaptureStackBackTrace_proc) (ULONG, ULONG, PVOID *,
                                                      PULONG);
 
 #define BACKTRACE_LIMIT_MAX 62
+/* The below must be kept in sync with the value of the
+   -Wl,-image-base switch we use in LD_SWITCH_SYSTEM_TEMACS, see
+   configure.ac.  */
+#if defined MINGW_W64 && EMACS_INT_MAX > LONG_MAX
+# define DEFAULT_IMAGE_BASE (ptrdiff_t)0x400000000
+#else  /* 32-bit MinGW build */
+# define DEFAULT_IMAGE_BASE (ptrdiff_t)0x01000000
+#endif
 
 static int
 w32_backtrace (void **buffer, int limit)
@@ -11181,6 +11189,13 @@ emacs_abort (void)
       {
        void *stack[BACKTRACE_LIMIT_MAX + 1];
        int i = w32_backtrace (stack, BACKTRACE_LIMIT_MAX + 1);
+#ifdef CYGWIN
+       ptrdiff_t addr_offset = 0;
+#else   /* MinGW */
+       /* The offset below is zero unless ASLR is in effect.  */
+       ptrdiff_t addr_offset
+         = DEFAULT_IMAGE_BASE - (ptrdiff_t)GetModuleHandle (NULL);
+#endif /* MinGW */
 
        if (i)
          {
@@ -11231,8 +11246,13 @@ emacs_abort (void)
              {
                /* stack[] gives the return addresses, whereas we want
                   the address of the call, so decrease each address
-                  by approximate size of 1 CALL instruction.  */
-               sprintf (buf, "%p\r\n", (char *)stack[j] - sizeof(void *));
+                  by approximate size of 1 CALL instruction.  We add
+                  ADDR_OFFSET to account for ASLR which changes the
+                  base address of the program's image in memory,
+                  whereas 'addr2line' needs to see addresses relative
+                  to the fixed base recorded in the PE header.  */
+               sprintf (buf, "%p\r\n",
+                        (char *)stack[j] - sizeof(void *) + addr_offset);
                if (stderr_fd >= 0)
                  write (stderr_fd, buf, strlen (buf));
                if (errfile_fd >= 0)



reply via email to

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