From tim@X3000  Sat Jun  8 21:54:49 1996
Received: from X3000 (ppp1544.on.sympatico.ca [206.172.249.8])
          by freefall.freebsd.org (8.7.5/8.7.3) with ESMTP id VAA16111
          for <FreeBSD-gnats-submit@freebsd.org>; Sat, 8 Jun 1996 21:54:42 -0700 (PDT)
Received: (from tim@localhost) by X3000 (8.7.5/8.7.3) id UAA00331; Sat, 8 Jun 1996 20:52:03 -0400 (EDT)
Message-Id: <199606090052.UAA00331@X3000>
Date: Sat, 8 Jun 1996 20:52:03 -0400 (EDT)
From: Tim Vanderhoek <tim@X3000>
Reply-To: ac199@freenet.hamilton.on.ca
To: FreeBSD-gnats-submit@freebsd.org
Subject: printf(3) manpage lies patently
X-Send-Pr-Version: 3.2

>Number:         1303
>Category:       docs
>Synopsis:       printf(3) manpage lies patently
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:
>Keywords:
>Date-Required:
>Class:          doc-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Jun  8 22:00:01 PDT 1996
>Closed-Date:    Sun Jun 9 08:45:45 MET DST 1996
>Last-Modified:  Sun Jun  9 08:49:30 MET DST 1996
>Originator:     Tim Vanderhoek
>Release:        FreeBSD 2.2-960501-SNAP i386
>Organization:
League of Those With Too Much Time
>Environment:

	bin and manpages distributions installed.  FreeBSD is also installed
somewhere.

>Description:

	The sixth last line of the printf(3) manpage says

"Because sprintf() and vsprintf() assume an infinitely long string, 
callers must be careful not to overflow the actual space; this is often
impossible to assure."

	The last statement in the quote is a patent lie, as the 
following code will readily demonstrate.  It is never impossible 
to assure that sprintf() and vsprintf() do not overflow the actual 
space available to them.

cut here------>

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

/* main (); */ /* "... no type or storage class" :( */
signed int Vasprintf (char **, char *, ...);

main () 
{
	char * string;
	int n;

	n = Vasprintf (&string, "FaVe%d%d%sDeAl", 2355, 1235, "asase");
	printf ("The string \"%s\" occupies %d chars.\n", string, n);
	_exit (-7);
}

signed int Vasprintf (char **ret, char * template, ...)
/* You didn't actually expect me to turn this into avsprintf(), did you!? */
{
	va_list xargs;
	int sockets[2], child;
	FILE *tf;
	int retlen;

	if (pipe(sockets) < 0) {
		perror ("Can't create pipe");
		exit (10);
	}

	va_start (xargs, template);
	if (tf = fdopen (sockets[1], "w")) {
		retlen = vfprintf (tf, template, xargs);
	} else {
		perror ("Can't open stream");
		exit (1);
	}
	va_end (xargs);

	if (!(*ret = (char *) malloc (retlen + 1)))
			perror ("Malloc failure (out of memory?)");
	if (!*ret) exit (666); /* who really reads exit codes, anyways? */

	/* we now know how many chars are to be printed.  Let's DO IT! */

	if (vsprintf (*ret, template, xargs) != retlen) {
		printf ("AHHH!!!  The printf(3) manpages is correct!!\n");
		exit (777);
	} 
	return retlen;
}
/* sockets?  close what sockets? */

<------end cutting here

	No matter what format string we hand Vasprintf() from main(),
it [Vasprintf()] will return the number of characters we need to 
alloc for sprintf() and vsprintf() thus allowing us to prevent them
from "overflowing the actual space" (printf(3)) available to them.

>How-To-Repeat:

	I don't know.

>Fix:
	
	Change the sentence starting on the sixth line of the
printf(3) manpage to

"Because sprintf() and vsprintf() assume an infinitely long string,
callers must be careful not to overflow the actual space; this often
requires a silly function to prevent from happening." 

>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->closed 
State-Changed-By: joerg 
State-Changed-When: Sun Jun 9 08:45:45 MET DST 1996 
State-Changed-Why:  
Slightly reworded in rev 1.5 of printf.3. 

>Unformatted:
 
