From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2178) id 8F18C386F44C; Tue, 12 May 2020 17:03:20 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8F18C386F44C Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Florian Weimer To: glibc-cvs@sourceware.org Subject: [glibc] string: Add string/tst-memmove-overflow, a test case for bug 25620 X-Act-Checkin: glibc X-Git-Author: Florian Weimer X-Git-Refname: refs/heads/master X-Git-Oldrev: 0e28cfff9dfdb71352151054e0d38816856182d5 X-Git-Newrev: eec0f4218cda936a6ab8f543e90b96b196df3fc2 Message-Id: <20200512170320.8F18C386F44C@sourceware.org> Date: Tue, 12 May 2020 17:03:20 +0000 (GMT) X-BeenThere: glibc-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Glibc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 May 2020 17:03:20 -0000 https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=eec0f4218cda936a6ab8f543e90b96b196df3fc2 commit eec0f4218cda936a6ab8f543e90b96b196df3fc2 Author: Florian Weimer Date: Tue May 12 19:02:08 2020 +0200 string: Add string/tst-memmove-overflow, a test case for bug 25620 Reviewed-by: Carlos O'Donell Tested-by: Carlos O'Donell Diff: --- string/Makefile | 2 +- string/tst-memmove-overflow.c | 155 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 1 deletion(-) diff --git a/string/Makefile b/string/Makefile index c46785f1a1..e1cca5516b 100644 --- a/string/Makefile +++ b/string/Makefile @@ -60,7 +60,7 @@ tests := tester inl-tester noinl-tester testcopy test-ffs \ bug-envz1 tst-strxfrm2 tst-endian tst-svc2 \ tst-strtok_r bug-strcoll2 tst-cmp tst-xbzero-opt \ test-endian-types test-endian-file-scope \ - test-endian-sign-conversion + test-endian-sign-conversion tst-memmove-overflow # This test allocates a lot of memory and can run for a long time. xtests = tst-strcoll-overflow diff --git a/string/tst-memmove-overflow.c b/string/tst-memmove-overflow.c new file mode 100644 index 0000000000..b744679ef4 --- /dev/null +++ b/string/tst-memmove-overflow.c @@ -0,0 +1,155 @@ +/* Test for signed comparision bug in memmove (bug 25620). + Copyright (C) 2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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 + . */ + +/* This test shifts a memory region which is a bit larger than 2 GiB + by one byte. In order to make it more likely that the memory + allocation succeeds on 32-bit systems, most of the allocation + consists of shared pages. Only a portion at the start and end of + the allocation are unshared, and contain a specific non-repeating + bit pattern. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEST_MAIN +#define TEST_NAME "memmove" +#include "test-string.h" +#include + +IMPL (memmove, 1) + +/* Size of the part of the allocation which is not shared, at the + start and the end of the overall allocation. 4 MiB. */ +static const size_t unshared_size = 4U << 20; + +/* The allocation is 2 GiB plus 8 MiB. This should work with all page + sizes that occur in practice. */ +static const size_t allocation_size = (2U << 30) + 2 * unshared_size; + +/* Compute the expected byte at the given index. This is used to + produce a non-repeating pattern. */ +static inline unsigned char +expected_value (size_t index) +{ + uint32_t randomized = 0x9e3779b9 * index; /* Based on golden ratio. */ + return randomized >> 25; /* Result is in the range [0, 127]. */ +} + +static int +test_main (void) +{ + test_init (); + + FOR_EACH_IMPL (impl, 0) + { + printf ("info: testing %s\n", impl->name); + + /* Check that the allocation sizes are multiples of the page + size. */ + TEST_COMPARE (allocation_size % xsysconf (_SC_PAGESIZE), 0); + TEST_COMPARE (unshared_size % xsysconf (_SC_PAGESIZE), 0); + + /* The repeating pattern has the MSB set in all bytes. */ + unsigned char repeating_pattern[128]; + for (unsigned int i = 0; i < array_length (repeating_pattern); ++i) + repeating_pattern[i] = 0x80 | i; + + struct support_blob_repeat repeat + = support_blob_repeat_allocate_shared (repeating_pattern, + sizeof (repeating_pattern), + (allocation_size + / sizeof (repeating_pattern))); + if (repeat.start == NULL) + FAIL_UNSUPPORTED ("repeated blob allocation failed: %m"); + TEST_COMPARE (repeat.size, allocation_size); + + /* Unshared the start and the end of the allocation. */ + unsigned char *start = repeat.start; + xmmap (start, unshared_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1); + xmmap (start + allocation_size - unshared_size, unshared_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1); + + /* Initialize the non-repeating pattern. */ + for (size_t i = 0; i < unshared_size; ++i) + start[i] = expected_value (i); + for (size_t i = allocation_size - unshared_size; i < allocation_size; + ++i) + start[i] = expected_value (i); + + /* Make sure that there was really no sharing. */ + asm volatile ("" ::: "memory"); + for (size_t i = 0; i < unshared_size; ++i) + TEST_COMPARE (start[i], expected_value (i)); + for (size_t i = allocation_size - unshared_size; i < allocation_size; + ++i) + TEST_COMPARE (start[i], expected_value (i)); + + /* Used for a nicer error diagnostic using + TEST_COMPARE_BLOB. */ + unsigned char expected_start[128]; + memcpy (expected_start, start + 1, sizeof (expected_start)); + unsigned char expected_end[128]; + memcpy (expected_end, + start + allocation_size - sizeof (expected_end), + sizeof (expected_end)); + + /* Move the entire allocation forward by one byte. */ + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (8, 0) + /* GCC 8 warns about string function argument overflows. */ + DIAG_IGNORE_NEEDS_COMMENT (8, "-Warray-bounds"); + DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-overflow"); +#endif + memmove (start, start + 1, allocation_size - 1); + DIAG_POP_NEEDS_COMMENT; + + /* Check that the unshared of the memory region have been + shifted as expected. The TEST_COMPARE_BLOB checks are + redundant, but produce nicer diagnostics. */ + asm volatile ("" ::: "memory"); + TEST_COMPARE_BLOB (expected_start, sizeof (expected_start), + start, sizeof (expected_start)); + TEST_COMPARE_BLOB (expected_end, sizeof (expected_end), + start + allocation_size - sizeof (expected_end) - 1, + sizeof (expected_end)); + for (size_t i = 0; i < unshared_size - 1; ++i) + TEST_COMPARE (start[i], expected_value (i + 1)); + /* The gap between the checked start and end area of the mapping + has shared mappings at unspecified boundaries, so do not + check the expected values in the middle. */ + for (size_t i = allocation_size - unshared_size; i < allocation_size - 1; + ++i) + TEST_COMPARE (start[i], expected_value (i + 1)); + + support_blob_repeat_free (&repeat); + } + + return 0; +} + +#include