]>
Commit | Line | Data |
---|---|---|
7f0d9e61 | 1 | /* Test for signed comparison bug in memmove (bug 25620). |
6d7e8eda | 2 | Copyright (C) 2020-2023 Free Software Foundation, Inc. |
eec0f421 FW |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, see | |
17 | <https://www.gnu.org/licenses/>. */ | |
18 | ||
19 | /* This test shifts a memory region which is a bit larger than 2 GiB | |
20 | by one byte. In order to make it more likely that the memory | |
21 | allocation succeeds on 32-bit systems, most of the allocation | |
22 | consists of shared pages. Only a portion at the start and end of | |
23 | the allocation are unshared, and contain a specific non-repeating | |
24 | bit pattern. */ | |
25 | ||
26 | #include <array_length.h> | |
27 | #include <libc-diag.h> | |
28 | #include <stdint.h> | |
29 | #include <string.h> | |
30 | #include <support/blob_repeat.h> | |
31 | #include <support/check.h> | |
32 | #include <support/xunistd.h> | |
33 | #include <sys/mman.h> | |
34 | #include <unistd.h> | |
35 | ||
36 | #define TEST_MAIN | |
37 | #define TEST_NAME "memmove" | |
38 | #include "test-string.h" | |
39 | #include <support/test-driver.h> | |
40 | ||
41 | IMPL (memmove, 1) | |
42 | ||
43 | /* Size of the part of the allocation which is not shared, at the | |
44 | start and the end of the overall allocation. 4 MiB. */ | |
a4a35192 | 45 | enum { unshared_size = (size_t) 4U << 20 }; |
eec0f421 FW |
46 | |
47 | /* The allocation is 2 GiB plus 8 MiB. This should work with all page | |
48 | sizes that occur in practice. */ | |
a4a35192 | 49 | enum { allocation_size = ((size_t) 2U << 30) + 2 * unshared_size }; |
eec0f421 FW |
50 | |
51 | /* Compute the expected byte at the given index. This is used to | |
52 | produce a non-repeating pattern. */ | |
53 | static inline unsigned char | |
54 | expected_value (size_t index) | |
55 | { | |
56 | uint32_t randomized = 0x9e3779b9 * index; /* Based on golden ratio. */ | |
57 | return randomized >> 25; /* Result is in the range [0, 127]. */ | |
58 | } | |
59 | ||
eca1b233 FW |
60 | /* Used to count mismatches up to a limit, to avoid creating a huge |
61 | test output file. */ | |
62 | static unsigned int mismatch_count; | |
63 | ||
64 | /* Check ACTUAL == EXPECTED. Use INDEX for error reporting. Exit the | |
65 | process after too many errors. */ | |
66 | static inline void | |
67 | check_one_index (size_t index, unsigned char actual, unsigned char expected) | |
68 | { | |
69 | if (actual != expected) | |
70 | { | |
71 | printf ("error: mismatch at index %zu: expected 0x%02x, got 0x%02x\n", | |
72 | index, actual, expected); | |
73 | ++mismatch_count; | |
74 | if (mismatch_count > 200) | |
75 | FAIL_EXIT1 ("bailing out due to too many errors"); | |
76 | } | |
77 | } | |
78 | ||
eec0f421 FW |
79 | static int |
80 | test_main (void) | |
81 | { | |
82 | test_init (); | |
83 | ||
84 | FOR_EACH_IMPL (impl, 0) | |
85 | { | |
86 | printf ("info: testing %s\n", impl->name); | |
87 | ||
88 | /* Check that the allocation sizes are multiples of the page | |
89 | size. */ | |
90 | TEST_COMPARE (allocation_size % xsysconf (_SC_PAGESIZE), 0); | |
91 | TEST_COMPARE (unshared_size % xsysconf (_SC_PAGESIZE), 0); | |
92 | ||
93 | /* The repeating pattern has the MSB set in all bytes. */ | |
94 | unsigned char repeating_pattern[128]; | |
95 | for (unsigned int i = 0; i < array_length (repeating_pattern); ++i) | |
96 | repeating_pattern[i] = 0x80 | i; | |
97 | ||
98 | struct support_blob_repeat repeat | |
99 | = support_blob_repeat_allocate_shared (repeating_pattern, | |
100 | sizeof (repeating_pattern), | |
101 | (allocation_size | |
102 | / sizeof (repeating_pattern))); | |
103 | if (repeat.start == NULL) | |
104 | FAIL_UNSUPPORTED ("repeated blob allocation failed: %m"); | |
105 | TEST_COMPARE (repeat.size, allocation_size); | |
106 | ||
107 | /* Unshared the start and the end of the allocation. */ | |
108 | unsigned char *start = repeat.start; | |
109 | xmmap (start, unshared_size, | |
110 | PROT_READ | PROT_WRITE, | |
111 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1); | |
112 | xmmap (start + allocation_size - unshared_size, unshared_size, | |
113 | PROT_READ | PROT_WRITE, | |
114 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1); | |
115 | ||
116 | /* Initialize the non-repeating pattern. */ | |
117 | for (size_t i = 0; i < unshared_size; ++i) | |
118 | start[i] = expected_value (i); | |
119 | for (size_t i = allocation_size - unshared_size; i < allocation_size; | |
120 | ++i) | |
121 | start[i] = expected_value (i); | |
122 | ||
123 | /* Make sure that there was really no sharing. */ | |
124 | asm volatile ("" ::: "memory"); | |
125 | for (size_t i = 0; i < unshared_size; ++i) | |
126 | TEST_COMPARE (start[i], expected_value (i)); | |
127 | for (size_t i = allocation_size - unshared_size; i < allocation_size; | |
128 | ++i) | |
129 | TEST_COMPARE (start[i], expected_value (i)); | |
130 | ||
131 | /* Used for a nicer error diagnostic using | |
132 | TEST_COMPARE_BLOB. */ | |
133 | unsigned char expected_start[128]; | |
134 | memcpy (expected_start, start + 1, sizeof (expected_start)); | |
135 | unsigned char expected_end[128]; | |
136 | memcpy (expected_end, | |
137 | start + allocation_size - sizeof (expected_end), | |
138 | sizeof (expected_end)); | |
139 | ||
140 | /* Move the entire allocation forward by one byte. */ | |
141 | DIAG_PUSH_NEEDS_COMMENT; | |
142 | #if __GNUC_PREREQ (8, 0) | |
143 | /* GCC 8 warns about string function argument overflows. */ | |
144 | DIAG_IGNORE_NEEDS_COMMENT (8, "-Warray-bounds"); | |
145 | DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-overflow"); | |
146 | #endif | |
147 | memmove (start, start + 1, allocation_size - 1); | |
148 | DIAG_POP_NEEDS_COMMENT; | |
149 | ||
150 | /* Check that the unshared of the memory region have been | |
151 | shifted as expected. The TEST_COMPARE_BLOB checks are | |
152 | redundant, but produce nicer diagnostics. */ | |
153 | asm volatile ("" ::: "memory"); | |
154 | TEST_COMPARE_BLOB (expected_start, sizeof (expected_start), | |
155 | start, sizeof (expected_start)); | |
156 | TEST_COMPARE_BLOB (expected_end, sizeof (expected_end), | |
157 | start + allocation_size - sizeof (expected_end) - 1, | |
158 | sizeof (expected_end)); | |
159 | for (size_t i = 0; i < unshared_size - 1; ++i) | |
eca1b233 | 160 | check_one_index (i, start[i], expected_value (i + 1)); |
eec0f421 FW |
161 | /* The gap between the checked start and end area of the mapping |
162 | has shared mappings at unspecified boundaries, so do not | |
163 | check the expected values in the middle. */ | |
164 | for (size_t i = allocation_size - unshared_size; i < allocation_size - 1; | |
165 | ++i) | |
eca1b233 | 166 | check_one_index (i, start[i], expected_value (i + 1)); |
eec0f421 FW |
167 | |
168 | support_blob_repeat_free (&repeat); | |
169 | } | |
170 | ||
171 | return 0; | |
172 | } | |
173 | ||
174 | #include <support/test-driver.c> |