Subject: V01zmodload fails on Cygwin
From: "Jun T." <[email-masked]>
To: "[email-masked]" <[email-masked]>
Date: Sun, 24 Jan 2016 20:10:14 +0900
List-Id: Zsh Workers List <zsh-workers.zsh.org>

V01zmodload.ztst fails on my Cygwin (on 64 bit Windows7):
CYGWIN_NT-6.1 2.4.0(0.293/5/3) 2016-01-15 16:16 x86_64
(probably the latest 64bit cygwin)

First of all, I want to be confirmed that the test fails
also on other cygwin systems.

If I run
% ZTST_verbose=2 make TESTNUM=V01 check
the last part of the output looks like

ZTST_getchunk: read code chunk:
 mods[(r)zsh/main]=()
 zmodunload $mods
 zmodload zsh/parameter
ZTST_test: examining line:

Running test: Unload the modules loaded by this test suite
ZTST_test: expecting status: 0
Input: /tmp/zsh.ztst.in.3560, output: /tmp/zsh.ztst.out.3560, error: /tmp/zsh.ztst.terr.3560
ZTST_execchunk: status 0
**************************************
0 successful test scripts, 1 failure, 0 skipped
**************************************

So the execchunk for
0d:Unload the modules loaded by this test suite
has succeeded but ztst.zsh seems to die before
0:Listing feature autoloads includes unloaded modules

With some experiment, I found that the following causes a core dump:

cygwin$ ~/bin/zsh -f    # the zsh I have just built
% zmodload zsh/param/private
% zmodload -u zsh/param/private
% local i

but I couldn't get any backtrace from the core.

The following is my *guess* as to what is going wrong.

On Cygwin, parm_private.dll is built by

gcc -g  -shared -Wl,--export-all-symbols -o param_private.dll param_private..o   ../../Src/libzsh-5.2-dev-1.dll  -liconv -ldl -lncursesw -lrt -lm  -lc

So it seems some symbols from libzsh-5.2-dev-1.dll also exists
in param_private.dll, and gethashnode2 is one of those symbols:

% nm libzsh-5.2-dev-1.dll | grep '[Tt] gethashnode2'
0000000514fd1b7f T gethashnode2
% nm Modules/param_private.dll | grep '[Tt] gethashnode2'
00000004bea72a58 T gethashnode2

In function cleanup_(), at line 628 of Src/Module/param_private.c:

    realparamtab->getnode2 = gethashnode2;

the gethashnode2 seems to point to the symbol in param_private.dll,
which can not be accessed after the module has been unloaded.

The following patch seems to work, but I hope someone who knows
cygwin better to confirm/improve the patch.

# do we need to use #ifdef __CYGWIN__ ?

diff --git a/Src/Modules/param_private.c b/Src/Modules/param_private.c
index e13813c..f0679a4 100644
--- a/Src/Modules/param_private.c
+++ b/Src/Modules/param_private.c
@@ -567,6 +567,8 @@ static struct features module_features = {
 };
 
 static struct builtin save_local;
+static GetNodeFunc save_getnode2;
+static ScanFunc save_printnode;
 static struct reswd reswd_private = {{NULL, "private", 0}, TYPESET};
 
 /**/
@@ -577,6 +579,8 @@ setup_(UNUSED(Module m))
 
     /* Horrible, horrible hack */
     getparamnode = realparamtab->getnode;
+    save_getnode2 = realparamtab->getnode2;
+    save_printnode = realparamtab->printnode;
     realparamtab->getnode = getprivatenode;
     realparamtab->getnode2 = getprivatenode2;
     realparamtab->printnode = printprivatenode;
@@ -624,8 +628,8 @@ cleanup_(Module m)
     removehashnode(reswdtab, "private");
     
     realparamtab->getnode = getparamnode;
-    realparamtab->getnode2 = gethashnode2;
-    realparamtab->printnode = printparamnode;
+    realparamtab->getnode2 = save_getnode2;
+    realparamtab->printnode = save_printnode;
 
     deletewrapper(m, wrapper);
     return setfeatureenables(m, &module_features, NULL);