Applying: Fix Windows 7 crash after connecting when Python plugin init fails

This commit is contained in:
2026-07-07 19:04:51 -06:00
parent f068a0e0fa
commit 251272c708
5 changed files with 80 additions and 29 deletions

View File

@@ -126,11 +126,12 @@ jobs:
$pyRoot = $env:pythonLocation $pyRoot = $env:pythonLocation
if (-not $pyRoot) { $pyRoot = & python -c "import sys; print(sys.prefix)" } if (-not $pyRoot) { $pyRoot = & python -c "import sys; print(sys.prefix)" }
$pyDir = "C:\gtk-build\python-3.8" foreach ($pyDir in @("C:\gtk-build\python-3.8.10", "C:\gtk-build\python-3.8")) {
New-Item -Path $pyDir -ItemType Directory -Force | Out-Null New-Item -Path $pyDir -ItemType Directory -Force | Out-Null
$target = Join-Path $pyDir "${{ matrix.platform }}" $target = Join-Path $pyDir "${{ matrix.platform }}"
if (Test-Path $target) { Remove-Item $target -Recurse -Force } if (Test-Path $target) { Remove-Item $target -Recurse -Force }
New-Item -Path $pyDir -Name "${{ matrix.platform }}" -ItemType Junction -Value $pyRoot | Out-Null New-Item -Path $pyDir -Name "${{ matrix.platform }}" -ItemType Junction -Value $pyRoot | Out-Null
}
- name: Build - name: Build
run: | run: |
@@ -143,23 +144,33 @@ jobs:
exit /b 1 exit /b 1
) )
set "LIB=%PYTHON_DIR%\libs;%LIB%"
set "INCLUDE=%PYTHON_DIR%\include;%INCLUDE%"
powershell -NoProfile -ExecutionPolicy Bypass -Command "$archiveLib='C:\gtk-build\gtk\x64\release\lib\libarchive.lib'; if (-not (Test-Path $archiveLib)) { $archiveDll = Get-ChildItem 'C:\gtk-build\gtk\x64\release\bin\libarchive*.dll' | Select-Object -First 1; if ($archiveDll) { Push-Location 'C:\gtk-build\gtk\x64\release\lib'; & 'C:\gtk-build\gendef\gendef.exe' $archiveDll.FullName | Out-Null; $archiveDef = Get-ChildItem 'libarchive*.def' | Select-Object -First 1; if ($archiveDef) { & lib /def:$archiveDef.Name /machine:${{ matrix.platform }} /out:libarchive.lib | Out-Null }; Pop-Location } }"
msbuild win32\zoitechat.sln /m /verbosity:minimal /p:Configuration=Release /p:Platform=${{ matrix.platform }}
set "PYTHON38_DIR=C:\gtk-build\python-3.8\${{ matrix.platform }}" set "PYTHON38_DIR=C:\gtk-build\python-3.8\${{ matrix.platform }}"
if not exist "%PYTHON38_DIR%\libs\python38.lib" ( if not exist "%PYTHON38_DIR%\libs\python38.lib" (
echo Missing %PYTHON38_DIR%\libs\python38.lib echo Missing %PYTHON38_DIR%\libs\python38.lib
dir "%PYTHON38_DIR%\libs" dir "%PYTHON38_DIR%\libs"
exit /b 1 exit /b 1
) )
if not exist "%PYTHON38_DIR%\Lib\site-packages\_cffi_backend.cp38*.pyd" (
echo Missing %PYTHON38_DIR%\Lib\site-packages\_cffi_backend.cp38*.pyd
exit /b 1
)
msbuild plugins\python\python3.vcxproj /m /verbosity:minimal /p:Configuration=Release /p:Platform=${{ matrix.platform }} /p:SolutionDir=%CD%\win32\ /p:YourPython3Path=C:\gtk-build\python-3.8 /p:Python3Lib=python38 /p:Python3Output=hcpython38 set "LIB=%PYTHON_DIR%\libs;%LIB%"
copy /Y "%PYTHON38_DIR%\Lib\site-packages\_cffi_backend.cp38*.pyd" "..\zoitechat-build\${{ matrix.platform }}\bin\" set "INCLUDE=%PYTHON_DIR%\include;%INCLUDE%"
msbuild win32\installer\installer.vcxproj /m /verbosity:minimal /p:Configuration=Release /p:Platform=${{ matrix.platform }} /p:SolutionDir=%CD%\win32\
powershell -NoProfile -ExecutionPolicy Bypass -Command "$archiveLib='C:\gtk-build\gtk\x64\release\lib\libarchive.lib'; if (-not (Test-Path $archiveLib)) { $archiveDll = Get-ChildItem 'C:\gtk-build\gtk\x64\release\bin\libarchive*.dll' | Select-Object -First 1; if ($archiveDll) { Push-Location 'C:\gtk-build\gtk\x64\release\lib'; & 'C:\gtk-build\gendef\gendef.exe' $archiveDll.FullName | Out-Null; $archiveDef = Get-ChildItem 'libarchive*.def' | Select-Object -First 1; if ($archiveDef) { & lib /def:$archiveDef.Name /machine:${{ matrix.platform }} /out:libarchive.lib | Out-Null }; Pop-Location } }"
msbuild win32\zoitechat.sln /m /verbosity:minimal /p:Configuration=Release /p:Platform=${{ matrix.platform }}
if errorlevel 1 exit /b 1
if not exist "..\zoitechat-build\${{ matrix.platform }}\rel\plugins\hcpython38.dll" (
echo hcpython38.dll was not built
exit /b 1
)
if not exist "..\zoitechat-build\${{ matrix.platform }}\rel\_cffi_backend.cp38*.pyd" (
echo _cffi_backend for Python 3.8 was not staged for the installer
exit /b 1
)
shell: cmd shell: cmd
- name: Preparing Artifacts - name: Preparing Artifacts

View File

@@ -53,6 +53,16 @@ builder.set_source('_zoitechat_embedded', '''
#include "config.h" #include "config.h"
#include "zoitechat-plugin.h" #include "zoitechat-plugin.h"
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#endif
static zoitechat_plugin *ph; static zoitechat_plugin *ph;
CFFI_DLLEXPORT int _on_plugin_init(char **, char **, char **, char *, char *); CFFI_DLLEXPORT int _on_plugin_init(char **, char **, char **, char *, char *);
CFFI_DLLEXPORT int _on_plugin_deinit(void); CFFI_DLLEXPORT int _on_plugin_deinit(void);
@@ -61,6 +71,20 @@ int zoitechat_plugin_init(zoitechat_plugin *plugin_handle,
char **name_out, char **description_out, char **name_out, char **description_out,
char **version_out, char *arg) char **version_out, char *arg)
{ {
#ifdef _WIN32
/* CPython cannot be removed from a process once Py_Initialize has run.
If the embedded interpreter fails to start (e.g. _cffi_backend is
missing), the host responds to our 0 return by g_module_close()ing
this plugin, which would also drop the last reference to pythonXY.dll
and unload it mid-flight; the leftover process-global state then
crashes the process later, e.g. when a server connection spawns the
next thread. Pin this module so FreeLibrary can never unload it. */
HMODULE self_handle;
GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_PIN |
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCWSTR)&zoitechat_plugin_init, &self_handle);
#endif
if (ph != NULL) if (ph != NULL)
{ {
puts ("Python plugin already loaded\\n"); puts ("Python plugin already loaded\\n");

View File

@@ -59,18 +59,32 @@ typedef struct session zoitechat_context;
#define DEBUG(x) {x;} #define DEBUG(x) {x;}
#ifdef WIN32 #ifdef WIN32
/* Python >= 3.9 dropped support for Windows versions before 10, so those
* systems get a Python 3.8 build of the plugin instead. RtlGetVersion is
* used because GetVersionEx reports a version capped by the compatibility
* manifest rather than the real one. */
static gboolean static gboolean
plugin_windows_is_windows7 (void) plugin_windows_needs_python38 (void)
{ {
OSVERSIONINFOEXA version; typedef LONG (WINAPI *rtl_get_version_func) (PRTL_OSVERSIONINFOW);
rtl_get_version_func rtl_get_version;
RTL_OSVERSIONINFOW version;
HMODULE ntdll;
ntdll = GetModuleHandleW (L"ntdll.dll");
if (ntdll == NULL)
return FALSE;
rtl_get_version = (rtl_get_version_func) GetProcAddress (ntdll, "RtlGetVersion");
if (rtl_get_version == NULL)
return FALSE;
memset (&version, 0, sizeof (version)); memset (&version, 0, sizeof (version));
version.dwOSVersionInfoSize = sizeof (version); version.dwOSVersionInfoSize = sizeof (version);
if (!GetVersionExA ((OSVERSIONINFOA *)&version)) if (rtl_get_version (&version) != 0)
return FALSE; return FALSE;
return version.dwPlatformId == VER_PLATFORM_WIN32_NT && return version.dwMajorVersion < 10;
version.dwMajorVersion == 6 && version.dwMinorVersion == 1;
} }
#endif #endif
@@ -508,7 +522,7 @@ plugin_auto_load (session *sess)
for_files (lib_dir, "hcfishlim.dll", plugin_auto_load_cb); for_files (lib_dir, "hcfishlim.dll", plugin_auto_load_cb);
for_files(lib_dir, "hclua.dll", plugin_auto_load_cb); for_files(lib_dir, "hclua.dll", plugin_auto_load_cb);
for_files (lib_dir, "hcperl.dll", plugin_auto_load_cb); for_files (lib_dir, "hcperl.dll", plugin_auto_load_cb);
if (plugin_windows_is_windows7 ()) if (plugin_windows_needs_python38 ())
for_files (lib_dir, "hcpython38.dll", plugin_auto_load_cb); for_files (lib_dir, "hcpython38.dll", plugin_auto_load_cb);
else else
for_files (lib_dir, "hcpython3.dll", plugin_auto_load_cb); for_files (lib_dir, "hcpython3.dll", plugin_auto_load_cb);

View File

@@ -59,7 +59,7 @@ Name: "plugins\upd"; Description: "Update Checker"; Types: normal custom; Flags:
Name: "langs"; Description: "Language Interfaces"; Types: custom; Flags: disablenouninstallwarning Name: "langs"; Description: "Language Interfaces"; Types: custom; Flags: disablenouninstallwarning
Name: "langs\lua"; Description: "Lua (LuaJIT 2.1)"; Types: normal custom; Flags: disablenouninstallwarning Name: "langs\lua"; Description: "Lua (LuaJIT 2.1)"; Types: normal custom; Flags: disablenouninstallwarning
Name: "langs\perl"; Description: "Perl (Strawberry Perl 5.42.0.1)"; Types: custom; Flags: disablenouninstallwarning Name: "langs\perl"; Description: "Perl (Strawberry Perl 5.42.0.1)"; Types: custom; Flags: disablenouninstallwarning
Name: "langs\python"; Description: "Python (Python 3.14.3, or 3.8.10 on Windows 7)"; Types: custom; Flags: disablenouninstallwarning Name: "langs\python"; Description: "Python (Python 3.14.3, or 3.8.10 before Windows 10)"; Types: custom; Flags: disablenouninstallwarning
Name: "themes"; Description: "GTK3 Themes"; Types: normal minimal custom; Flags: disablenouninstallwarning Name: "themes"; Description: "GTK3 Themes"; Types: normal minimal custom; Flags: disablenouninstallwarning
Name: "themes\windows10"; Description: "Windows 10"; Types: normal minimal custom; Flags: disablenouninstallwarning Name: "themes\windows10"; Description: "Windows 10"; Types: normal minimal custom; Flags: disablenouninstallwarning
Name: "themes\windows10dark"; Description: "Windows 10 Dark"; Types: normal minimal custom; Flags: disablenouninstallwarning Name: "themes\windows10dark"; Description: "Windows 10 Dark"; Types: normal minimal custom; Flags: disablenouninstallwarning
@@ -181,8 +181,8 @@ Source: "plugins\hcperl.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Co
Source: "python\*.py"; DestDir: "{app}\python"; Flags: ignoreversion; Components: langs\python Source: "python\*.py"; DestDir: "{app}\python"; Flags: ignoreversion; Components: langs\python
Source: "plugins\hcpython3.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: langs\python; Check: not IsWindows7 Source: "plugins\hcpython3.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: langs\python; Check: not NeedsLegacyPython
Source: "plugins\hcpython38.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion skipifsourcedoesntexist; Components: langs\python; Check: IsWindows7 Source: "plugins\hcpython38.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion skipifsourcedoesntexist; Components: langs\python; Check: NeedsLegacyPython
Source: "_cffi_backend.cp3*.pyd"; DestDir: "{app}"; Flags: ignoreversion; Components: langs\python Source: "_cffi_backend.cp3*.pyd"; DestDir: "{app}"; Flags: ignoreversion; Components: langs\python
Source: "zoitechat.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "zoitechat.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
@@ -329,17 +329,19 @@ begin
Result := DirExists(ExpandConstant('{localappdata}') + '\enchant\myspell'); Result := DirExists(ExpandConstant('{localappdata}') + '\enchant\myspell');
end; end;
function IsWindows7(): Boolean; // Python >= 3.9 dropped support for Windows versions before 10;
// those systems get Python 3.8 and the matching plugin instead.
function NeedsLegacyPython(): Boolean;
var var
Version: TWindowsVersion; Version: TWindowsVersion;
begin begin
GetWindowsVersionEx(Version); GetWindowsVersionEx(Version);
Result := Version.NTPlatform and (Version.Major = 6) and (Version.Minor = 1); Result := Version.NTPlatform and (Version.Major < 10);
end; end;
function PythonURL(): String; function PythonURL(): String;
begin begin
if IsWindows7() then if NeedsLegacyPython() then
Result := 'https://www.python.org/ftp/python/3.8.10/python-3.8.10-amd64.exe' Result := 'https://www.python.org/ftp/python/3.8.10/python-3.8.10-amd64.exe'
else else
Result := 'https://www.python.org/ftp/python/3.14.3/python-3.14.3-amd64.exe'; Result := 'https://www.python.org/ftp/python/3.14.3/python-3.14.3-amd64.exe';
@@ -347,7 +349,7 @@ end;
function PythonDLL(): String; function PythonDLL(): String;
begin begin
if IsWindows7() then if NeedsLegacyPython() then
Result := 'python38.dll' Result := 'python38.dll'
else else
Result := 'python314.dll'; Result := 'python314.dll';

View File

@@ -8,7 +8,7 @@
<YourGendefPath>c:\gtk-build\gendef</YourGendefPath> <YourGendefPath>c:\gtk-build\gendef</YourGendefPath>
<YourPerlPath>c:\gtk-build\perl-5.42.0.1</YourPerlPath> <YourPerlPath>c:\gtk-build\perl-5.42.0.1</YourPerlPath>
<YourPython3Path>c:\gtk-build\python-3.14</YourPython3Path> <YourPython3Path>c:\gtk-build\python-3.14</YourPython3Path>
<YourPython38Path>c:\gtk-build\python-3.8.10</YourPython38Path> <YourPython38Path>c:\gtk-build\python-3.8</YourPython38Path>
<YourWinSparklePath>c:\gtk-build\WinSparkle</YourWinSparklePath> <YourWinSparklePath>c:\gtk-build\WinSparkle</YourWinSparklePath>
<!-- YOU SHOULDN'T TOUCH ANYTHING BELOW --> <!-- YOU SHOULDN'T TOUCH ANYTHING BELOW -->