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

Bug#609756: vsnprintf segfaults on second attempt with alloca



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;
}


Reply to: