From fc77d66abf6ed97a50e30b619b1647759d43f593 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 15 Aug 2002 23:57:00 +0000 Subject: * libio/fileops.c (_IO_file_seekoff_mmap): Leave read pointers at EOF if seek would go past it. (mmap_remap_check): If file position is at or past EOF after check, leave read pointers at EOF and don't seek. * libio/tst-mmap-offend.c: New file. * libio/Makefile (tests): Add it. --- libio/Makefile | 2 +- libio/fileops.c | 41 ++++++++++++++++------- libio/tst-mmap-offend.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 libio/tst-mmap-offend.c (limited to 'libio') diff --git a/libio/Makefile b/libio/Makefile index 28d8519a97..58d6575340 100644 --- a/libio/Makefile +++ b/libio/Makefile @@ -53,7 +53,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ tst-mmap-setvbuf bug-ungetwc1 bug-ungetwc2 tst-atime tst-eof \ tst-freopen bug-rewind bug-ungetc bug-fseek \ tst-mmap-eofsync tst-mmap-fflushsync bug-mmap-fflush \ - tst-mmap2-eofsync + tst-mmap2-eofsync tst-mmap-offend test-srcs = test-freopen all: # Make this the default target; it will be defined in Rules. diff --git a/libio/fileops.c b/libio/fileops.c index 247243f44c..24235e9134 100644 --- a/libio/fileops.c +++ b/libio/fileops.c @@ -665,22 +665,30 @@ mmap_remap_check (_IO_FILE *fp) # undef ROUNDED fp->_offset -= fp->_IO_read_end - fp->_IO_read_ptr; - _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + fp->_offset, + _IO_setg (fp, fp->_IO_buf_base, + fp->_offset < fp->_IO_buf_end - fp->_IO_buf_base + ? fp->_IO_buf_base + fp->_offset : fp->_IO_buf_end, fp->_IO_buf_end); - if ( + /* If we are already positioned at or past the end of the file, don't + change the current offset. If not, seek past what we have mapped, + mimicking the position left by a normal underflow reading into its + buffer until EOF. */ + + if (fp->_offset < fp->_IO_buf_end - fp->_IO_buf_base) + { + if ( # ifdef _G_LSEEK64 - _G_LSEEK64 + _G_LSEEK64 # else - __lseek + __lseek # endif - (fp->_fileno, fp->_IO_buf_end - fp->_IO_buf_base, SEEK_SET) - != fp->_IO_buf_end - fp->_IO_buf_base) - { - fp->_flags |= _IO_ERR_SEEN; - return EOF; + (fp->_fileno, fp->_IO_buf_end - fp->_IO_buf_base, SEEK_SET) + != fp->_IO_buf_end - fp->_IO_buf_base) + fp->_flags |= _IO_ERR_SEEN; + else + fp->_offset = fp->_IO_buf_end - fp->_IO_buf_base; } - fp->_offset = fp->_IO_buf_end - fp->_IO_buf_base; return 0; } @@ -1152,8 +1160,17 @@ _IO_file_seekoff_mmap (fp, offset, dir, mode) if (result < 0) return EOF; - _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + offset, - fp->_IO_buf_base + offset); + if (offset > fp->_IO_buf_end - fp->_IO_buf_base) + /* One can fseek arbitrarily past the end of the file + and it is meaningless until one attempts to read. + Leave the buffer pointers in EOF state until underflow. */ + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_end, fp->_IO_buf_end); + else + /* Adjust the read pointers to match the file position, + but so the next read attempt will call underflow. */ + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + offset, + fp->_IO_buf_base + offset); + fp->_offset = result; _IO_mask_flags (fp, 0, _IO_EOF_SEEN); diff --git a/libio/tst-mmap-offend.c b/libio/tst-mmap-offend.c new file mode 100644 index 0000000000..2025f1d2a8 --- /dev/null +++ b/libio/tst-mmap-offend.c @@ -0,0 +1,86 @@ +/* Test case for bug with mmap stdio read past end of file. */ + +#include +#include +#include + +static void do_prepare (void); +#define PREPARE(argc, argv) do_prepare () +static int do_test (void); +#define TEST_FUNCTION do_test () +#include + +static char *temp_file; + +static const char text1[] = "hello\n"; + +static void +do_prepare (void) +{ + int temp_fd = create_temp_file ("tst-mmap-offend.", &temp_file); + if (temp_fd == -1) + error (1, errno, "cannot create temporary file"); + else + { + ssize_t cc = write (temp_fd, text1, sizeof text1 - 1); + if (cc != sizeof text1 - 1) + error (1, errno, "cannot write to temporary file"); + } + close (temp_fd); +} + +static int +do_test (void) +{ + unsigned char buffer[8192]; + int result = 0; + FILE *f = fopen (temp_file, "r"); + size_t cc; + + if (f == NULL) + { + perror (temp_file); + return 1; + } + + cc = fread (buffer, 1, sizeof (buffer), f); + printf ("fread %zu: \"%.*s\"\n", cc, (int) cc, buffer); + if (cc != sizeof text1 - 1) + { + perror ("fread"); + result = 1; + } + + if (fseek (f, 2048, SEEK_SET) != 0) + { + perror ("fseek off end"); + result = 1; + } + + if (fread (buffer, 1, sizeof (buffer), f) != 0 + || ferror (f) || !feof (f)) + { + printf ("after fread error %d eof %d\n", + ferror (f), feof (f)); + result = 1; + } + + printf ("ftell %ld\n", ftell (f)); + + if (fseek (f, 0, SEEK_SET) != 0) + { + perror ("fseek rewind"); + result = 1; + } + + cc = fread (buffer, 1, sizeof (buffer), f); + printf ("fread after rewind %zu: \"%.*s\"\n", cc, (int) cc, buffer); + if (cc != sizeof text1 - 1) + { + perror ("fread after rewind"); + result = 1; + } + + fclose (f); + return result; +} -- cgit v1.2.3