bruce@stride.UUCP (Bruce Robertson) (03/26/86)
Description:
There is a bug in Standard I/O for System V Release 2 Version 2. If
you have more than one FILE stream open on a single file descriptor,
bad things to your malloc() heap space happen.
Throughout the stdio code, the end of the buffer associated with
a stream is referenced by the macro _bufend(). This macro is
defined in /usr/include/stdio.h, and references a table of pointers
the end of the buffers. The problem is, the table is referenced
like this:
_bufendtab[(p)->_file]
where `p' is your FILE pointer. This is wrong. What you really
want to do is reference the table like this:
_bufendtab[(p) - &_iob[0]]
which associates slots in the table of pointers with slots in
the table of _iob structures.
Repeat-By:
int fd;
FILE *fp1, *fp2;
fd = open("/dev/tty", 2);
fp1 = fdopen(fd, "r");
fp2 = fdopen(fd, "w");
Subsequent fputs() calls to `fp2' will cause random areas of
memory to be modified, because the data structures that describe
the length of the buffer have been clobbered.
Fix:
Two fixes - one to /usr/include/stdio.h, and another to
/usr/src/lib/libc/port/print/doprnt.c, which also references
the table incorrectly, without using the macro. Note that
after making the change to /usr/include/stdio.h, you must
recompile everything in /usr/src/lib/libc/port/stdio.
*** /usr/include/stdio.h-old Mon Jul 2 19:32:20 1984
--- /usr/include/stdio.h Tue Mar 4 22:14:47 1986
***************
*** 54,60
#define stdout (&_iob[1])
#define stderr (&_iob[2])
! #define _bufend(p) _bufendtab[(p)->_file]
#define _bufsiz(p) (_bufend(p) - (p)->_base)
#ifndef lint
--- 54,60 -----
#define stdout (&_iob[1])
#define stderr (&_iob[2])
! #define _bufend(p) _bufendtab[(p) - &_iob[0]]
#define _bufsiz(p) (_bufend(p) - (p)->_base)
#ifndef lint
*** /usr/src/lib/libc/port/print/doprnt.c-old Tue Mar 25 21:26:41 1986
--- /usr/src/lib/libc/port/print/doprnt.c Tue Mar 25 21:26:43 1986
***************
*** 159,165
bufptr = iop->_ptr;
bufferend = (fno == _NFILE) ?
(unsigned char *)((long) bufptr | (-1L & ~HIBITL))
! : _bufendtab[fno];
}
/*
--- 159,165 -----
bufptr = iop->_ptr;
bufferend = (fno == _NFILE) ?
(unsigned char *)((long) bufptr | (-1L & ~HIBITL))
! : _bufend(iop);
}
/*
--
Bruce Robertson
UUCP: cbosgd!utah-cs!utah-gr!stride!bruce
ARPA: stride!bruce@utah-gr.arpakwh@bentley.UUCP (03/28/86)
In article <562@stride.stride.UUCP> stride!bruce (Bruce Robertson) writes: >The problem is, the table is referenced like this: > _bufendtab[(p)->_file] >where `p' is your FILE pointer. This is wrong. What you really >want to do is reference the table like this: > _bufendtab[(p) - &_iob[0]] >which associates slots in the table of pointers with slots in >the table of _iob structures. This assumes that all objects of type FILE are in the _iob[] array. This is not necessarily the case; e.g. there is an auto variable of type FILE (not FILE*) in sprintf(); there may be others. Are you sure that having two streams on one descriptor is legal? Is there any documentation that explicitly permits or forbids it? Now, the *real* question. Why is _bufendtab[] in a separate array, rather than being another field in the FILE structure where it seems to belong? Karl W. Z. Heuer (ihnp4!bentley!kwh), The Walking Lint