Fix: sessiond: ODR violation results in memory corruption
[lttng-tools.git] / tests / unit / test_utils_expand_path.cpp
1 /*
2 * Copyright (C) 2013 Raphaƫl Beamonte <raphael.beamonte@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #include <string.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <limits.h>
12
13 #include <sys/stat.h>
14 #include <sys/types.h>
15
16 #include <tap/tap.h>
17
18 #include <common/utils.hpp>
19 #include <common/path.hpp>
20 #include <common/common.hpp>
21
22 /* For error.h */
23 int lttng_opt_quiet = 1;
24 int lttng_opt_verbose = 3;
25 int lttng_opt_mi;
26
27 namespace {
28 struct valid_test_input {
29 const char *input;
30 const char *relative_part;
31 const char *absolute_part;
32 };
33
34 struct tree_symlink {
35 const char *orig;
36 const char *dest;
37 };
38
39 struct symlink_test_input {
40 const char *input;
41 const char *expected_result;
42 };
43
44 /* Valid test cases */
45 struct valid_test_input valid_tests_inputs[] = {
46 { "/a/b/c/d/e", "", "/a/b/c/d/e" },
47 { "/a//b//c/d/e", "", "/a/b/c/d/e" },
48 { "./a/b/c/d/e", ".", "/a/b/c/d/e" },
49 { "../a/b/c/d/../e", "..", "/a/b/c/e" },
50 { ".././a/b/c/d/./e", "..", "/a/b/c/d/e" },
51 { "../../a/b/c/d/e", "../..", "/a/b/c/d/e" },
52 { "./a/b/../c/d/../e", ".", "/a/c/e" },
53 { "../a/b/../../c/./d/./e", "..", "/c/d/e" },
54 { "../../a/b/../c/d/../../e", "../..", "/a/e" },
55 { "./a/b/c/d/../../../../e", ".", "/e" },
56 { ".././a/b/c/d/./e", "..", "/a/b/c/d/e" },
57 { "a/", ".", "/a/" },
58 { "a", ".", "/a" },
59 { "../../", "../..", "/" },
60 { "../..", "../..", "" },
61 { "../", "..", "/" },
62 { "..", "..", "" },
63 { "./", ".", "/" },
64 { ".", ".", "" },
65 { "/../a/b/c/d/e", "", "/a/b/c/d/e" },
66 { "/a/b/c/d/../../../../../e", "", "/e" },
67 { "/..", "", "/" },
68 { "/a/..", "", "/" },
69 };
70 char **valid_tests_expected_results;
71 const int num_valid_tests =
72 sizeof(valid_tests_inputs) / sizeof(valid_tests_inputs[0]);
73
74 /* Symlinks test cases */
75 char tree_origin[] = "/tmp/test_utils_expand_path.XXXXXX";
76
77 const char * const tree_dirs[] = {
78 "a",
79 "a/b",
80 "a/b/c",
81 "a/e",
82 };
83 const int num_tree_dirs =
84 sizeof(tree_dirs) / sizeof(tree_dirs[0]);
85
86 struct tree_symlink tree_symlinks[] = {
87 { "a/d", "b/c/" },
88 { "a/g", "d/" },
89 { "a/b/f", "../e/" },
90 { "a/b/h", "../g/" },
91 { "a/b/k", "c/g/" },
92 { "a/b/c/g", "../../../" },
93 };
94 const int num_tree_symlinks =
95 sizeof(tree_symlinks) / sizeof(tree_symlinks[0]);
96
97 static struct symlink_test_input symlink_tests_inputs[] = {
98 { "a/g/../l/.", "a/b/l" },
99 { "a/g/../l/./", "a/b/l/" },
100 { "a/g/../l/..", "a/b" },
101 { "a/g/../l/../", "a/b/" },
102 { "a/b/h/g/", "" },
103 };
104 const int num_symlink_tests =
105 sizeof(symlink_tests_inputs) / sizeof(symlink_tests_inputs[0]);
106
107 /* Invalid test cases */
108 char *invalid_tests_inputs[] = {
109 NULL,
110 };
111 const int num_invalid_tests =
112 sizeof(invalid_tests_inputs) / sizeof(invalid_tests_inputs[0]);
113 } /* namespace */
114
115 #define PRINT_ERR(fmt, args...) \
116 fprintf(stderr, "test_utils_expand_path: error: " fmt "\n", ## args)
117
118 static int prepare_valid_results(void)
119 {
120 int i;
121 char *relative, *cur_path = NULL, *prev_path = NULL,
122 *pprev_path = NULL, *empty = NULL;
123 int ret = 0;
124
125 /* Prepare the relative paths */
126 cur_path = realpath(".", NULL);
127 prev_path = realpath("..", NULL);
128 pprev_path = realpath("../..", NULL);
129 empty = strdup("");
130 if (!cur_path || !prev_path || !pprev_path || !empty) {
131 PRINT_ERR("strdup out of memory");
132 ret = -1;
133 goto end;
134 }
135
136 /* allocate memory for the expected results */
137 valid_tests_expected_results = calloc<char *>(num_valid_tests);
138 if (!valid_tests_expected_results) {
139 PRINT_ERR("out of memory");
140 ret = -1;
141 goto end;
142 }
143 for (i = 0; i < num_valid_tests; i++) {
144 valid_tests_expected_results[i] = calloc<char>(PATH_MAX);
145 if (valid_tests_expected_results[i] == NULL) {
146 PRINT_ERR("malloc expected results");
147 ret = -1;
148 goto end;
149 }
150
151 if (strcmp(valid_tests_inputs[i].relative_part, ".") == 0) {
152 relative = cur_path;
153 } else if (strcmp(valid_tests_inputs[i].relative_part, "..") == 0) {
154 relative = prev_path;
155 } else if (strcmp(valid_tests_inputs[i].relative_part, "../..") == 0) {
156 relative = pprev_path;
157 } else {
158 relative = empty;
159 }
160
161 snprintf(valid_tests_expected_results[i], PATH_MAX,
162 "%s%s", relative, valid_tests_inputs[i].absolute_part);
163 }
164
165 end:
166 free(cur_path);
167 free(prev_path);
168 free(pprev_path);
169 free(empty);
170
171 return ret;
172 }
173
174 static int free_valid_results(void)
175 {
176 int i;
177
178 for (i = 0; i < num_valid_tests; i++) {
179 free(valid_tests_expected_results[i]);
180 }
181
182 free(valid_tests_expected_results);
183
184 return 0;
185 }
186
187 static int prepare_symlink_tree(void)
188 {
189 int i;
190 char tmppath[PATH_MAX] = {};
191
192 /* Create the temporary directory */
193 if (mkdtemp(tree_origin) == NULL) {
194 PRINT_ERR("failed to mkdtemp");
195 goto error;
196 }
197
198 /* Create the directories of the test tree */
199 for (i = 0; i < num_tree_dirs; i++) {
200 snprintf(tmppath, sizeof(tmppath), "%s/%s", tree_origin,
201 tree_dirs[i]);
202
203 if (mkdir(tmppath, 0755) != 0) {
204 PRINT_ERR("mkdir failed with path \"%s\"", tmppath);
205 goto error;
206 }
207 }
208
209 /* Create the symlinks of the test tree */
210 for (i = 0; i < num_tree_symlinks; i++) {
211 snprintf(tmppath, sizeof(tmppath), "%s/%s",
212 tree_origin, tree_symlinks[i].orig);
213
214 if (symlink(tree_symlinks[i].dest, tmppath) != 0) {
215 PRINT_ERR("failed to symlink \"%s\" to \"%s\"", tmppath,
216 tree_symlinks[i].dest);
217 goto error;
218 }
219 }
220
221 return 0;
222
223 error:
224 return 1;
225 }
226
227 static int free_symlink_tree(void)
228 {
229 int i;
230 char tmppath[PATH_MAX];
231
232 /* Remove the symlinks from the test tree */
233 for (i = num_tree_symlinks - 1; i > -1; i--) {
234 snprintf(tmppath, PATH_MAX, "%s/%s",
235 tree_origin, tree_symlinks[i].orig);
236
237 if (unlink(tmppath) != 0) {
238 PRINT_ERR("failed to unlink \"%s\"", tmppath);
239 goto error;
240 }
241 }
242
243 /* Remove the directories from the test tree */
244 for (i = num_tree_dirs - 1; i > -1; i--) {
245 snprintf(tmppath, PATH_MAX, "%s/%s", tree_origin, tree_dirs[i]);
246
247 if (rmdir(tmppath) != 0) {
248 PRINT_ERR("failed to rmdir \"%s\"", tmppath);
249 goto error;
250 }
251 }
252
253 /* Remove the temporary directory */
254 if (rmdir(tree_origin) != 0) {
255 PRINT_ERR("failed to rmdir \"%s\"", tree_origin);
256 goto error;
257 }
258
259 return 0;
260
261 error:
262 return 1;
263 }
264
265 static void test_utils_expand_path(void)
266 {
267 char *result;
268 char name[100], tmppath[PATH_MAX], real_tree_origin[PATH_MAX];
269 int i, treelen;
270
271 /* Test valid cases */
272 for (i = 0; i < num_valid_tests; i++) {
273 sprintf(name, "valid test case: %s", valid_tests_inputs[i].input);
274
275 result = utils_expand_path(valid_tests_inputs[i].input);
276 ok(result != NULL &&
277 strcmp(result, valid_tests_expected_results[i]) == 0, "%s", name);
278
279 free(result);
280 }
281
282 /*
283 * Get the realpath for the tree_origin since it can itself be a
284 * symlink.
285 */
286 result = realpath(tree_origin, real_tree_origin);
287 if (!result) {
288 fail("realpath failed.");
289 return;
290 }
291
292 /* Test symlink tree cases */
293 treelen = strlen(real_tree_origin) + 1;
294 for (i = 0; i < num_symlink_tests; i++) {
295 int ret;
296
297 sprintf(name, "symlink tree test case: [tmppath/]%s",
298 symlink_tests_inputs[i].input);
299
300 ret = snprintf(tmppath, PATH_MAX, "%s/%s",
301 real_tree_origin,
302 symlink_tests_inputs[i].input);
303 if (ret == -1 || ret >= PATH_MAX) {
304 PRINT_ERR("truncation occurred while concatenating paths \"%s\" and \"%s\"",
305 real_tree_origin,
306 symlink_tests_inputs[i].input);
307 fail("%s", name);
308 continue;
309 }
310 result = utils_expand_path(tmppath);
311 ok(result != NULL && strcmp(result + treelen,
312 symlink_tests_inputs[i].expected_result) == 0, "%s", name);
313
314 free(result);
315 }
316
317 /* Test invalid cases */
318 for (i = 0; i < num_invalid_tests; i++) {
319 const char *test_input = invalid_tests_inputs[i];
320
321 sprintf(name, "invalid test case: %s", test_input ?
322 test_input : "NULL");
323
324 result = utils_expand_path(test_input);
325 if (result != NULL) {
326 free(result);
327 }
328 ok(result == NULL, "%s", name);
329 }
330 }
331
332 int main(void)
333 {
334 if (prepare_symlink_tree() != 0) {
335 goto error_mkdir;
336 }
337
338 if (prepare_valid_results() != 0) {
339 goto error_malloc;
340 }
341
342 plan_tests(num_valid_tests + num_invalid_tests + num_symlink_tests);
343
344 diag("utils_expand_path tests");
345
346 test_utils_expand_path();
347
348 free_valid_results();
349 free_symlink_tree();
350
351 return exit_status();
352
353 error_malloc:
354 free_valid_results();
355
356 error_mkdir:
357 free_symlink_tree();
358
359 return 1;
360 }
This page took 0.037154 seconds and 5 git commands to generate.