Re: bsdtar core dumps

From: Harti Brandt <harti_at_freebsd.org>
Date: Tue, 24 Aug 2004 20:08:12 +0200 (CEST)
On Tue, 24 Aug 2004, Sean McNeil wrote:

SM>On Sat, 2004-08-21 at 10:19, Tim Kientzle wrote:
SM>> Sean McNeil wrote:
SM>> >>>
SM>> >>>I just tried to unarchive a file that didn't exist and got a core dump:
SM>> > 
SM>> > Here is a backtrace of the error:
SM>> > 
SM>> > #0  0x0000000200926d7e in __vfprintf (fp=0x7fffffffe360,
SM>> >     fmt0=0x4161d9 "Failed to open '%s'", ap=0x7fffffffe640)
SM>> >     at /usr/src/lib/libc/stdio/vfprintf.c:1052
SM>> > #1  0x00000002008c4006 in vsnprintf (str=0x32 <Address 0x32 out of bounds>,
SM>> >     n=4284889, fmt=0x4161d9 "Failed to open '%s'", ap=0x7fffffffe640)
SM>> >     at /usr/src/lib/libc/stdio/vsnprintf.c:75
SM>> > #2  0x0000000000411478 in __archive_string_vsprintf (as=0x520240,
SM>> >     fmt=0x4161d9 "Failed to open '%s'", ap=0x7fffffffe640)
SM>> >     at /usr/src/lib/libarchive/archive_string_sprintf.c:60
SM>> > 
SM>> > Could be a compiler bug I suppose, but more likely I think it is this
SM>> > code:
SM>> > 
SM>> > 	if (n == 0) {
SM>> > 		if (on > 0)
SM>> > 	  		*str = '\0';
SM>> > 		str = dummy;
SM>> > 		n = 1;
SM>> > 	}
SM>> > 
SM>> > in vsnprintf.c::vsnprintf.
SM>> 
SM>> The code you've pointed to above concerns
SM>> me because of the part about:
SM>>      if (n == 0) {
SM>>            ...
SM>>            n = 1;
SM>>      }
SM>> That ain't right:  If I told vsnprintf the buffer
SM>> size was zero, it should treat it as such.  If I
SM>> meant "one", I would have said "one."
SM>> 
SM>> On the other hand, the vsnprintf.3 man page
SM>> does explicitly state that "the output is always
SM>> null-terminated," which would preclude passing
SM>> a zero-length buffer, which is exactly what
SM>> libarchive is doing in this situation.  It is
SM>> bogus, but at least it's documented bogosity. ;-)
SM>> 
SM>> Please try the attached patch to libarchive/archive_string_sprintf.c
SM>> and let me know if it works for you.  It simply
SM>> forces the target buffer to be allocated and thereby
SM>> avoids calling vsnprintf with a NULL buffer.
SM>> 
SM>> Tim Kientzle
SM>> 
SM>> ______________________________________________________________________
SM>> Index: archive_string_sprintf.c
SM>> ===================================================================
SM>> RCS file: /home/ncvs/src/lib/libarchive/archive_string_sprintf.c,v
SM>> retrieving revision 1.4
SM>> diff -u -r1.4 archive_string_sprintf.c
SM>> --- archive_string_sprintf.c	14 Aug 2004 03:45:45 -0000	1.4
SM>> +++ archive_string_sprintf.c	21 Aug 2004 17:02:49 -0000
SM>> _at__at_ -48,6 +48,9 _at__at_
SM>>  {
SM>>  	size_t l;
SM>>  
SM>> +	/* Make sure the target area is initialized. */
SM>> +	__archive_string_ensure(as, 64);
SM>> +
SM>>  	if (fmt == NULL) {
SM>>  		as->s[0] = 0;
SM>>  		return;
SM>
SM>I think what is happening is that the amd64 architecture passes a
SM>va_list by reference instead of by value.  This is causing a side-effect
SM>within __vfprintf.  To counter the side-effect, the following patch
SM>saves the ap and uses the copy for the second call to vsnprintf.  Here
SM>is a patch that fixes my core dump:

Sorry to jump in.

You cannot use a va_list twice. As soon as someone call va_arg() on the
ap all the aps in the calling functions get invalid. The only thing that 
can and must be done is that the function that did the va_start() must 
call va_end.

If you need it twice you must make a copy as in the patch below.
But the function call va_copy must also call va_end() on that copy
(this seems missing in the patch).

harti

SM>
SM>*** lib/libarchive/archive_string_sprintf.c.orig        Fri Aug 13
SM>20:45:45 2004--- lib/libarchive/archive_string_sprintf.c     Tue Aug 24
SM>10:37:02 2004
SM>*************** __archive_string_vsprintf(struct archive
SM>*** 47,63 ****
SM>      va_list ap)
SM>  {
SM>        size_t l;
SM>
SM>        if (fmt == NULL) {
SM>                as->s[0] = 0;
SM>                return;
SM>        }
SM>
SM>        l = vsnprintf(as->s, as->buffer_length, fmt, ap);
SM>        /* If output is bigger than the buffer, resize and try again. */
SM>        if (l+1 >= as->buffer_length) {
SM>                __archive_string_ensure(as, l + 1);
SM>!               l = vsnprintf(as->s, as->buffer_length, fmt, ap);
SM>        }
SM>        as->length = l;
SM>  }
SM>--- 47,65 ----
SM>      va_list ap)
SM>  {
SM>        size_t l;
SM>+       va_list ap1;
SM>
SM>        if (fmt == NULL) {
SM>                as->s[0] = 0;
SM>                return;
SM>        }
SM>
SM>+       va_copy(ap1,ap);
SM>        l = vsnprintf(as->s, as->buffer_length, fmt, ap);
SM>        /* If output is bigger than the buffer, resize and try again. */
SM>        if (l+1 >= as->buffer_length) {
SM>                __archive_string_ensure(as, l + 1);
SM>!               l = vsnprintf(as->s, as->buffer_length, fmt, ap1);
SM>        }
SM>        as->length = l;
SM>  }
SM>
SM>
SM>_______________________________________________
SM>freebsd-current_at_freebsd.org mailing list
SM>http://lists.freebsd.org/mailman/listinfo/freebsd-current
SM>To unsubscribe, send any mail to "freebsd-current-unsubscribe_at_freebsd.org"
SM>
SM>
SM>
Received on Tue Aug 24 2004 - 16:08:13 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:08 UTC