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.arpa
kwh@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