fix(win32): no module could load under muxscript, for two reasons (#1594)

The module preflight added with #1572 turned master red on Windows because
none of the three modules smoke.conf configures could load there.  Two
independent causes; fixing either alone left the run red.

1. comsys and mail built as comsys.dll / mail.dll, while modules/Makefile.am
   builds comsys_mod.so / mail_mod.so.  `cf_module` resolves `module <name>`
   to `.\bin\<name>.dll` or `./bin/<name>.so`, so no single config line could
   name those two modules on both platforms.  The vcxproj files were taking
   their default TargetName; they now set it explicitly.  Renaming the
   Windows side rather than the Unix side because those two DLLs had no
   DCL_EXPORT until #1569 and so were never loadable on Windows at all --
   nothing can depend on the old names, whereas Unix installs use _mod today.

2. exp3 -- whose name already matched on both platforms -- still did not
   load, silently, and only under muxscript.  LoadLibrary() does not treat a
   relative path as relative to the current directory: it appends the whole
   relative path to every entry in the DLL search order.  The current
   directory is one of those entries until something calls SetDllDirectory(),
   which removes it.  muxscript calls it in init_com() so engine.dll can find
   libmux.dll, and cf_module hands LoadLibrary ".\bin\<name>.dll" -- so under
   muxscript that resolved nowhere.  netmux never calls SetDllDirectory(),
   which is why the identical config worked there and the divergence looked
   inexplicable.  ModuleLoad now resolves the path against the current
   directory itself, which is what every caller already assumed.

Both smoke gates go back to unconditional.  They were made advisory on
Windows only because the platform could not comply; it can now.

Verified on Windows Server 2022, MSVC 14.51, Release x64: all three modules
report (loaded) under muxscript from a clean environment, netmux logs
"Comsys module loaded" / "Mail module loaded" with the new names, and the
preflight passes silently in the smoke run.

Measured, and worth recording for #1589/#1614: with the modules finally live
on Windows, the suite returns exactly what it returns without them --
1555 succeeded, 5 failed, same five, same one-verdict deficit.  The five are
a pre-existing configuration gap (autoconf-win32.h has no HAVE_LIBSSL and no
reality levels), not a regression, and they are identical with
SMOKE_OMIT_MODULES set.  The corpus still cannot tell the two
implementations apart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Stephen Dennis 2026-07-27 18:46:23 -06:00
parent 011b06e967
commit 6cccafd1d0
6 changed files with 52 additions and 52 deletions

View file

@ -312,7 +312,29 @@ static void ModuleLoad(Module *pModule)
return;
}
#if defined(WINDOWS_DYNALIB)
// LoadLibrary() does not treat a relative path as relative to the current
// directory: it appends the whole relative path to every entry in the DLL
// search order. The current directory is one of those entries -- until
// something calls SetDllDirectory(), which removes it. muxscript does
// exactly that so engine.dll can find libmux.dll, and cf_module hands us
// ".\\bin\\<name>.dll", so every module configured under muxscript failed
// to load (#1594). netmux never calls SetDllDirectory(), which is why the
// identical config worked there and the divergence went unexplained.
//
// Resolve against the current directory ourselves. That is what every
// caller already assumes, and it no longer depends on the search order.
//
UTF16 aFullPath[4096];
DWORD nFullPath = GetFullPathNameW(pModule->pFileName,
sizeof(aFullPath)/sizeof(aFullPath[0]), aFullPath, nullptr);
const UTF16 *pPathName = ( 0 < nFullPath
&& nFullPath < sizeof(aFullPath)/sizeof(aFullPath[0]))
? aFullPath : pModule->pFileName;
pModule->hInst = MOD_OPEN(pPathName);
#else
pModule->hInst = MOD_OPEN(pModule->pFileName);
#endif
if (nullptr != pModule->hInst)
{
pModule->fpGetClassObject = reinterpret_cast<FPGETCLASSOBJECT *>(MOD_SYM(pModule->hInst, "mux_GetClassObject"));

View file

@ -41,11 +41,15 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>..\..\bin_release\</OutDir>
<IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<!-- modules/Makefile.am builds comsys_mod.so; `module comsys_mod` has to
name the same thing on both platforms (#1594). -->
<TargetName>comsys_mod</TargetName>
<IncludePath>C:\tinymux\mux\include;C:\tinymux\mux\sqlite;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>..\..\bin_debug\</OutDir>
<IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<TargetName>comsys_mod</TargetName>
<IncludePath>C:\tinymux\mux\include;C:\tinymux\mux\sqlite;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

View file

@ -41,11 +41,15 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>..\..\bin_release\</OutDir>
<IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<!-- modules/Makefile.am builds mail_mod.so; `module mail_mod` has to name
the same thing on both platforms (#1594). -->
<TargetName>mail_mod</TargetName>
<IncludePath>C:\tinymux\mux\include;C:\tinymux\mux\sqlite;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>..\..\bin_debug\</OutDir>
<IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<TargetName>mail_mod</TargetName>
<IncludePath>C:\tinymux\mux\include;C:\tinymux\mux\sqlite;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

View file

@ -255,34 +255,16 @@ if [ -n "$WANT_MODULES" ]; then
sed -n '/^Modules:/,/^$/p' modprobe.log | sed 's/^/ /'
echo
# Fatal where the check is achievable; advisory where it is not yet.
# Unconditional again as of #1594. It was briefly advisory on Windows,
# where no module could load under muxscript at all: comsys/mail built
# as comsys.dll/mail.dll instead of the *_mod names smoke.conf needs,
# and muxscript's SetDllDirectory() call removed the current directory
# from the DLL search order, so cf_module's relative ".\bin\<name>.dll"
# resolved nowhere. Both are fixed; every platform can comply, so a
# module that does not load is a failure everywhere.
#
# On Windows none of the three modules can load today, for two causes
# tracked in #1594: comsys/mail build as comsys.dll/mail.dll rather
# than the *_mod names smoke.conf must use for Unix, and exp3 -- whose
# name matches on both platforms -- still does not load under
# muxscript specifically, with no diagnostic. Neither is fixable from
# the harness, and a platform that cannot comply should not have a red
# build held over it: red master blocks everyone (#1564).
#
# This is temporary and should be deleted, not kept. When #1594
# closes, drop the branch so the check is unconditional again --
# or set SMOKE_REQUIRE_MODULES=1 to get that behaviour now.
#
case "${SMOKE_REQUIRE_MODULES:-}${MODCHECK_PLATFORM:-$(uname -s 2>/dev/null)}" in
1*|Linux*|Darwin*|*BSD*|SunOS*)
echo "=== Smoke: FAILED (module preflight) ==="
exit 1
;;
*)
echo "WARNING: continuing anyway -- this platform cannot load"
echo " modules under muxscript at all yet (#1594)."
echo " The results below may exercise the engine's"
echo " built-in comsys/mail rather than the modules."
echo " Set SMOKE_REQUIRE_MODULES=1 to make this fatal."
echo
;;
esac
echo "=== Smoke: FAILED (module preflight) ==="
exit 1
fi
rm -rf modprobe.in modprobe.log modprobe.conf modprobe.d
fi
@ -423,30 +405,16 @@ esac
if [ -n "$IMPL_BAD" ]; then
echo ""
# Same platform gate as the load preflight (#1599 / #1594): fatal where
# modules can load; advisory on Windows until that is fixed. Otherwise
# this check undoes the soft preflight -- modules fail to load, the
# built-in answers, and we exit 1 after a long green-looking suite.
# Unconditional, like the load preflight above (#1599 / #1594).
#
case "${SMOKE_REQUIRE_MODULES:-}${MODCHECK_PLATFORM:-$(uname -s 2>/dev/null)}" in
1*|Linux*|Darwin*|*BSD*|SunOS*)
echo "=== Smoke: FAILED (implementation fallback) ==="
echo "smoke.conf asks for the module, but the built-in engine answered"
echo "for:$IMPL_BAD"
echo ""
echo "Either the module never loaded (preflight may have been advisory)"
echo "or discover_comsys_mail_modules() fell back after load. The"
echo "results describe the built-in, not the module under test."
exit 1
;;
*)
echo "WARNING: smoke.conf asks for the module, but the built-in"
echo " answered for:$IMPL_BAD (#1594 / #1581)."
echo " Continuing on this platform; set"
echo " SMOKE_REQUIRE_MODULES=1 to make this fatal."
echo
;;
esac
echo "=== Smoke: FAILED (implementation fallback) ==="
echo "smoke.conf asks for the module, but the built-in engine answered"
echo "for:$IMPL_BAD"
echo ""
echo "Either the module never loaded (the preflight should have caught"
echo "that) or discover_comsys_mail_modules() fell back after load. The"
echo "results describe the built-in, not the module under test."
exit 1
fi
echo ""

View file

@ -12,11 +12,11 @@ docs/LIMITS.md
docs/PATCHES.md
docs/REALMS.md
game/alias.conf
game/bin/comsys.dll
game/bin/comsys_mod.dll
game/bin/engine.dll
game/bin/exp3.dll
game/bin/libmux.dll
game/bin/mail.dll
game/bin/mail_mod.dll
game/bin/msvcp140.dll
game/bin/muxscript.exe
game/bin/netmux.exe

View file

@ -13,7 +13,9 @@ docs/LIMITS
docs/MEMORY
docs/PATCHES
docs/REALMS
game/bin/comsys.dll
game/bin/funcs.dll
game/bin/mail.dll
game/bin/sample.dll
game/bin/sum.dll
src/copyright.h