mdemo ltdl failure

Charles Wilson libtool@cwilson.fastmail.fm
Fri Mar 16 15:35:00 GMT 2007


[cross-posted to cygwin]

Ralf Wildenhues wrote:
> A (very small) progress report.
> On Tue, Feb 27, 2007 at 11:02:01PM +0100, Ralf Wildenhues wrote:
>> * Charles Wilson wrote on Tue, Feb 27, 2007 at 05:42:50AM CET:
>> > Ralf Wildenhues wrote:
>> > >The only thing that's then still worrying me is that on Cygwin, the
>> > >mdemo and mdemo_static programs sometimes throw segmentation faults
>> > >on my system.  Not all the time though.
>> > > Well, it's failing all the time for me, but I'm not sure it's a > 
>> segfault. What does "Hangup" mean, when reported by the shell after > 
>> executing the app:
>> Good question, I don't know.  I suppose there is memory corruption
>> earlier, and due to it anything weird can happen later, so the exit
>> status is not really reliable.

When I compiled with -O0, the error message changed to 'Aborted (core 
dumped)'.  It was indeed a segfault, and occurred at line 1582 in 
ltdl.c: 'FREE(buf)' within lt_argz_insertdir.

> It's exposed by try_iterate which calls lt_dlforeachfile.  I think it's
> somewhere in dirent code.  I have a feeling that it's not caused by
> anything in Libtool, but am not sure.  (Only noting this because it may
> ring a bell, not because I have any evidence.)

I've (almost) tracked down the error: it is caused by yet another bug in 
newlib's argz_insert() (or possibly realloc()! ), as called by 
lt_argz_insert:

1473	static int
1474	lt_argz_insert (char **pargz, size_t *pargz_len, char *before,
1475			const char *entry)
1476	{
1477	  error_t error;
1478
1479	  /* Prior to Sep 8, 2005, newlib had a bug where argz_insert(pargz,
1480	     pargz_len, NULL, entry) failed with EINVAL.  */
1481	  if (before)
1482	    error = argz_insert (pargz, pargz_len, before, entry);
1483	  else
1484	    error = argz_append (pargz, pargz_len, entry, 1 + strlen (entry));
1485
1486	  if (error)

The very first time argz_insert() is called -- rather than argz_append() 
-- the memory pointed to by pargz and entry gets corrupted (entry is 
known as 'buf' back in the caller lt_argz_insertdir.)

The value of 'entry' and 'before' during each successive call to 
lt_arg_insert() was:

"tests/mdemo/config", NULL
"tests/mdemo/foo1", NULL
"tests/mdemo/foo2", NULL
"tests/mdemo/libfoo2", NULL
"tests/mdemo/libmlib", NULL
"tests/mdemo/libsub", NULL
"tests/mdemo/libtool", NULL
"tests/mdemo/main", NULL
"tests/mdemo/Makefile", == *pargz

Note that dirent is returning filenames in case-insensitive alphabetical 
order -- but lt_argz_insertinorder() is using case-sensitive comparison, 
so Makefile gets inserted at the front of the list, while all the others 
were successively appended to the pargz list.

What's odd is that this bug in argz_insert() is very ticklish: it 
triggers on "tests/mdemo/Makefile", but not when argz_insert is called 
with "./tests/mdemo/Makefile".  See the attached gdb screenshots from 
just before the buggy call and just after. I've highlighted in red the 
location to which *pargz points, and in blue the location to which entry 
(ne' buf) points.

The "after" shot indicates that the original contents of entry got 
copied to some 11 bytes prior to the beginning of the *pargz buffer, 
overlapping the beginning of the newly realloc'ed *pargz.  Furthermore, 
after the call, the *pargz buffer -- if the value of of *pargz and 
*pargz_len are to be believed -- extends across where entry (e.g. buf) 
points -- so the malloc subsytem obviously no longer thinks *buf is an 
allocated block (otherwise, it wouldn't have included that chunk in the 
memory assigned to *pargz by the realloc).  So, naturally, FREE(buf) fails.

I need to verify this using a debug-built cygwin kernel, but it looks 
like within newlib's argz_insert(), the call to realloc() is not 
operating correctly in this instance.

Note that using libltdl's own argz routines "fixes" this problem, 
perhaps because libltdl's argz_insert does not use realloc, but rather 
explicitly mallocs the new memory, does the copy, explicitly frees the 
old memory, and then does the *pargz pointer reassignment.

export ac_cv_func_argz_append=no;
export ac_cv_func_argz_create_sep=no;
export ac_cv_func_argz_insert=no;
export ac_cv_func_argz_next=no;
export ac_cv_func_argz_stringify=no;
export ac_cv_header_argz_h=no
../libtool-HEAD/configure FC=no CFLAGS="-ggdb -O0"
make
make -k check-TESTS TESTS='tests/mdemo-conf.test tests/mdemo-make.test 
tests/mdemo-exec.test' VERBOSE=t CFLAGS="-ggdb -O0"

works just fine (and I've verified that in this case, _lt__argz_insert() 
is being used, not cygwin's argz_insert()).

--
Chuck

P.S. all this was done using libtool-HEAD from yesterday, most recent 
changelog entry:

2007-03-09  Gary V. Vaughan  <...>

         * libtoolize.m4sh: Replace literal tab chars in help comment
         with spaces to align columns in --help output.

which unfortunately exhibited new testsuite failures in Subproject 
Libltdl...

  33: compiling softlinked libltdl FAILED (subproject.at:59)
  34: compiling copied libltdl     FAILED (subproject.at:75)
  35: installable libltdl          FAILED (subproject.at:95)

Haven't even tried to track these down.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: argz_insert-before.PNG
Type: image/png
Size: 37481 bytes
Desc: not available
URL: <http://cygwin.com/pipermail/cygwin/attachments/20070316/26365ba7/attachment.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: argz_insert-after.PNG
Type: image/png
Size: 36249 bytes
Desc: not available
URL: <http://cygwin.com/pipermail/cygwin/attachments/20070316/26365ba7/attachment-0001.png>
-------------- next part --------------
--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


More information about the Cygwin mailing list