1 /* Test reporting of Safe-Linking caught errors.
2 Copyright (C) 2020-2024 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/>. */
26 #include <support/capture_subprocess.h>
27 #include <support/check.h>
29 /* Run CALLBACK and check that the data on standard error equals
32 check (const char *test
, void (*callback
) (void *),
36 int success
= 0; /* 0 == fail, 1 == other check 2 == safe linking */
37 /* There is a chance of 1/16 that a corrupted pointer will be aligned.
38 Try multiple times so that statistical failure will be improbable. */
39 for (i
= 0; i
< 16; ++i
)
41 rand_mask
= rand () & 0xFF;
42 struct support_capture_subprocess result
43 = support_capture_subprocess (callback
, &rand_mask
);
44 printf ("%s\n", result
.out
.buffer
);
45 /* Did not crash, could happen. Try again. */
46 if (strlen (result
.err
.buffer
) == 0)
48 /* Crashed, it may either be safe linking or some other check. If it's
49 not safe linking then try again. */
50 if (strcmp (result
.err
.buffer
, expected
) != 0)
52 printf ("test %s failed with a different error\n"
55 test
, expected
, result
.err
.buffer
);
59 TEST_VERIFY (WIFSIGNALED (result
.status
));
60 if (WIFSIGNALED (result
.status
))
61 TEST_VERIFY (WTERMSIG (result
.status
) == SIGABRT
);
62 support_capture_subprocess_free (&result
);
66 /* The test fails only if the corruption was not caught by any of the malloc
67 mechanisms in all those iterations. This has a lower than 1 in 2^64
68 chance of a false positive. */
69 TEST_VERIFY (success
);
72 /* Implementation details must be kept in sync with malloc. */
73 #define TCACHE_FILL_COUNT 7
74 #define TCACHE_ALLOC_SIZE 0x20
75 #define MALLOC_CONSOLIDATE_SIZE 256*1024
77 /* Try corrupting the tcache list. */
79 test_tcache (void *closure
)
81 int mask
= ((int *)closure
)[0];
82 size_t size
= TCACHE_ALLOC_SIZE
;
84 printf ("++ tcache ++\n");
86 /* Populate the tcache list. */
87 void * volatile a
= malloc (size
);
88 void * volatile b
= malloc (size
);
89 void * volatile c
= malloc (size
);
90 printf ("a=%p, b=%p, c=%p\n", a
, b
, c
);
95 /* Corrupt the pointer with a random value, and avoid optimizations. */
96 printf ("Before: c=%p, c[0]=%p\n", c
, ((void **)c
)[0]);
97 memset (c
, mask
& 0xFF, size
);
98 printf ("After: c=%p, c[0]=%p\n", c
, ((void **)c
)[0]);
101 printf ("Allocated: c=%p\n", c
);
102 /* This line will trigger the Safe-Linking check. */
104 printf ("b=%p\n", b
);
107 /* Try corrupting the fastbin list. */
109 test_fastbin (void *closure
)
112 int mask
= ((int *)closure
)[0];
113 size_t size
= TCACHE_ALLOC_SIZE
;
115 printf ("++ fastbin ++\n");
117 /* Take the tcache out of the game. */
118 for (i
= 0; i
< TCACHE_FILL_COUNT
; ++i
)
120 void * volatile p
= calloc (1, size
);
121 printf ("p=%p\n", p
);
125 /* Populate the fastbin list. */
126 void * volatile a
= calloc (1, size
);
127 void * volatile b
= calloc (1, size
);
128 void * volatile c
= calloc (1, size
);
129 printf ("a=%p, b=%p, c=%p\n", a
, b
, c
);
134 /* Corrupt the pointer with a random value, and avoid optimizations. */
135 printf ("Before: c=%p, c[0]=%p\n", c
, ((void **)c
)[0]);
136 memset (c
, mask
& 0xFF, size
);
137 printf ("After: c=%p, c[0]=%p\n", c
, ((void **)c
)[0]);
139 c
= calloc (1, size
);
140 printf ("Allocated: c=%p\n", c
);
141 /* This line will trigger the Safe-Linking check. */
142 b
= calloc (1, size
);
143 printf ("b=%p\n", b
);
146 /* Try corrupting the fastbin list and trigger a consolidate. */
148 test_fastbin_consolidate (void *closure
)
151 int mask
= ((int*)closure
)[0];
152 size_t size
= TCACHE_ALLOC_SIZE
;
154 printf ("++ fastbin consolidate ++\n");
156 /* Take the tcache out of the game. */
157 for (i
= 0; i
< TCACHE_FILL_COUNT
; ++i
)
159 void * volatile p
= calloc (1, size
);
163 /* Populate the fastbin list. */
164 void * volatile a
= calloc (1, size
);
165 void * volatile b
= calloc (1, size
);
166 void * volatile c
= calloc (1, size
);
167 printf ("a=%p, b=%p, c=%p\n", a
, b
, c
);
172 /* Corrupt the pointer with a random value, and avoid optimizations. */
173 printf ("Before: c=%p, c[0]=%p\n", c
, ((void **)c
)[0]);
174 memset (c
, mask
& 0xFF, size
);
175 printf ("After: c=%p, c[0]=%p\n", c
, ((void **)c
)[0]);
177 /* This line will trigger the Safe-Linking check. */
178 b
= malloc (MALLOC_CONSOLIDATE_SIZE
);
179 printf ("b=%p\n", b
);
185 /* Seed the random for the test. */
188 check ("test_tcache", test_tcache
,
189 "malloc(): unaligned tcache chunk detected\n");
190 check ("test_fastbin", test_fastbin
,
191 "malloc(): unaligned fastbin chunk detected 2\n");
192 check ("test_fastbin_consolidate", test_fastbin_consolidate
,
193 "malloc_consolidate(): unaligned fastbin chunk detected\n");
198 #include <support/test-driver.c>