[comp.lang.c] _IOSTRG in stdio.h

mouse@mcgill-vision.UUCP (der Mouse) (11/15/88)

In article <14413@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> In article <1004@cps3xx.UUCP> usenet@cps3xx.UUCP (Usenet file owner) writes:
>> Could someone tell me what the _IOSTRG parameter in stdio.h on BSD
>> controls?
> Absolutely nothing.  It is never tested.  You can expect it to vanish
> in the future.

[Reality check time: I'm about to disagree with Chris.]

From flsbuf.c:
	fclose(iop)
		register FILE *iop;
	{
....
		if (iop->_flag&(_IOREAD|_IOWRT|_IORW) && (iop->_flag&_IOSTRG)==0) {

From filbuf.c:
	_filbuf(iop)
	register FILE *iop;
	{
....
		if (iop->_flag&(_IOSTRG|_IOEOF))

(And yes, Chris, this is the distribution stdio, not my stdio.)

To answer what the original poster probably wanted to know, _IOSTRG
indicates that the stream is a fake stream for I/O to a string: sprintf
or sscanf.  As for what it actually *controls*, Chris is almost
correct; I think _doprnt doesn't check this flag at all [VAX version],
and (bug alert!) neither does _flsbuf.  If you sprintf more than 32K,
sprintf will make mistakes.  Initially, the mistakes are (relatively)
benign (the sprintffed output past 32K gets stuffed in malloc()ed
memory which is then lost), but if you push it to 40K, it will start
flushing stuff to a random file descriptor ("random" = "stack trash"),
which in my tests happened to be 0, the standard input.  Examination of
the code indicates that potential exists for it to drop core if it gets
the wrong stack trash.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

chris@mimsy.UUCP (Chris Torek) (11/15/88)

>In article <14413@mimsy.UUCP> I claimed:
>>... It is never tested.  You can expect it to vanish in the future.

[what, Never? well, Hardly Ever :-) ]

In article <1353@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP
(der Mouse) writes:
>[Reality check time: I'm about to disagree with Chris.]

[Yipes, that was my third egregious netnews error in the last few weeks.
What *is* the world coming to?  ... Must have been the worm! :-) ]

>flsbuf.c:
>	fclose(iop)
>....
>		(iop->_flag&_IOSTRG)==0

This one is actually rather amusing, as the routines which set _IOSTRG
never call fclose(), and the FILE blocks in which _IOSTRG is set are
not on the regular list, so an exit() in a signal handler will never
see them.  In other words, this test is always true.

>filbuf.c:
>		if (iop->_flag&(_IOSTRG|_IOEOF))

This one is probably actually necessary in the current implementation.
(Actually, there is an easy hack to make it unnecessary.)

The last time I actually ran `grep _IOSTRG' on the source was for
4.1BSD, as I had just run into an interesting bug in (Gosling) Emacs.

>To answer what the original poster probably wanted to know, _IOSTRG
>indicates that the stream is a fake stream for I/O to a string: sprintf
>or sscanf.  As for what it actually *controls*, Chris is almost
>correct; I think _doprnt doesn't check this flag at all [VAX version],
>and (bug alert!) neither does _flsbuf.

Right.  This led to the bug I was investigating when I found this.

>If you sprintf more than 32K, sprintf will make mistakes.  Initially,
>the mistakes are (relatively) benign (the sprintffed output past 32K
>gets stuffed in malloc()ed memory which is then lost), but if you push
>it to 40K, it will start flushing stuff to a random file descriptor ....

I was using a routine called `sprintfl', which took a length parameter
and `guaranteed' not to write past the end of that length.  The code
was (before varargs cleanup)

	char *
	sprintfl(buf, len, fmt, a1)
		char *buf;
		int len;
		char *fmt;
	{
		FILE f;

		f._flag = _IOWRT|_IOSTRG;
		f._ptr = buf;
		f._cnt = len - 1;
		_doprnt(fmt, &a1, &f);
		putc('\0', &f);
		buf[len-1] = '\0';
		return (buf);
	}

It misbehaved terribly (along the lines der Mouse indicated).
The `fix' was to change the first code line to

		f._flag = _IOSTRG;
	
!
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris