]>
Commit | Line | Data |
---|---|---|
69fda43b | 1 | /* Test that free preserves errno. |
dff8da6b | 2 | Copyright (C) 2020-2024 Free Software Foundation, Inc. |
69fda43b PE |
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 | #include <errno.h> | |
20 | #include <stdlib.h> | |
21 | #include <string.h> | |
22 | #include <unistd.h> | |
23 | #include <fcntl.h> | |
24 | #include <stdint.h> | |
25 | #include <string.h> | |
26 | #include <sys/mman.h> | |
27 | #include <support/check.h> | |
28 | #include <support/support.h> | |
29 | #include <support/temp_file.h> | |
30 | #include <support/xunistd.h> | |
31 | ||
32 | /* The __attribute__ ((weak)) prevents a GCC optimization. Without | |
33 | it, GCC would "know" that errno is unchanged by calling free (ptr), | |
34 | when ptr was the result of a malloc call in the same function. */ | |
35 | int __attribute__ ((weak)) | |
36 | get_errno (void) | |
37 | { | |
38 | return errno; | |
39 | } | |
40 | ||
41 | static int | |
42 | do_test (void) | |
43 | { | |
44 | /* Check that free() preserves errno. */ | |
45 | { | |
46 | errno = 1789; /* Liberté, égalité, fraternité. */ | |
47 | free (NULL); | |
48 | TEST_VERIFY (get_errno () == 1789); | |
49 | } | |
50 | { /* Large memory allocations, to force mmap. */ | |
51 | enum { N = 2 }; | |
52 | void * volatile ptrs[N]; | |
53 | size_t i; | |
54 | for (i = 0; i < N; i++) | |
55 | ptrs[i] = xmalloc (5318153); | |
56 | for (i = 0; i < N; i++) | |
57 | { | |
58 | errno = 1789; | |
59 | free (ptrs[i]); | |
60 | TEST_VERIFY (get_errno () == 1789); | |
61 | } | |
62 | } | |
63 | ||
64 | /* Test a less common code path. | |
65 | When malloc() is based on mmap(), free() can sometimes call munmap(). | |
66 | munmap() usually succeeds, but fails in a particular situation: when | |
67 | - it has to unmap the middle part of a VMA, and | |
68 | - the number of VMAs of a process is limited and the limit is | |
69 | already reached. | |
70 | The latter condition is fulfilled on Linux, when the file | |
71 | /proc/sys/vm/max_map_count exists. For all known Linux versions | |
72 | the default limit is at most 65536. | |
73 | */ | |
74 | #if defined __linux__ | |
75 | if (xopen ("/proc/sys/vm/max_map_count", O_RDONLY, 0) >= 0) | |
76 | { | |
77 | /* Preparations. */ | |
78 | size_t pagesize = getpagesize (); | |
79 | void *firstpage_backup = xmalloc (pagesize); | |
80 | void *lastpage_backup = xmalloc (pagesize); | |
81 | /* Allocate a large memory area, as a bumper, so that the MAP_FIXED | |
82 | allocation later will not overwrite parts of the memory areas | |
83 | allocated to ld.so or libc.so. */ | |
84 | xmmap (NULL, 0x1000000, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1); | |
85 | /* A file descriptor pointing to a regular file. */ | |
86 | int fd = create_temp_file ("tst-free-errno", NULL); | |
87 | if (fd < 0) | |
88 | FAIL_EXIT1 ("cannot create temporary file"); | |
89 | ||
90 | /* Do a large memory allocation. */ | |
91 | size_t big_size = 0x1000000; | |
92 | void * volatile ptr = xmalloc (big_size - 0x100); | |
93 | char *ptr_aligned = (char *) ((uintptr_t) ptr & ~(pagesize - 1)); | |
94 | /* This large memory allocation allocated a memory area | |
95 | from ptr_aligned to ptr_aligned + big_size. | |
96 | Enlarge this memory area by adding a page before and a page | |
97 | after it. */ | |
98 | memcpy (firstpage_backup, ptr_aligned, pagesize); | |
99 | memcpy (lastpage_backup, ptr_aligned + big_size - pagesize, | |
100 | pagesize); | |
101 | xmmap (ptr_aligned - pagesize, pagesize + big_size + pagesize, | |
102 | PROT_READ | PROT_WRITE, | |
103 | MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1); | |
104 | memcpy (ptr_aligned, firstpage_backup, pagesize); | |
105 | memcpy (ptr_aligned + big_size - pagesize, lastpage_backup, | |
106 | pagesize); | |
107 | ||
108 | /* Now add as many mappings as we can. | |
109 | Stop at 65536, in order not to crash the machine (in case the | |
110 | limit has been increased by the system administrator). */ | |
111 | for (int i = 0; i < 65536; i++) | |
112 | if (mmap (NULL, pagesize, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0) | |
113 | == MAP_FAILED) | |
114 | break; | |
115 | /* Now the number of VMAs of this process has hopefully attained | |
116 | its limit. */ | |
117 | ||
118 | errno = 1789; | |
119 | /* This call to free() is supposed to call | |
120 | munmap (ptr_aligned, big_size); | |
121 | which increases the number of VMAs by 1, which is supposed | |
122 | to fail. */ | |
123 | free (ptr); | |
124 | TEST_VERIFY (get_errno () == 1789); | |
125 | } | |
126 | #endif | |
127 | ||
128 | return 0; | |
129 | } | |
130 | ||
131 | #include <support/test-driver.c> |