Hi,
I'd like to share my finding.
I also duplicated the error on CentOS 7, who comes with perl 5.16
installed and tcl-8.5.
while on my Cygwin build there is no problem.
After some tracing, I found the error point is at the perl_destruct()
calling Perl_safesysfree() in perl.c:

    
https://perl5.git.perl.org/perl5.git/blob/06d742c02d396d6515581002f376b55ab1972c1b:/perl.c#l811

There is a 'char **environ' for the environment variable string list
and calling Perl_safesysfree(environ[i]) to free the memory space.
However, I found the pointer value passed into Perl_safesysfree()
differs from that reported by gdb 'p environ[0]' command.
Here I have a demo of the gdb tracing result. There are two
'environ[0]'s: One is at address 0x7fffffffe70e (report by gdb)
and the other is at 0x618330 (actually passed into Perl_safesysfree).
Both of them have the same string content "USER=...".
However, later has one additional item in its string list: "FOO=bar"
while gdb reported one does not have it.
Freeing this additional string leads to the error.
Its seems to be issue of compiler optimization. I am going to digging
into it later.

--------------------
(gdb) set breakpoint pending on
(gdb) b perl.c:811
Breakpoint 1 (perl.c:811) pending.
(gdb) r
Starting program: /usr/bin/perl -MTcl -e Tcl::new-\>Eval\(\"set\
env\(FOO\)\ bar\"\)
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[New Thread 0x7fffefa8f700 (LWP 6045)]
[Thread 0x7fffefa8f700 (LWP 6045) exited]

Breakpoint 1, perl_destruct (my_perl=0x603010) at perl.c:811
811                 safesysfree(environ[i]);
Missing separate debuginfos, use: debuginfo-install
libgcc-4.8.5-39.el7.x86_64 nss-softokn-freebl-3.44.0-8.el7_7.x86_64
tcl-8.5.13-8.el7.x86
(gdb) p environ
$1 = (char **) 0x7fffffffe460
(gdb) p environ[0]
$2 = 0x7fffffffe70e "USER=crystal"
(gdb) p environ[1]
$3 = 0x7fffffffe71b "LOGNAME=crystal"
(gdb) step
Perl_safesysfree (where=0x618330) at util.c:254
254         if (where) {
(gdb) p (char*)where
$4 = 0x618330 "USER=crystal"
(gdb) finish
Run till exit from #0  Perl_safesysfree (where=0x618330) at util.c:254
perl_destruct (my_perl=0x603010) at perl.c:810
810             for (i = 0; environ[i]; i++)
(gdb) step

Breakpoint 1, perl_destruct (my_perl=0x603010) at perl.c:811
811                 safesysfree(environ[i]);
(gdb) step
Perl_safesysfree (where=0x618350) at util.c:254
254         if (where) {
(gdb) p (char*)where
$5 = 0x618350 "LOGNAME=crystal"
--------------------
SJ

Konovalov, Vadim <vadim.konova...@dell.com> wrote
>
> You're ingenious!
>
> vad@bonita:~$ perl -MTcl -we 'my $i=new Tcl;$i->Init;$i->Eval("set env(FOO) 
> bar");'
> free(): invalid size
> Aborted (core dumped)
> vad@bonita:~$
>
> and even $i->Init not needed:
>
> vad@bonita:~$ perl -MTcl -we 'Tcl::new->Eval("set env(FOO) bar");'
> free(): invalid size
> Aborted (core dumped)
>
> Haven't looked deeper though, but the picture now is much more clear! Thanks!
>
> -----Original Message-----
> From: Christopher Chavez <chrischa...@gmx.us>
> Sent: Tuesday, March 17, 2020 6:08 AM
> To: tcltk@perl.org
> Subject: Re: Possible bug in Tcl.pm exposed by Tktable?
>
>
> [EXTERNAL EMAIL]
>
> On 3/16/2020 4:09 AM, Christopher Chavez wrote:
> > To partially answer my own question:
> > there are some compile-time techniques to try like -DPURIFY
> > https://wiki.tcl-lang.org/page/How+to+debug+memory+faults+in+Tcl+and+e
> > xtensions
> After build from upstream sources (Tcl/Tk core-8-6-branch and TkTable 2.11 -- 
> no Debian/Ubuntu Tcl/Tk packages) with -DPURIFY, the error is revealed to be 
> a double free. The addresses involved correspond to strings allocated for 
> environment variable(s) set by Tktable (tkTableInitScript.h).
>
> A simpler program without Tk or Tktable reveals the same issue:
>
> use Tcl;
>
> my $i = new Tcl;
> $i->Init;
> $i->Eval('set env(FOO) bar');
>
>
> Command line output:
>
> free(): double free detected in tcache 2 Aborted (core dumped)
>
> Valgrind output:
>
> ==13666== Invalid free() / delete / delete[] / realloc()
> ==13666==    at 0x48369AB: free (vg_replace_malloc.c:530)
> ==13666==    by 0x162304: perl_destruct (in /usr/bin/perl)
> ==13666==    by 0x13C3DB: main (in /usr/bin/perl)
> ==13666==  Address 0x5229a20 is 0 bytes inside a block of size 8 free'd
> ==13666==    at 0x48369AB: free (vg_replace_malloc.c:530)
> ==13666==    by 0x543EE86: TclpFree (tclAlloc.c:722)
> ==13666==    by 0x5517935: TclFinalizeEnvironment (tclEnv.c:768)
> ==13666==    by 0x5519268: Tcl_Finalize (tclEvent.c:1151)
> ==13666==    by 0x485123D: XS_Tcl__Finalize (Tcl.xs:1449)
> ==13666==    by 0x1F4360: Perl_pp_entersub (in /usr/bin/perl)
> ==13666==    by 0x1EA685: Perl_runops_standard (in /usr/bin/perl)
> ==13666==    by 0x15DF61: Perl_call_sv (in /usr/bin/perl)
> ==13666==    by 0x160AC3: Perl_call_list (in /usr/bin/perl)
> ==13666==    by 0x16235E: perl_destruct (in /usr/bin/perl)
> ==13666==    by 0x13C3DB: main (in /usr/bin/perl)
> ==13666==  Block was alloc'd at
> ==13666==    at 0x4837D7B: realloc (vg_replace_malloc.c:826)
> ==13666==    by 0x543EEAA: TclpRealloc (tclAlloc.c:747)
> ==13666==    by 0x5456E8D: Tcl_Realloc (tclCkalloc.c:1147)
> ==13666==    by 0x55172A9: TclSetEnv (tclEnv.c:317)
> ==13666==    by 0x5517688: EnvTraceProc (tclEnv.c:636)
> ==13666==    by 0x55A0B69: TclCallVarTraces (tclTrace.c:2678)
> ==13666==    by 0x55A0860: TclObjCallVarTraces (tclTrace.c:2564)
> ==13666==    by 0x55AAFDB: TclPtrSetVarIdx (tclVar.c:2001)
> ==13666==    by 0x55AA957: Tcl_ObjSetVar2 (tclVar.c:1770)
> ==13666==    by 0x55AA609: Tcl_SetObjCmd (tclVar.c:1529)
> ==13666==    by 0x544A42A: Dispatch (tclBasic.c:4456)
> ==13666==    by 0x544A4B0: TclNRRunCallbacks (tclBasic.c:4492)
> ==13666==    by 0x5449D83: Tcl_EvalObjv (tclBasic.c:4215)
> ==13666==    by 0x544C1AB: TclEvalEx (tclBasic.c:5361)
> ==13666==    by 0x544B571: Tcl_EvalEx (tclBasic.c:5026)
> ==13666==    by 0x48525A8: XS_Tcl_Eval (Tcl.xs:1097)
> ==13666==    by 0x1F4360: Perl_pp_entersub (in /usr/bin/perl)
> ==13666==    by 0x1EA685: Perl_runops_standard (in /usr/bin/perl)
> ==13666==    by 0x166116: perl_run (in /usr/bin/perl)
> ==13666==    by 0x13C401: main (in /usr/bin/perl)
> ==13666==
> ==13666== Invalid free() / delete / delete[] / realloc()
> ==13666==    at 0x48369AB: free (vg_replace_malloc.c:530)
> ==13666==    by 0x162322: perl_destruct (in /usr/bin/perl)
> ==13666==    by 0x13C3DB: main (in /usr/bin/perl)
> ==13666==  Address 0x5229810 is 0 bytes inside a block of size 376 free'd
> ==13666==    at 0x48369AB: free (vg_replace_malloc.c:530)
> ==13666==    by 0x543EE86: TclpFree (tclAlloc.c:722)
> ==13666==    by 0x5517983: TclFinalizeEnvironment (tclEnv.c:776)
> ==13666==    by 0x5519268: Tcl_Finalize (tclEvent.c:1151)
> ==13666==    by 0x485123D: XS_Tcl__Finalize (Tcl.xs:1449)
> ==13666==    by 0x1F4360: Perl_pp_entersub (in /usr/bin/perl)
> ==13666==    by 0x1EA685: Perl_runops_standard (in /usr/bin/perl)
> ==13666==    by 0x15DF61: Perl_call_sv (in /usr/bin/perl)
> ==13666==    by 0x160AC3: Perl_call_list (in /usr/bin/perl)
> ==13666==    by 0x16235E: perl_destruct (in /usr/bin/perl)
> ==13666==    by 0x13C3DB: main (in /usr/bin/perl)
> ==13666==  Block was alloc'd at
> ==13666==    at 0x483577F: malloc (vg_replace_malloc.c:299)
> ==13666==    by 0x543EE6C: TclpAlloc (tclAlloc.c:699)
> ==13666==    by 0x5456D99: Tcl_Alloc (tclCkalloc.c:1059)
> ==13666==    by 0x5517074: TclSetEnv (tclEnv.c:263)
> ==13666==    by 0x5517688: EnvTraceProc (tclEnv.c:636)
> ==13666==    by 0x55A0B69: TclCallVarTraces (tclTrace.c:2678)
> ==13666==    by 0x55A0860: TclObjCallVarTraces (tclTrace.c:2564)
> ==13666==    by 0x55AAFDB: TclPtrSetVarIdx (tclVar.c:2001)
> ==13666==    by 0x55AA957: Tcl_ObjSetVar2 (tclVar.c:1770)
> ==13666==    by 0x55AA609: Tcl_SetObjCmd (tclVar.c:1529)
> ==13666==    by 0x544A42A: Dispatch (tclBasic.c:4456)
> ==13666==    by 0x544A4B0: TclNRRunCallbacks (tclBasic.c:4492)
> ==13666==    by 0x5449D83: Tcl_EvalObjv (tclBasic.c:4215)
> ==13666==    by 0x544C1AB: TclEvalEx (tclBasic.c:5361)
> ==13666==    by 0x544B571: Tcl_EvalEx (tclBasic.c:5026)
> ==13666==    by 0x48525A8: XS_Tcl_Eval (Tcl.xs:1097)
> ==13666==    by 0x1F4360: Perl_pp_entersub (in /usr/bin/perl)
> ==13666==    by 0x1EA685: Perl_runops_standard (in /usr/bin/perl)
> ==13666==    by 0x166116: perl_run (in /usr/bin/perl)
> ==13666==    by 0x13C401: main (in /usr/bin/perl)
>
>
>
> (Note that I built Tcl/Tk with threads, since that is how Debian/Ubuntu 
> Tcl/Tk are built; not yet sure if that affects this issue. Using system Perl 
> vs self-compiled Perl should not be a factor, since Travis CI uses Perlbrew 
> whereas I've used the system Perl.)
>
>
> Christopher A. Chavez

Reply via email to