From patchwork Tue May 5 13:57:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 38916 X-Patchwork-Delegate: carlos@redhat.com Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B8ED9388F40E; Tue, 5 May 2020 13:57:10 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from albireo.enyo.de (albireo.enyo.de [37.24.231.21]) by sourceware.org (Postfix) with ESMTPS id 3D233388F060 for ; Tue, 5 May 2020 13:57:06 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 3D233388F060 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=deneb.enyo.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=fw@deneb.enyo.de Received: from [172.17.203.2] (helo=deneb.enyo.de) by albireo.enyo.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) id 1jVy4H-0000ud-7a for libc-alpha@sourceware.org; Tue, 05 May 2020 13:57:05 +0000 Received: from fw by deneb.enyo.de with local (Exim 4.92) (envelope-from ) id 1jVy4H-0000DX-5d for libc-alpha@sourceware.org; Tue, 05 May 2020 15:57:05 +0200 From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH] string: Add string/tst-memmove-overflow, a test case for bug 25620 Date: Tue, 05 May 2020 15:57:05 +0200 Message-ID: <87bln21o3y.fsf@mid.deneb.enyo.de> MIME-Version: 1.0 X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_NUMSUBJECT, KAM_SHORT, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" ----- Changes to the previous version: * Use support_blob_repeat_allocate_shared to preserve sharing (no copy-on-write). * Use MAP_FIXED for the head and tail, to change the existing mapping. string/Makefile | 2 +- string/tst-memmove-overflow.c | 155 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 1 deletion(-) Reviewed-by: Carlos O'Donell Tested-by: Carlos O'Donell 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