1 /* Test for signed comparision bug in memmove (bug 25620).
2 Copyright (C) 2020-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
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
26 #include <array_length.h>
27 #include <libc-diag.h>
30 #include <support/blob_repeat.h>
31 #include <support/check.h>
32 #include <support/xunistd.h>
37 #define TEST_NAME "memmove"
38 #include "test-string.h"
39 #include <support/test-driver.h>
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. */
45 enum { unshared_size
= (size_t) 4U << 20 };
47 /* The allocation is 2 GiB plus 8 MiB. This should work with all page
48 sizes that occur in practice. */
49 enum { allocation_size
= ((size_t) 2U << 30) + 2 * unshared_size
};
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
)
56 uint32_t randomized
= 0x9e3779b9 * index
; /* Based on golden ratio. */
57 return randomized
>> 25; /* Result is in the range [0, 127]. */
60 /* Used to count mismatches up to a limit, to avoid creating a huge
62 static unsigned int mismatch_count
;
64 /* Check ACTUAL == EXPECTED. Use INDEX for error reporting. Exit the
65 process after too many errors. */
67 check_one_index (size_t index
, unsigned char actual
, unsigned char expected
)
69 if (actual
!= expected
)
71 printf ("error: mismatch at index %zu: expected 0x%02x, got 0x%02x\n",
72 index
, actual
, expected
);
74 if (mismatch_count
> 200)
75 FAIL_EXIT1 ("bailing out due to too many errors");
84 FOR_EACH_IMPL (impl
, 0)
86 printf ("info: testing %s\n", impl
->name
);
88 /* Check that the allocation sizes are multiples of the page
90 TEST_COMPARE (allocation_size
% xsysconf (_SC_PAGESIZE
), 0);
91 TEST_COMPARE (unshared_size
% xsysconf (_SC_PAGESIZE
), 0);
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
;
98 struct support_blob_repeat repeat
99 = support_blob_repeat_allocate_shared (repeating_pattern
,
100 sizeof (repeating_pattern
),
102 / sizeof (repeating_pattern
)));
103 if (repeat
.start
== NULL
)
104 FAIL_UNSUPPORTED ("repeated blob allocation failed: %m");
105 TEST_COMPARE (repeat
.size
, allocation_size
);
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);
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
;
121 start
[i
] = expected_value (i
);
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
;
129 TEST_COMPARE (start
[i
], expected_value (i
));
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
));
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");
147 memmove (start
, start
+ 1, allocation_size
- 1);
148 DIAG_POP_NEEDS_COMMENT
;
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
)
160 check_one_index (i
, start
[i
], expected_value (i
+ 1));
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;
166 check_one_index (i
, start
[i
], expected_value (i
+ 1));
168 support_blob_repeat_free (&repeat
);
174 #include <support/test-driver.c>