From vd@datamax.bg  Wed Nov  9 11:48:25 2005
Return-Path: <vd@datamax.bg>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 9C9AA16A41F;
	Wed,  9 Nov 2005 11:48:25 +0000 (GMT)
	(envelope-from vd@datamax.bg)
Received: from jengal.datamax.bg (jengal.datamax.bg [82.103.104.21])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 1E44E43D45;
	Wed,  9 Nov 2005 11:48:24 +0000 (GMT)
	(envelope-from vd@datamax.bg)
Received: from qlovarnika.bg.datamax (qlovarnika.bg.datamax [192.168.10.2])
	by jengal.datamax.bg (Postfix) with SMTP id 4A801B830;
	Wed,  9 Nov 2005 13:48:23 +0200 (EET)
Received: (nullmailer pid 41555 invoked by uid 1002);
	Wed, 09 Nov 2005 11:48:23 -0000
Message-Id: <20051109114823.GA2512@qlovarnika.bg.datamax>
Date: Wed, 9 Nov 2005 13:48:23 +0200
From: Vasil Dimov <vd@datamax.bg>
Reply-To: vd@datamax.bg
To: FreeBSD-gnats-submit@freebsd.org
Cc: kevlo@FreeBSD.org, bug-libextractor@gnu.org
Subject: [patch] fix textproc/libextractor double free() bug
X-Send-Pr-Version: 3.113

>Number:         88716
>Category:       ports
>Synopsis:       [patch] textproc/libextractor fix double free() bug
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kevlo
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Nov 09 11:50:13 GMT 2005
>Closed-Date:    Fri Nov 11 05:11:01 GMT 2005
>Last-Modified:  Fri Nov 11 05:11:01 GMT 2005
>Originator:     Vasil Dimov
>Release:        FreeBSD 6.0-STABLE amd64
>Organization:
DataMax
>Environment:

System: FreeBSD qlovarnika.bg.datamax 6.0-STABLE FreeBSD 6.0-STABLE #0: Tue Nov  8 09:24:59 EET 2005     root@qlovarnika.bg.datamax:/usr/obj/usr/src/sys/QLOVARNIKA  amd64

>Description:

Problem: `make check' for textproc/libextractor fails:
...
make  check-TESTS
lt-trivialtest in free(): error: chunk is already free
Abort trap (core dumped)
FAIL: trivialtest
PASS: keywordlisttest
lt-plugintest in free(): error: chunk is already free
Abort trap (core dumped)
FAIL: plugintest
lt-multiload in free(): error: chunk is already free
Abort trap (core dumped)
FAIL: multiload
=========================================
3 of 4 tests failed
Please report to bug-libextractor@gnu.org
=========================================
...

(NOTE: options AJ are set via malloc.conf(3))

Lets look closer to one of the failing progs:

$ cd libextractor-0.5.6a/src/test
$ ./.libs/lt-trivialtest
lt-trivialtest in free(): error: chunk is already free
Abort trap: 6 (core dumped)
$

gdb is useless here, because it segfaults itself, so I used printfs to
locate the problem.

the following is self-explanatory trace of the program, created by
inserting printfs in the appropriate places:
(the prog is being run via electricfence to make it crash as soon as
possible)

$ ./.libs/lt-trivialtest
extractor.c:216 le_ltdl_init begin
extractor.c:253 le_ltdl_init end
trivialtest.c:24 main begin
extractor.c:216 le_ltdl_init begin
extractor.c:235 le_ltdl_init old_dlsearchpath=0x801122fcc
extractor.c:237 le_ltdl_init old_dlsearchpath=/usr/lib/libextractor:/usr/local/lib/libextractor
extractor.c:253 le_ltdl_init end
extractor.c:258 le_ltdl_fini begin
ltdl.c:4058 lt_dlsetsearchpath search_path=0x801122fcc
ltdl.c:4060 lt_dlsetsearchpath search_path=/usr/lib/libextractor:/usr/local/lib/libextractor
extractor.c:274 le_ltdl_fini end
trivialtest.c:28 main between
extractor.c:216 le_ltdl_init begin
extractor.c:235 le_ltdl_init old_dlsearchpath=0x802cd3fcc
extractor.c:237 le_ltdl_init old_dlsearchpath=/usr/lib/libextractor:/usr/local/lib/libextractor
extractor.c:253 le_ltdl_init end
extractor.c:258 le_ltdl_fini begin
ltdl.c:4058 lt_dlsetsearchpath search_path=0x802cd3fcc
ltdl.c:4060 lt_dlsetsearchpath search_path=/usr/lib/libextractor:/usr/local/lib/libextractor
extractor.c:274 le_ltdl_fini end
trivialtest.c:31 main end
extractor.c:258 le_ltdl_fini begin
ltdl.c:4058 lt_dlsetsearchpath search_path=0x802cd3fcc
Bus error: 10 (core dumped)
$

You see, the destructor le_ltdl_fini() is being called "unexpectedly" when
the program exits, but search_path=0x802cd3fcc has already been free()d by
the previous invocation.

Fix: it seems quite trivial, we just need to old_dlsearchpath = NULL
after free()ing it - lt_dlsetsearchpath() is checking if called with NULL
pointer and we are calling free() only if old_dlsearchpath is non-NULL.

With the included patch, output of trivialtest looks like:

$ ./.libs/lt-trivialtest
extractor.c:216 le_ltdl_init begin
extractor.c:253 le_ltdl_init end
trivialtest.c:24 main begin
extractor.c:216 le_ltdl_init begin
extractor.c:235 le_ltdl_init old_dlsearchpath=0x801122fcc
extractor.c:237 le_ltdl_init old_dlsearchpath=/usr/lib/libextractor:/usr/local/lib/libextractor
extractor.c:253 le_ltdl_init end
extractor.c:258 le_ltdl_fini begin
ltdl.c:4058 lt_dlsetsearchpath search_path=0x801122fcc
ltdl.c:4060 lt_dlsetsearchpath search_path=/usr/lib/libextractor:/usr/local/lib/libextractor
extractor.c:274 le_ltdl_fini end
trivialtest.c:28 main between
extractor.c:216 le_ltdl_init begin
extractor.c:235 le_ltdl_init old_dlsearchpath=0x802cd3fcc
extractor.c:237 le_ltdl_init old_dlsearchpath=/usr/lib/libextractor:/usr/local/lib/libextractor
extractor.c:253 le_ltdl_init end
extractor.c:258 le_ltdl_fini begin
ltdl.c:4058 lt_dlsetsearchpath search_path=0x802cd3fcc
ltdl.c:4060 lt_dlsetsearchpath search_path=/usr/lib/libextractor:/usr/local/lib/libextractor
extractor.c:274 le_ltdl_fini end
trivialtest.c:31 main end
extractor.c:258 le_ltdl_fini begin
ltdl.c:4058 lt_dlsetsearchpath search_path=0x0
ltdl.c:4060 lt_dlsetsearchpath search_path=(null)
extractor.c:274 le_ltdl_fini end
$

And of-course...
$ make check
...
==================
All 4 tests passed
==================
$

>How-To-Repeat:

export MALLOC_OPTIONS=AJ
cd /usr/ports/textproc/libextractor
make check

>Fix:

--- libextractor_free.diff begins here ---
diff -urN --exclude=CVS libextractor.orig/Makefile libextractor/Makefile
--- libextractor.orig/Makefile	Sun Nov  6 02:20:45 2005
+++ libextractor/Makefile	Wed Nov  9 12:55:44 2005
@@ -7,7 +7,7 @@
 
 PORTNAME=	libextractor
 PORTVERSION=	0.5.6a
-PORTREVISION=	1
+PORTREVISION=	2
 CATEGORIES=	textproc
 MASTER_SITES=	http://gnunet.org/libextractor/download/ \
 		${MASTER_SITE_GNU}
diff -urN --exclude=CVS libextractor.orig/files/patch-src::main::extractor.c libextractor/files/patch-src::main::extractor.c
--- libextractor.orig/files/patch-src::main::extractor.c	Thu Jan  1 02:00:00 1970
+++ libextractor/files/patch-src::main::extractor.c	Wed Nov  9 12:02:48 2005
@@ -0,0 +1,14 @@
+--- src/main/extractor.c.orig	Wed Nov  9 11:57:54 2005
++++ src/main/extractor.c	Wed Nov  9 11:58:31 2005
+@@ -246,8 +246,10 @@
+ 
+ void __attribute__ ((destructor)) le_ltdl_fini(void) {
+   lt_dlsetsearchpath(old_dlsearchpath);
+-  if (old_dlsearchpath != NULL)
++  if (old_dlsearchpath != NULL) {
+     free(old_dlsearchpath);
++    old_dlsearchpath = NULL;
++  }
+ #ifdef MINGW
+   ShutdownWinEnv();
+ #endif
--- libextractor_free.diff ends here ---
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-ports-bugs->kevlo 
Responsible-Changed-By: edwin 
Responsible-Changed-When: Wed Nov 9 11:51:14 GMT 2005 
Responsible-Changed-Why:  
Over to maintainer 

http://www.freebsd.org/cgi/query-pr.cgi?pr=88716 

Adding to audit trail from misfiled PR ports/88748:

Date: Wed, 9 Nov 2005 12:53:05 -0800
From: Christian Grothoff <christian@grothoff.org>

 Patch looks good and will be in the next LE release (is already in subversion 
 2237).  I'm still not sure under which circumstances the _destructor_ 
 function is invoked twice without _constructor_ in the meantime (BSD-ism?) 
 but the patch certainly makes the code cleaner in general.
 
 So, thanks!
 
 Christian [ libextractor maintainer ]


From: Vasil Dimov <vd@datamax.bg>
To: Christian Grothoff <christian@grothoff.org>
Cc: bug-libextractor@gnu.org, FreeBSD-gnats-submit@freebsd.org, kevlo@freebsd.org
Subject: Re: ports/88716: [patch] fix textproc/libextractor double free() bug
Date: Thu, 10 Nov 2005 11:23:54 +0200

 --zhXaljGHf11kAtnf
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 Content-Transfer-Encoding: quoted-printable
 
 On Wed, Nov 09, 2005 at 12:53:05PM -0800, Christian Grothoff wrote:
 > Patch looks good and will be in the next LE release (is already in subver=
 sion=20
 > 2237).  I'm still not sure under which circumstances the _destructor_=20
 > function is invoked twice without _constructor_ in the meantime (BSD-ism?=
 )=20
 
 The constructor and the destructor are called 3 times each:
 
 $ ./.libs/lt-trivialtest
 // constructor call 1, does not initialize old_dlsearchpath
 extractor.c:215 le_ltdl_init begin old_dlsearchpath=3D0x0
 extractor.c:246 le_ltdl_init end old_dlsearchpath=3D0x0
 
 trivialtest.c:23 main begin
 
 // constructor call 2, initializes old_dlsearchpath
 extractor.c:215 le_ltdl_init begin old_dlsearchpath=3D0x0
 extractor.c:246 le_ltdl_init end old_dlsearchpath=3D0x501280
 
 // destructor call 1, frees old_dlsearchpath
 extractor.c:250 le_ltdl_fini begin old_dlsearchpath=3D0x501280
 extractor.c:253 le_ltdl_fini free(0x501280)
 extractor.c:262 le_ltdl_fini end old_dlsearchpath=3D0x501280
 
 // constructor call 3, initializes old_dlsearchpath (again)
 extractor.c:215 le_ltdl_init begin old_dlsearchpath=3D0x501280
 extractor.c:246 le_ltdl_init end old_dlsearchpath=3D0x5012c0
 
 // destructor call 2, frees old_dlsearchpath,
 // initialized from constructor call 3
 extractor.c:250 le_ltdl_fini begin old_dlsearchpath=3D0x5012c0
 extractor.c:253 le_ltdl_fini free(0x5012c0)
 extractor.c:262 le_ltdl_fini end old_dlsearchpath=3D0x5012c0
 
 trivialtest.c:27 main end
 
 // destructor call 3, attempts to free old_dlsearchpath, initialized
 // from constructor call 3
 extractor.c:250 le_ltdl_fini begin old_dlsearchpath=3D0x5012c0
 extractor.c:253 le_ltdl_fini free(0x5012c0)
 lt-trivialtest in free(): error: chunk is already free
 Abort trap: 6 (core dumped)
 $
 
 Lets see what happens on Linux:
 
 $ uname -a
 Linux fqdn 2.4.18-14 #1 Wed Sep 4 13:35:50 EDT 2002 i686 i686 i386 GNU/Linux
 
 $ /lib/libc.so.6
 GNU C Library development release version 2.2.93, by Roland McGrath et al.
 Copyright (C) 1992-2001, 2002 Free Software Foundation, Inc.
 This is free software; see the source for copying conditions.
 There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
 PARTICULAR PURPOSE.
 Compiled by GNU CC version 3.2 20020903 (Red Hat Linux 8.0 3.2-7).
 Compiled on a Linux 2.4.9-9 system on 2002-09-05.
 Available extensions:
         GNU libio by Per Bothner
         crypt add-on version 2.1 by Michael Glad and others
         The C stubs add-on version 2.1.2.
         linuxthreads-0.10 by Xavier Leroy
         BIND-8.2.3-T5B
         NIS(YP)/NIS+ NSS modules 0.19 by Thorsten Kukuk
         Glibc-2.0 compatibility add-on by Cristian Gafton
         libthread_db work sponsored by Alpha Processor Inc
 Report bugs using the `glibcbug' script to <bugs@gnu.org>.
 
 $ gcc --version
 gcc (GCC) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)
 =2E..
 
 $ ./.libs/lt-trivialtest
 extractor.c:215 le_ltdl_init begin old_dlsearchpath=3D(nil)
 extractor.c:246 le_ltdl_init end old_dlsearchpath=3D(nil)
 trivialtest.c:23 main begin
 trivialtest.c:27 main end
 extractor.c:250 le_ltdl_fini begin old_dlsearchpath=3D(nil)
 extractor.c:262 le_ltdl_fini end old_dlsearchpath=3D(nil)
 $
 
 Hmmz, looks quite different.
 
 --=20
 Vasil Dimov
 
 --zhXaljGHf11kAtnf
 Content-Type: application/pgp-signature
 Content-Disposition: inline
 
 -----BEGIN PGP SIGNATURE-----
 
 iD8DBQFDcxGpFw6SP/bBpCARAsxRAKDaYQ+kpRSNf0DEWHW04A4yM8zLXACfZtCx
 eGj4ZxSy2abMsBWx04NcXDU=
 =Hma1
 -----END PGP SIGNATURE-----
 
 --zhXaljGHf11kAtnf--
State-Changed-From-To: open->closed 
State-Changed-By: kevlo 
State-Changed-When: Fri Nov 11 05:10:45 GMT 2005 
State-Changed-Why:  
Committed, thanks. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=88716 
>Unformatted:
