Subject: 28.1; Emacs crashes with native compilation on when some antivirus program is running on MS-Windows

From: Ioannis Kappas <[email-masked]>
Date: Sat, 17 Sep 2022 12:14:36 +0100

Hi,

there appears to be an issue with native compilation and some
antivirus programs on MS-Windows that could cause Emacs to crash.

This can happen when the antivirus program rewires GetProcAddress
system fn to return NULL on a call to get the address of an exported
variable/function, of which native compilation makes use of to
identify features of the compiled code.

I can't think of any straightforward instructions to reproduce the
issue without such antivirus programs running, but the crash happens
when an .el file has been compiled and the native code is partially
loaded and then there is an attempt to unload it with the
unload_comp_unit fn below

src/comp.c:
void
unload_comp_unit (struct Lisp_Native_Comp_Unit *cu)
{
  if (cu->handle == NULL)
    return;

  Lisp_Object *saved_cu = dynlib_sym (cu->handle, COMP_UNIT_SYM);
  Lisp_Object this_cu;
  XSETNATIVE_COMP_UNIT (this_cu, cu);
  if (EQ (this_cu, *saved_cu))
    *saved_cu = Qnil;
  dynlib_close (cu->handle);
}

saved_cu is returned as NULL and the program crashes without an
indication what has might have gone wrong.

I suppose a partial fix to avoid the crash (which seems good to have
regardless of antivirus interference), would be to check for NULL
pointer

void
unload_comp_unit (struct Lisp_Native_Comp_Unit *cu)
{
  if (cu->handle == NULL)
    return;

  Lisp_Object *saved_cu = dynlib_sym (cu->handle, COMP_UNIT_SYM);
  if (saved_cu)
    {
      Lisp_Object this_cu;
      XSETNATIVE_COMP_UNIT (this_cu, cu);
      if (EQ (this_cu, *saved_cu))
*saved_cu = Qnil;
    }
  dynlib_close (cu->handle);
}

Not sure if there is much we can do to circumvent the antivirus
restrictions? This at least also affects dynamically loaded modules
from loading  (but Emacs doesn't crash here, just displays the
misleading "module is not GPL compatible" warning), since it employs
the same technique to check if modules are GPL compatible

DEFUN ("module-load", Fmodule_load, Smodule_load, 1, 1, 0,
       doc: /* Load module FILE.  */)
  (Lisp_Object file)
{
  dynlib_handle_ptr handle;
  emacs_init_function module_init;
  void *gpl_sym;

  CHECK_STRING (file);
  handle = dynlib_open (SSDATA (file));
  if (!handle)
    xsignal2 (Qmodule_open_failed, file, build_string (dynlib_error ()));

  gpl_sym = dynlib_sym (handle, "plugin_is_GPL_compatible");
  if (!gpl_sym)
    xsignal1 (Qmodule_not_gpl_compatible, file);

// ...
}

In some situations (or perhaps in most?), the antivirus only applies
these restrictions to dll/eln files loaded from certain directories,
such as the user home directory starting at c:\Users. In that case, it
is possible to use the XDG_CONFIG_HOME path to set the user directory
(where the .eln files are generated at) to another, unrestricted,
location:

> mkdir c:\xdg-config\emacs
> set XDG_CONFIG_HOME=c:\xdg-config
> emacs

and then check that the above has taken effect with C-h v  user-emacs-directory.

(For XDG_CONFIG_HOME to work properly, ~/.emacs.d should not exist,
see https://www.gnu.org/software/emacs/manual/html_node/emacs/Find-Init.html
)

Thanks