Summary: | fflush violates POSIX on seekable input streams | ||
---|---|---|---|
Product: | glibc | Reporter: | Eric Blake <eblake> |
Component: | stdio | Assignee: | Not yet assigned to anyone <unassigned> |
Status: | NEW --- | ||
Severity: | normal | CC: | chimpatheist, dancol, fweimer, hannes, rjones, siddhesh |
Priority: | P2 | Flags: | fweimer:
security-
|
Version: | 2.13 | ||
Target Milestone: | --- | ||
Host: | Target: | ||
Build: | Last reconfirmed: | ||
Bug Depends on: | |||
Bug Blocks: | 12724 |
Description
Eric Blake
2011-05-23 17:14:06 UTC
The removal of libio.h is making this bug all the more important to fix, so that gnulib can quit mucking around in glibc internals: https://lists.gnu.org/archive/html/bug-gnulib/2018-03/msg00002.html Is there a chance that it can be fixed for 2.28? (In reply to Eric Blake from comment #1) > The removal of libio.h is making this bug all the more important to fix, so > that gnulib can quit mucking around in glibc internals: > https://lists.gnu.org/archive/html/bug-gnulib/2018-03/msg00002.html > > Is there a chance that it can be fixed for 2.28? Still broken in 2020. Similarly, fflush(NULL) should have this effect on all seekable input streams. Maybe I'm wrong, but seems that this bug goes out if fflush() make a call to _IO_switch_to_main_get_area() just before the call to _IO_new_file_sync(). (In reply to chimpatheist from comment #3) > Maybe I'm wrong, but seems that this bug goes out if fflush() make a call to > _IO_switch_to_main_get_area() just before the call to _IO_new_file_sync(). Never mind. Actually, the bug occurs when fflush() is called and _IO_IN_BACKUP is on, but just returning to main_get_area doesn't work. Before switching, we need calculate the difference between fp->_IO_read_end and fp->_IO_read_ptr and adjust fp->_IO_read_ptr after the switch. something like this : fflush(FILE *fp) { : : if(fp->_flags & _IO_IN_BACKUP) { long delta = fp->_IO_read_end - fp->_IO_read_ptr; _IO_switch_to_main_get_area(fp); fp->_IO_read_base -= delta; fp->_IO_read_ptr = fp->_IO_read_base; } : : } More exactly... if(fp->_flags & _IO_IN_BACKUP) { // how many ungetc() ? long delta1 = fp->_IO_read_end - fp->_IO_read_ptr; // how many fgetc() before going to backup area ? long delta2 = fp->_IO_save_base - fp->_IO_buf_base; // choose the better of the two values if(delta1 < delta2) delta2 = delta1; // discard all pushed chars fp->_IO_read_ptr = fp->_IO_read_end; // and reset save_base fp->_IO_save_base -= delta2; _IO_switch_to_main_get_area(fp); } |