From bf70f6f1face8e36030544a74e5ea04903df16cb Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 8 Jun 2016 21:49:04 +0200 Subject: test: add new mmap tests from glibc Rename mmap2 test as this is a ARM specific test, only execute on ARM systems. Add more new tests from glibc. --- test/mmap/Makefile.in | 6 +++ test/mmap/mmap-arm.c | 46 +++++++++++++++++ test/mmap/mmap2.c | 46 ----------------- test/mmap/tst-mmap-eofsync.c | 106 ++++++++++++++++++++++++++++++++++++++++ test/mmap/tst-mmap-fflushsync.c | 99 +++++++++++++++++++++++++++++++++++++ test/mmap/tst-mmap-offend.c | 86 ++++++++++++++++++++++++++++++++ test/mmap/tst-mmap-setvbuf.c | 81 ++++++++++++++++++++++++++++++ 7 files changed, 424 insertions(+), 46 deletions(-) create mode 100644 test/mmap/Makefile.in create mode 100644 test/mmap/mmap-arm.c delete mode 100644 test/mmap/mmap2.c create mode 100644 test/mmap/tst-mmap-eofsync.c create mode 100644 test/mmap/tst-mmap-fflushsync.c create mode 100644 test/mmap/tst-mmap-offend.c create mode 100644 test/mmap/tst-mmap-setvbuf.c diff --git a/test/mmap/Makefile.in b/test/mmap/Makefile.in new file mode 100644 index 000000000..7bb34acb6 --- /dev/null +++ b/test/mmap/Makefile.in @@ -0,0 +1,6 @@ +# uClibc mmap tests +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +ifneq ($(TARGET_ARCH),arm) +TESTS_DISABLED += mmap-arm +endif diff --git a/test/mmap/mmap-arm.c b/test/mmap/mmap-arm.c new file mode 100644 index 000000000..8b94c6199 --- /dev/null +++ b/test/mmap/mmap-arm.c @@ -0,0 +1,46 @@ +/* When trying to map /dev/mem with offset 0xFFFFF000 on the ARM platform, mmap + * returns -EOVERFLOW. + * + * Since off_t is defined as a long int and the sign bit is set in the address, + * the shift operation shifts in ones instead of zeroes + * from the left. This results the offset sent to the kernel function becomes + * 0xFFFFFFFF instead of 0x000FFFFF with MMAP2_PAGE_SHIFT set to 12. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \ + __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0) + +#define MAP_SIZE 4096UL +#define MAP_MASK (MAP_SIZE - 1) + +int main(int argc, char **argv) { + void* map_base = 0; + int fd; + off_t target = 0xfffff000; + if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) { + /* skip test for non-root users */ + if (errno == EACCES) + return 0; + FATAL; + } + printf("/dev/mem opened.\n"); + fflush(stdout); + + /* Map one page */ + map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, target & ~MAP_MASK); + if(map_base == (void *) -1) FATAL; + printf("Memory mapped at address %p.\n", map_base); + fflush(stdout); + if(munmap(map_base, MAP_SIZE) == -1) FATAL; + close(fd); + return 0; +} diff --git a/test/mmap/mmap2.c b/test/mmap/mmap2.c deleted file mode 100644 index 8b94c6199..000000000 --- a/test/mmap/mmap2.c +++ /dev/null @@ -1,46 +0,0 @@ -/* When trying to map /dev/mem with offset 0xFFFFF000 on the ARM platform, mmap - * returns -EOVERFLOW. - * - * Since off_t is defined as a long int and the sign bit is set in the address, - * the shift operation shifts in ones instead of zeroes - * from the left. This results the offset sent to the kernel function becomes - * 0xFFFFFFFF instead of 0x000FFFFF with MMAP2_PAGE_SHIFT set to 12. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \ - __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0) - -#define MAP_SIZE 4096UL -#define MAP_MASK (MAP_SIZE - 1) - -int main(int argc, char **argv) { - void* map_base = 0; - int fd; - off_t target = 0xfffff000; - if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) { - /* skip test for non-root users */ - if (errno == EACCES) - return 0; - FATAL; - } - printf("/dev/mem opened.\n"); - fflush(stdout); - - /* Map one page */ - map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, - fd, target & ~MAP_MASK); - if(map_base == (void *) -1) FATAL; - printf("Memory mapped at address %p.\n", map_base); - fflush(stdout); - if(munmap(map_base, MAP_SIZE) == -1) FATAL; - close(fd); - return 0; -} diff --git a/test/mmap/tst-mmap-eofsync.c b/test/mmap/tst-mmap-eofsync.c new file mode 100644 index 000000000..e8ef72714 --- /dev/null +++ b/test/mmap/tst-mmap-eofsync.c @@ -0,0 +1,106 @@ +/* Test program for synchronization of stdio state with file after EOF. */ + +#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 int temp_fd; + +static char text1[] = "Line the first\n"; +static char text2[] = "Line the second\n"; + +static void +do_prepare (void) +{ + temp_fd = create_temp_file ("tst-mmap-eofsync.", &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"); + } +} + +static int +do_test (void) +{ + FILE *f; + char buf[128]; + int result = 0; + int c; + + f = fopen (temp_file, "rm"); + if (f == NULL) + { + perror (temp_file); + return 1; + } + + if (fgets (buf, sizeof buf, f) == NULL) + { + perror ("fgets"); + return 1; + } + + if (strcmp (buf, text1)) + { + printf ("read \"%s\", expected \"%s\"\n", buf, text1); + result = 1; + } + + printf ("feof = %d, ferror = %d immediately after fgets\n", + feof (f), ferror (f)); + +#if 1 + c = fgetc (f); + if (c == EOF) + printf ("fgetc -> EOF (feof = %d, ferror = %d)\n", + feof (f), ferror (f)); + else + { + printf ("fgetc returned %o (feof = %d, ferror = %d)\n", + c, feof (f), ferror (f)); + result = 1; + } +#endif + + c = write (temp_fd, text2, sizeof text2 - 1); + if (c == sizeof text2 - 1) + printf ("wrote more to file\n"); + else + { + printf ("wrote %d != %zd (%m)\n", c, sizeof text2 - 1); + result = 1; + } + + if (fgets (buf, sizeof buf, f) == NULL) + { + printf ("second fgets fails: feof = %d, ferror = %d (%m)\n", + feof (f), ferror (f)); + clearerr (f); + if (fgets (buf, sizeof buf, f) == NULL) + { + printf ("retry fgets fails: feof = %d, ferror = %d (%m)\n", + feof (f), ferror (f)); + result = 1; + } + } + if (result == 0 && strcmp (buf, text2)) + { + printf ("second time read \"%s\", expected \"%s\"\n", buf, text2); + result = 1; + } + + fclose (f); + + return result; +} diff --git a/test/mmap/tst-mmap-fflushsync.c b/test/mmap/tst-mmap-fflushsync.c new file mode 100644 index 000000000..24ae33cae --- /dev/null +++ b/test/mmap/tst-mmap-fflushsync.c @@ -0,0 +1,99 @@ +/* Test program for synchronization of stdio state with file after fflush. */ + +#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 int temp_fd; + +static char text1[] = "Line the first\n"; +static char text2[] = "Line the second\n"; + +static void +do_prepare (void) +{ + temp_fd = create_temp_file ("tst-mmap-eofsync.", &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"); + } +} + +static int +do_test (void) +{ + FILE *f; + char buf[128]; + int result = 0; + int c; + + f = fopen (temp_file, "rm"); + if (f == NULL) + { + perror (temp_file); + return 1; + } + + if (fgets (buf, sizeof buf, f) == NULL) + { + perror ("fgets"); + return 1; + } + + if (strcmp (buf, text1)) + { + printf ("read \"%s\", expected \"%s\"\n", buf, text1); + result = 1; + } + + printf ("feof = %d, ferror = %d immediately after fgets\n", + feof (f), ferror (f)); + + if (fflush (f) != 0) + { + printf ("fflush failed! %m\n"); + result = 1; + } + + c = write (temp_fd, text2, sizeof text2 - 1); + if (c == sizeof text2 - 1) + printf ("wrote more to file\n"); + else + { + printf ("wrote %d != %zd (%m)\n", c, sizeof text2 - 1); + result = 1; + } + + if (fgets (buf, sizeof buf, f) == NULL) + { + printf ("second fgets fails: feof = %d, ferror = %d (%m)\n", + feof (f), ferror (f)); + clearerr (f); + if (fgets (buf, sizeof buf, f) == NULL) + { + printf ("retry fgets fails: feof = %d, ferror = %d (%m)\n", + feof (f), ferror (f)); + result = 1; + } + } + if (result == 0 && strcmp (buf, text2)) + { + printf ("second time read \"%s\", expected \"%s\"\n", buf, text2); + result = 1; + } + + fclose (f); + + return result; +} diff --git a/test/mmap/tst-mmap-offend.c b/test/mmap/tst-mmap-offend.c new file mode 100644 index 000000000..19732e620 --- /dev/null +++ b/test/mmap/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, "rm"); + 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; +} diff --git a/test/mmap/tst-mmap-setvbuf.c b/test/mmap/tst-mmap-setvbuf.c new file mode 100644 index 000000000..33d60b7bd --- /dev/null +++ b/test/mmap/tst-mmap-setvbuf.c @@ -0,0 +1,81 @@ +/* Test setvbuf on readonly fopen (using mmap stdio). + Copyright (C) 2002-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +int main (void) +{ + char name[] = "/tmp/tst-mmap-setvbuf.XXXXXX"; + char buf[4096]; + const char * const test = "Let's see if mmap stdio works with setvbuf.\n"; + char temp[strlen (test) + 1]; + int fd = mkstemp (name); + FILE *f; + + if (fd == -1) + { + printf ("%u: cannot open temporary file: %m\n", __LINE__); + exit (1); + } + + f = fdopen (fd, "w"); + if (f == NULL) + { + printf ("%u: cannot fdopen temporary file: %m\n", __LINE__); + exit (1); + } + + fputs (test, f); + fclose (f); + + f = fopen (name, "rm"); + if (f == NULL) + { + printf ("%u: cannot fopen temporary file: %m\n", __LINE__); + exit (1); + } + + if (setvbuf (f, buf, _IOFBF, sizeof buf)) + { + printf ("%u: setvbuf failed: %m\n", __LINE__); + exit (1); + } + + if (fread (temp, 1, strlen (test), f) != strlen (test)) + { + printf ("%u: couldn't read the file back: %m\n", __LINE__); + exit (1); + } + temp [strlen (test)] = '\0'; + + if (strcmp (test, temp)) + { + printf ("%u: read different string than was written:\n%s%s", + __LINE__, test, temp); + exit (1); + } + + fclose (f); + + unlink (name); + exit (0); +} -- cgit v1.2.3