[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#609756: marked as done (vsnprintf segfaults on second attempt with alloca)



Your message dated Sat, 4 Jun 2011 18:53:30 +0200
with message-id <20110604165330.GA22852@volta.aurel32.net>
and subject line Re: Bug#609756: vsnprintf segfaults on second attempt with alloca
has caused the Debian Bug report #609756,
regarding vsnprintf segfaults on second attempt with alloca
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
609756: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=609756
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: libc6
Version: 2.7-18lenny7

It is not a heisenbug as suggested by the file name. Its a hard one. It
fails, but man page malloc example works.

Is this a bug in vsnprintf or my fprint.c?

I use alloca which appears to succeed before calling vsnprintf which
then segfaults.

String is no larger than many auto arrays. Is stack allocation failing
later?



/*
fprint.c - unistdio fprint function - Andrew Buckeridge
*/
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <alloca.h>
#include "fprint.h"
/*
#include <string.h>
*/
/* +Ve == bytes written -Ve == bytes required */

int vfnprint(int fdout, int r, const char *fmt, va_list ap)
{
	int i;
	char *p;

	p=alloca(r);

	p[r-1]='\0';
/*
	memset(p,0,r);
*/
/* NB: alloca may return shit, but no it _IS_ vsnprintf */

fprintf(stderr,"\nvsnprintf(%d,%d,%p,...)=",fdout,r,fmt);

/* segfault inside this  */
	i=vsnprintf(p,r,fmt,ap);

fprintf(stderr,"=%d\n",i);

	if(i<0) {
		return 1-2*r;
	}
	if(i<r) {
		return ((write(fdout,p,i))==i)?i:-1;
	}
	return -i;
}

/* +Ve == bytes written -Ve == failure */

int vfprint(int fdout, const char *fmt, va_list ap)
{
	int i=NONSTDBUF;
	i=vfnprint(fdout, i, fmt, ap);
	if(i<-1)
		i=vfnprint(fdout, 1-i, fmt, ap);
	return i;
}

int fprint(int fdout, const char *fmt, ...)
{
	va_list ap;
	int r;

	va_start(ap, fmt);
	r=vfprint(fdout, fmt, ap);
	va_end(ap);
	return r;
}




/*
fprint.h - unistdio fprint fuction - Andrew Buckeridge
*/
#define NONSTDBUF 1024

int vfnprint(int fdout, int r, const char *fmt, va_list ap);
int vfprint(int fdout, const char *fmt, va_list ap);
int fprint(int fdout, const char *fmt, ...);


/*BINFMTC: -O -Wuninitialized -Werror -pedantic-errors
Goes away when you strace. With other example in which read from pipe
gets broken up. This is now a hard bug.
*/

#include <string.h>
#include "fprint.c"

int main()
{
	char b[1024];

	memset(b,'H',1024);
	/* b[1022]='\n'; */
	b[1023]='\0';

/* we succeed on first go */
	fprint(1,"%s",b);

/* we fail on first go but second go segfaults */
	fprint(1,"%s\n",b);

/* not reached */
	fprint(1,"%dH%s\n",strlen(b),b);

	return 0;
}


/*BINFMTC: -O -Wuninitialized -Werror -pedantic-errors
The man page example works.
*/
#include <string.h>
#include <unistd.h>

       #include <stdio.h>
       #include <stdlib.h>
       #include <stdarg.h>

       char *
       make_message(const char *fmt, ...)
       {
           /* Guess we need no more than 100 bytes. */
           int n, size = 100;
           char *p, *np;
           va_list ap;

           if ((p = malloc(size)) == NULL)
               return NULL;

           while (1) {
               /* Try to print in the allocated space. */
               va_start(ap, fmt);
               n = vsnprintf(p, size, fmt, ap);
               va_end(ap);
               /* If that worked, return the string. */
               if (n > -1 && n < size)
                   return p;
               /* Else try again with more space. */
               if (n > -1)    /* glibc 2.1 */
                   size = n+1; /* precisely what is needed */
               else           /* glibc 2.0 */
                   size *= 2;  /* twice the old size */
               if ((np = realloc (p, size)) == NULL) {
                   free(p);
                   return NULL;
               } else {
                   p = np;
               }
           }
       }

int main()
{

	char *s;
	char b[1024];

	memset(b,'H',1024);
	/* b[1022]='\n'; */
	b[1023]='\0';

/* we succeed on first go */
	s=make_message("%s",b);
	write(1,s,strlen(s));
	free(s);

/* we fail on first go but second go segfaults */
	s=make_message("%s\n",b);
	write(1,s,strlen(s));
	free(s);

/* not reached */
	s=make_message("%dH%s\n",strlen(b),b);
	write(1,s,strlen(s));
	free(s);

	return 0;
}


--- End Message ---
--- Begin Message ---
On Wed, Jan 12, 2011 at 06:01:55PM +0000, Florian Weimer wrote:
> * Andrew Buckeridge:
> 
> > C99 only va_copy does help. This is a new one for me.
> > Does vfnprint destroy the callers ap?
> 
> Yes, it does.  Not on all platforms, but on amd64, for example.
> Passing va_list as an argument does not make a sufficiently deep copy,
> so that va_arg in the callee affects subsequent va_arg invocations in
> the caller.
> 

As Florian explained, vfnprint() may destroy the callers ap depending
on the architecture. va_copy should be used in that case.

This is therefore not a GNU libc bug, I am closing it.

-- 
Aurelien Jarno                          GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net


--- End Message ---

Reply to: