1 | /* Test driver for malloc interposition tests. |
2 | Copyright (C) 2016-2022 Free Software Foundation, Inc. |
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 License as |
7 | published by the Free Software Foundation; either version 2.1 of the |
8 | 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; see the file COPYING.LIB. If |
17 | not, see <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <stdio.h> |
20 | #include <stdlib.h> |
21 | #include <string.h> |
22 | #include <unistd.h> |
23 | |
24 | #if INTERPOSE_THREADS |
25 | #include <pthread.h> |
26 | #endif |
27 | |
28 | static int do_test (void); |
29 | #define TEST_FUNCTION do_test () |
30 | #include "../test-skeleton.c" |
31 | |
32 | /* Fills BUFFER with a test string. */ |
33 | static void |
34 | line_string (int number, char *buffer, size_t length) |
35 | { |
36 | for (size_t i = 0; i < length - 2; ++i) |
37 | buffer[i] = 'A' + ((number + i) % 26); |
38 | buffer[length - 2] = '\n'; |
39 | buffer[length - 1] = '\0'; |
40 | } |
41 | |
42 | /* Perform the tests. */ |
43 | static void * |
44 | run_tests (void *closure) |
45 | { |
46 | char *temp_file_path; |
47 | int fd = create_temp_file (base: "tst-malloc-interpose" , filename: &temp_file_path); |
48 | if (fd < 0) |
49 | _exit (1); |
50 | |
51 | /* Line lengths excluding the line terminator. */ |
52 | static const int line_lengths[] = { 0, 45, 80, 2, 8201, 0, 17, -1 }; |
53 | |
54 | /* Fill the test file with data. */ |
55 | { |
56 | FILE *fp = fdopen (fd, "w" ); |
57 | for (int lineno = 0; line_lengths[lineno] >= 0; ++lineno) |
58 | { |
59 | char buffer[line_lengths[lineno] + 2]; |
60 | line_string (number: lineno, buffer, length: sizeof (buffer)); |
61 | fprintf (fp, "%s" , buffer); |
62 | } |
63 | |
64 | if (ferror (stream: fp)) |
65 | { |
66 | printf (format: "error: fprintf: %m\n" ); |
67 | _exit (1); |
68 | } |
69 | if (fclose (fp) != 0) |
70 | { |
71 | printf (format: "error: fclose: %m\n" ); |
72 | _exit (1); |
73 | } |
74 | } |
75 | |
76 | /* Read the test file. This tests libc-internal allocation with |
77 | realloc. */ |
78 | { |
79 | FILE *fp = fopen (temp_file_path, "r" ); |
80 | |
81 | char *actual = NULL; |
82 | size_t actual_size = 0; |
83 | for (int lineno = 0; ; ++lineno) |
84 | { |
85 | errno = 0; |
86 | ssize_t result = getline (lineptr: &actual, n: &actual_size, stream: fp); |
87 | if (result == 0) |
88 | { |
89 | printf (format: "error: invalid return value 0 from getline\n" ); |
90 | _exit (1); |
91 | } |
92 | if (result < 0 && errno != 0) |
93 | { |
94 | printf (format: "error: getline: %m\n" ); |
95 | _exit (1); |
96 | } |
97 | if (result < 0 && line_lengths[lineno] >= 0) |
98 | { |
99 | printf (format: "error: unexpected end of file after line %d\n" , lineno); |
100 | _exit (1); |
101 | } |
102 | if (result > 0 && line_lengths[lineno] < 0) |
103 | { |
104 | printf (format: "error: no end of file after line %d\n" , lineno); |
105 | _exit (1); |
106 | } |
107 | if (result == -1 && line_lengths[lineno] == -1) |
108 | /* End of file reached as expected. */ |
109 | break; |
110 | |
111 | if (result != line_lengths[lineno] + 1) |
112 | { |
113 | printf (format: "error: line length mismatch: expected %d, got %zd\n" , |
114 | line_lengths[lineno], result); |
115 | _exit (1); |
116 | } |
117 | |
118 | char expected[line_lengths[lineno] + 2]; |
119 | line_string (number: lineno, buffer: expected, length: sizeof (expected)); |
120 | if (strcmp (actual, expected) != 0) |
121 | { |
122 | printf (format: "error: line mismatch\n" ); |
123 | printf (format: "error: expected: [[%s]]\n" , expected); |
124 | printf (format: "error: actual: [[%s]]\n" , actual); |
125 | _exit (1); |
126 | } |
127 | } |
128 | |
129 | if (fclose (fp) != 0) |
130 | { |
131 | printf (format: "error: fclose (after reading): %m\n" ); |
132 | _exit (1); |
133 | } |
134 | } |
135 | |
136 | free (ptr: temp_file_path); |
137 | |
138 | /* Make sure that fork is working. */ |
139 | pid_t pid = fork (); |
140 | if (pid == -1) |
141 | { |
142 | printf (format: "error: fork: %m\n" ); |
143 | _exit (1); |
144 | } |
145 | enum { exit_code = 55 }; |
146 | if (pid == 0) |
147 | _exit (exit_code); |
148 | int status; |
149 | int ret = waitpid (pid: pid, stat_loc: &status, options: 0); |
150 | if (ret < 0) |
151 | { |
152 | printf (format: "error: waitpid: %m\n" ); |
153 | _exit (1); |
154 | } |
155 | if (!WIFEXITED (status) || WEXITSTATUS (status) != exit_code) |
156 | { |
157 | printf (format: "error: unexpected exit status from child process: %d\n" , |
158 | status); |
159 | _exit (1); |
160 | } |
161 | |
162 | return NULL; |
163 | } |
164 | |
165 | /* This is used to detect if malloc has not been successfully |
166 | interposed. The interposed malloc does not use brk/sbrk. */ |
167 | static void *initial_brk; |
168 | __attribute__ ((constructor)) |
169 | static void |
170 | set_initial_brk (void) |
171 | { |
172 | initial_brk = sbrk (delta: 0); |
173 | } |
174 | |
175 | /* Terminate the process if the break value has been changed. */ |
176 | __attribute__ ((destructor)) |
177 | static void |
178 | check_brk (void) |
179 | { |
180 | void *current = sbrk (delta: 0); |
181 | if (current != initial_brk) |
182 | { |
183 | printf (format: "error: brk changed from %p to %p; no interposition?\n" , |
184 | initial_brk, current); |
185 | _exit (1); |
186 | } |
187 | } |
188 | |
189 | static int |
190 | do_test (void) |
191 | { |
192 | check_brk (); |
193 | |
194 | #if INTERPOSE_THREADS |
195 | pthread_t thr = xpthread_create (NULL, run_tests, NULL); |
196 | xpthread_join (thr); |
197 | #else |
198 | run_tests (NULL); |
199 | #endif |
200 | |
201 | check_brk (); |
202 | |
203 | return 0; |
204 | } |
205 | |