Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 24 Aug 2004 10:40:21 -0700
From:      Sean McNeil <sean@mcneil.com>
To:        Tim Kientzle <kientzle@freebsd.org>
Cc:        freebsd-current@freebsd.org
Subject:   Re: bsdtar core dumps
Message-ID:  <1093369220.10362.6.camel@server.mcneil.com>
In-Reply-To: <4127841D.6050104@freebsd.org>
References:  <1092777586.92327.9.camel@server.mcneil.com> <20040817213813.GE3827@gothmog.gr><4127841D.6050104@freebsd.org>

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

I think what is happening is that the amd64 architecture passes a
va_list by reference instead of by value.  This is causing a side-effect
within __vfprintf.  To counter the side-effect, the following patch
saves the ap and uses the copy for the second call to vsnprintf.  Here
is a patch that fixes my core dump:

*** lib/libarchive/archive_string_sprintf.c.orig        Fri Aug 13
20:45:45 2004--- lib/libarchive/archive_string_sprintf.c     Tue Aug 24
10:37:02 2004
*************** __archive_string_vsprintf(struct archive
*** 47,63 ****
      va_list ap)
  {
        size_t l;

        if (fmt == NULL) {
                as->s[0] = 0;
                return;
        }

        l = vsnprintf(as->s, as->buffer_length, fmt, ap);
        /* If output is bigger than the buffer, resize and try again. */
        if (l+1 >= as->buffer_length) {
                __archive_string_ensure(as, l + 1);
!               l = vsnprintf(as->s, as->buffer_length, fmt, ap);
        }
        as->length = l;
  }
--- 47,65 ----
      va_list ap)
  {
        size_t l;
+       va_list ap1;

        if (fmt == NULL) {
                as->s[0] = 0;
                return;
        }

+       va_copy(ap1,ap);
        l = vsnprintf(as->s, as->buffer_length, fmt, ap);
        /* If output is bigger than the buffer, resize and try again. */
        if (l+1 >= as->buffer_length) {
                __archive_string_ensure(as, l + 1);
!               l = vsnprintf(as->s, as->buffer_length, fmt, ap1);
        }
        as->length = l;
  }




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1093369220.10362.6.camel>