Bug 243307

Summary: ftp/lftp: Crashes on 11.3-RELEASE-p3 i386
Product: Ports & Packages Reporter: Victor Sudakov <vas>
Component: Individual Port(s)Assignee: Ganael LAPLANCHE <martymac>
Status: Closed FIXED    
Severity: Affects Some People CC: uzsolt, vas
Priority: --- Keywords: crash, needs-qa
Version: LatestFlags: bugzilla: maintainer-feedback? (martymac)
koobs: merge-quarterly?
Hardware: i386   
OS: Any   
Attachments:
Description Flags
kdump output
none
Patch to illustrate the problem (not a proper fix) none

Description Victor Sudakov 2020-01-13 02:27:47 UTC
Created attachment 210679 [details]
kdump output

ftp/lftp: dumps core when started, on 11.3-RELEASE-p3 i386
Comment 1 Victor Sudakov 2020-01-13 02:30:09 UTC
Compiled in my own poudriere, Options:
        DOCS           : on
        GNUTLS         : off
        NLS            : off
        OPENSSL        : on
Comment 2 Kubilay Kocak freebsd_committer freebsd_triage 2020-01-13 02:31:47 UTC
Thank you for the report Victor

Does the port crash with default options?
Comment 3 Victor Sudakov 2020-01-13 07:21:25 UTC
(In reply to Kubilay Kocak from comment #2)
Rebuilt the port with default options which are: 
Options:
        DOCS           : on
        GNUTLS         : off
        NLS            : on
        OPENSSL        : on

(and the dependency on libintl.so.8 was added). Yes, it still craches.
Comment 4 Ganael LAPLANCHE freebsd_committer freebsd_triage 2020-01-13 07:31:35 UTC
*** Bug 243290 has been marked as a duplicate of this bug. ***
Comment 5 Ganael LAPLANCHE freebsd_committer freebsd_triage 2020-01-13 11:05:13 UTC
Hi and thanks for your report.

I could reproduce the problem on 11.3-RELEASE-p3 i386 by just starting lftp (it crashes at startup).
                                                                   
Here is a backtrace :
                                                                                                                                                                                                                                                                               
-------------------------------
(gdb) bt                                                                                                                               
#0  _xmap::make_hash (this=0x0, s=...) at xmap.cc:54
#1  0x0814adbe in _xmap::_lookup_c (this=0x0, key=...) at xmap.cc:81
#2  0x0812fd95 in xmap<ResType*>::lookup (this=0x0, key=...) at ./xmap.h:86
#3  0x0812f2f3 in xmap<ResType*>::lookup (this=0x0, key=0x8231b30 "dns:order") at ./xmap.h:91
#4  0x0812b156 in ResType::FindVar (name=0x8231b30 "dns:order", type=0xffffcd08, re_closure=0xffffcd28) at ResMgr.cc:89
#5  0x0812f3f4 in ResType::FindVar (name=0x8231b30 "dns:order", type=0xffffcd08, re_closure=0xffffcd28) at ./ResMgr.h:78
#6  0x0812b4f5 in ResType::Set (name=0x8231b30 "dns:order", cclosure=0x0, cvalue=0x8231b40 "inet", def=false) at ResMgr.cc:159
#7  0x0821f144 in NetworkInit::NetworkInit (this=0x8242a74 <NETWORK_INIT>) at network.cc:485
#8  0x0821f0e2 in __cxx_global_var_init () at network.cc:478
#9  0x0821f1d8 in _GLOBAL__sub_I_network.cc () at ./network.h:106                                                                      
#10 0x08222c82 in __do_global_ctors_aux ()
#11 0x080a2105 in _init ()
#12 0x2824037f in ?? () from /libexec/ld-elf.so.1
#13 0x2823f5c6 in ?? () from /libexec/ld-elf.so.1
#14 0x2823d12e in ?? () from /libexec/ld-elf.so.1  
-------------------------------
                                                                   
Re-running the program with a breakpoint gives the following :
                                                                                                                                       
-------------------------------
(gdb) break ResType::FindVar
Breakpoint 1 at 0x812b120: ResType::FindVar. (2 locations)                                                                             
(gdb) run                                                                                                                                                                                                                                                                      
The program being debugged has been started already.
Start it from the beginning? (y or n) y                         
Starting program: /usr/local/bin/lftp              

Breakpoint 1, ResType::FindVar (name=0x8231b30 "dns:order", type=0xffffccc8, re_closure=0xffffcce8) at ./ResMgr.h:78
78         static const char *FindVar(const char *name,ResType **type,const char **re_closure=0) { return FindVar(name,const_cast<const ResType **>(type),re_closure); }
(gdb) n                      
                                                                   
Breakpoint 1, ResType::FindVar (name=0x8231b30 "dns:order", type=0xffffccc8, re_closure=0xffffcce8) at ResMgr.cc:85
85         const ResType *exact_proto=0;
(gdb) n
86         const ResType *exact_name=0;             
(gdb) n                                         
87         int sub=0;      
(gdb) n 
89         *type=types_by_name->lookup(name);       
(gdb) p name                                                                                                                           
$1 = 0x8231b30 "dns:order"                                                                                                             
(gdb) p types_by_name                                                                                                                  
$2 = (xmap<ResType*> *) 0x0                                                                                                            
(gdb) n                                                                                                                                
                                                                                                                                       
Program received signal SIGSEGV, Segmentation fault.                                                                                   
-------------------------------                             
                                                                   
'types_by_name' should have been initialized by ResType::Register() (from src/ResMgr.cc:626), but it has never been called on i386 (while it is on amd64) ; that is why we have a NULL pointer de-reference here.
                                                                   
The question is : why is it called on amd64 but not on i386 ? I'll still have to investigate here...
Comment 6 Zsolt Udvari freebsd_committer freebsd_triage 2020-01-13 11:12:20 UTC
Crash on amd64 too.
Comment 7 Ganael LAPLANCHE freebsd_committer freebsd_triage 2020-01-13 11:53:35 UTC
Right, sorry for my lack of precision : in my previous comment, I meant it does not crash on 12.1-RELEASE/amd64.

I have not tested 11.3-RELEASE/amd64, only 11.3-RELEASE/i386.
Comment 8 Ganael LAPLANCHE freebsd_committer freebsd_triage 2020-01-13 12:18:51 UTC
On 12.1 amd64, we have :

-----------------------
(gdb) break NetworkInit::NetworkInit
Breakpoint 1 at 0x43140c: file network.cc, line 484.
(gdb) break ResType::Register
Breakpoint 2 at 0x34b24b: file ResMgr.cc, line 628.
(gdb) run
Starting program: /usr/local/bin/lftp 

Breakpoint 2, ResType::Register (this=0x43f028 <res_save_cwd_history>) at ResMgr.cc:628
628        if(!types_by_name)
(gdb) bt
#0  ResType::Register (this=0x43f028 <res_save_cwd_history>) at ResMgr.cc:628
#1  0x000000000034b227 in ResDecl::ResDecl (this=0x43f028 <res_save_cwd_history>, a_name=0x27442f "cmd:save-cwd-history", a_defvalue=0x26c046 "yes", a_val_valid=0x34a2d0 <ResMgr::BoolValidate(xstring_c*)>, a_closure_valid=0x34c740 <ResMgr::NoClosure(xstring_c*)>)
    at ResMgr.cc:596
#2  0x00000000002c734f in __cxx_global_var_init () at lftp.cc:70
#3  0x00000000002c8b29 in _GLOBAL__sub_I_lftp.cc ()
#4  0x000000080044346e in ?? () from /libexec/ld-elf.so.1
#5  0x00007fffffffd728 in ?? ()
-----------------------

On 11.3 i386 :

-----------------------
(gdb) break NetworkInit::NetworkInit
Breakpoint 1 at 0x821f0fc: file network.cc, line 484.
(gdb) break ResType::Register
Breakpoint 2 at 0x812d4fa: file ResMgr.cc, line 628.
(gdb) run
Starting program: /usr/local/bin/lftp 

Breakpoint 1, NetworkInit::NetworkInit (this=0x8242a74 <NETWORK_INIT>) at network.cc:484
484        if(!Networker::FindGlobalIPv6Address() || !CanCreateIpv6Socket())
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
_xmap::make_hash (this=0x0, s=...) at xmap.cc:54
54         if(hash_size==1)
(gdb) bt
#0  _xmap::make_hash (this=0x0, s=...) at xmap.cc:54
#1  0x0814adbe in _xmap::_lookup_c (this=0x0, key=...) at xmap.cc:81
#2  0x0812fd95 in xmap<ResType*>::lookup (this=0x0, key=...) at ./xmap.h:86
#3  0x0812f2f3 in xmap<ResType*>::lookup (this=0x0, key=0x8231b30 "dns:order") at ./xmap.h:91
#4  0x0812b156 in ResType::FindVar (name=0x8231b30 "dns:order", type=0xffffccd8, re_closure=0xffffccf8) at ResMgr.cc:89
#5  0x0812f3f4 in ResType::FindVar (name=0x8231b30 "dns:order", type=0xffffccd8, re_closure=0xffffccf8) at ./ResMgr.h:78
#6  0x0812b4f5 in ResType::Set (name=0x8231b30 "dns:order", cclosure=0x0, cvalue=0x8231b40 "inet", def=false) at ResMgr.cc:159
#7  0x0821f144 in NetworkInit::NetworkInit (this=0x8242a74 <NETWORK_INIT>) at network.cc:485
#8  0x0821f0e2 in __cxx_global_var_init () at network.cc:478
#9  0x0821f1d8 in _GLOBAL__sub_I_network.cc () at ./network.h:106
#10 0x08222c82 in __do_global_ctors_aux ()
#11 0x080a2105 in _init ()
#12 0x2824037f in ?? () from /libexec/ld-elf.so.1
-----------------------

Global vars init orders seem different between 12.1 and 11.3 :

12.1 calls __cxx_global_var_init () from lftp.cc:70 first,
while 11.3 calls __cxx_global_var_init () from network.cc:478

...and the latter tries to ResMgr::Set() a value:

ResMgr::Set("dns:order",0,"inet");
(see src/network.cc:485)

while ResType::Register() has not been called yet (it should have been, through a call to ResDecl constructor from lftp.cc:70).

Any idea why those initializations are not done in the same order between 11.3 and 12.1 ?
Comment 9 Ganael LAPLANCHE freebsd_committer freebsd_triage 2020-01-14 16:40:18 UTC
Hello,

From what I understand, the order of initialization of global variables in different translation units (source files) is unspecified in C++ and global variables from network.cc (which leads to calling NetworkInit::NetworkInit() constructor) seem to be initialized *before* types_by_name gets instanciated.

Find attached a quick and dirty patch that fixes the problem by forcing types_by_name instanciation before each pointer de-reference. Unfortunately, it is not optimal: it avoids NULL pointer de-refencing but some resources may remain unset.

In our case, src/resource.cc has not yet declared global lftp_vars so NetworkInit::NetworkInit() from src/network.cc cannot yet find and set "dns:order", so it remains unset (and this is not what we want). This could theoretically be the same problem for any resource set before it has been globally declared.

The good fix would probably be to ensure that lftp resources get always declared before the get accessed, so I'll submit bu report upstream to get feedback from the original author.

Best regards,
Ganael.
Comment 10 Ganael LAPLANCHE freebsd_committer freebsd_triage 2020-01-14 16:41:44 UTC
Created attachment 210736 [details]
Patch to illustrate the problem (not a proper fix)
Comment 11 Ganael LAPLANCHE freebsd_committer freebsd_triage 2020-01-14 16:52:21 UTC
Bug report submitted upstream: https://github.com/lavv17/lftp/issues/565
Comment 12 commit-hook freebsd_committer freebsd_triage 2020-01-15 11:04:42 UTC
A commit references this bug:

Author: martymac
Date: Wed Jan 15 11:04:12 UTC 2020
New revision: 523101
URL: https://svnweb.freebsd.org/changeset/ports/523101

Log:
  Fix segmentation fault at startup when IPv6 is enabled

  Backport commit 5d34493 from upstream.

  PR:		243307
  Submitted by:	Victor Sudakov <vas@sibptus.ru>
  Obtained from:	Github <https://github.com/lavv17/lftp/commit/5d344937d60380341c20409c11f135afb630d7ee>
  MFH:		2020Q1

Changes:
  head/ftp/lftp/Makefile
  head/ftp/lftp/files/patch-5d34493.txt
Comment 13 commit-hook freebsd_committer freebsd_triage 2020-01-16 16:11:39 UTC
A commit references this bug:

Author: martymac
Date: Thu Jan 16 16:10:51 UTC 2020
New revision: 523247
URL: https://svnweb.freebsd.org/changeset/ports/523247

Log:
  MFH: r523101

  Fix segmentation fault at startup when IPv6 is enabled

  Backport commit 5d34493 from upstream.

  PR:		243307
  Submitted by:	Victor Sudakov <vas@sibptus.ru>
  Obtained from:	Github <https://github.com/lavv17/lftp/commit/5d344937d60380341c20409c11f135afb630d7ee>

  Approved by:	portmgr

Changes:
_U  branches/2020Q1/
  branches/2020Q1/ftp/lftp/Makefile
  branches/2020Q1/ftp/lftp/files/patch-5d34493.txt
Comment 14 Ganael LAPLANCHE freebsd_committer freebsd_triage 2020-01-16 16:14:49 UTC
MFH to 2020Q1 done.

Thanks again for your bug report!