Skip to content

WineFix: keep libplugins.dll loaded (crash on a stale call into the plugin host) - #61

Open
jfacemyer wants to merge 1 commit into
noahc3:devfrom
jfacemyer:winefix-keep-plugin-host-loaded
Open

jfacemyer wants to merge 1 commit into
noahc3:devfrom
jfacemyer:winefix-keep-plugin-host-loaded

Conversation

@jfacemyer

Copy link
Copy Markdown

Fixes crashes that arrive at no particular moment and blame whatever was in flight; ours was on a JPEG import.

What the dump shows. The main thread faults with 0xC0000005 trying to execute an address inside libplugins.dll. By then the module is in the unloaded-module list, twice at the same base, and its memory is free:

UnloadedModuleList  0x6fffc5230000 +0x00408000  libplugins.dll  (twice)
MemoryInfoList      0x6fffc5220000 +0x2b0000    FREE  NOACCESS

The call came in through Serif.Interop.Persona.dll -> libscripting.dll. The scripting engine still holds an entry point into a module the loader has released. Two entries at the same base mean load/free cycles during the session, not teardown.

Fix. Hold one reference to libplugins.dll that is never released, taken in OnLoad before Affinity can run the cycle even once. The refcount can't reach zero, so the pages stay mapped and the stale pointer stays valid. This removes the consequence, not whatever drops the last reference; on Windows something presumably keeps the module loaded in a way Wine's loader doesn't. It isn't a Harmony patch, because the caller is native and there's no managed frame to intercept.

Setting. pin_plugin_host: on by default, restart required, listed with the crash fixes. When active, it logs "Holding a reference to libplugins.dll".

Tested on Affinity 3.3.0.4850 under Wine 11.16 and 11.18: it loads and logs the hold at startup. The crash was intermittent, so there's no before/after number.

A crash dump taken on a JPEG import has the main thread faulting with
0xC0000005 trying to *execute* 0x6fffc524d6c0. That address is inside
libplugins.dll, and by the time of the dump libplugins.dll is in the
unloaded-module list with the memory at that address marked FREE/NOACCESS:

  UnloadedModuleList  0x6fffc5230000 +0x00408000  libplugins.dll  (twice)
  MemoryInfoList      0x6fffc5220000 +0x2b0000    FREE  NOACCESS

The call came in through Serif.Interop.Persona.dll -> libscripting.dll, so
the scripting engine was still holding an entry point into a module the
loader had released. Two entries at the same base address say this is a
load/free cycle during the session rather than teardown, which fits crashes
that arrive at no particular moment and blame whatever operation was in
flight -- here an image import, which had nothing to do with it.

Hold one reference that is never released. The refcount cannot then reach
zero, the pages stay mapped, and the stale pointer stays valid. This does
not fix whatever drops the last reference; it removes the consequence.
Something on Windows presumably keeps this module up in a way Wine's loader
does not, since the same build does not crash there, but the dump shows the
use-after-unload and not the reason for it.

Not a Harmony patch -- the caller is native, with no managed frame to
intercept -- so it sits in OnLoad, before Affinity has had a chance to run
the cycle even once. Defaults on, next to the font-enumeration fix, and can
be turned off from the Crash Fixes section.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant