From f8029ed6d3dd444ee2608146118f2189cf9ef0d8 Mon Sep 17 00:00:00 2001 From: marxin Date: Mon, 14 Aug 2017 13:56:32 +0200 Subject: [PATCH] Fix file find utils and add unit tests (PR driver/81829). gcc/ChangeLog: 2017-08-14 Martin Liska PR driver/81829 * file-find.c (do_add_prefix): Always append DIR_SEPARATOR at the end of a prefix. (remove_prefix): Properly remove elements and accept also path without a trailing DIR_SEPARATOR. (purge): New function. (file_find_verify_prefix_creation): Likewise. (file_find_verify_prefix_add): Likewise. (file_find_verify_prefix_removal): Likewise. (file_find_c_tests): Likewise. * selftest-run-tests.c (selftest::run_tests): Add new file_find_c_tests. * selftest.h (file_find_c_tests): Likewise. --- gcc/file-find.c | 182 ++++++++++++++++++++++++++++++++++++++++++----- gcc/gcc-ar.c | 19 +++-- gcc/selftest-run-tests.c | 1 + gcc/selftest.h | 1 + 4 files changed, 179 insertions(+), 24 deletions(-) Index: b/src/gcc/file-find.c =================================================================== --- a/src/gcc/file-find.c +++ b/src/gcc/file-find.c @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. #include "system.h" #include "filenames.h" #include "file-find.h" +#include "selftest.h" static bool debug = false; @@ -126,11 +127,22 @@ do_add_prefix (struct path_prefix *ppref /* Keep track of the longest prefix. */ len = strlen (prefix); + bool append_separator = !IS_DIR_SEPARATOR (prefix[len - 1]); + if (append_separator) + len++; + if (len > pprefix->max_len) pprefix->max_len = len; pl = XNEW (struct prefix_list); - pl->prefix = xstrdup (prefix); + char *dup = XCNEWVEC (char, len + 1); + memcpy (dup, prefix, append_separator ? len - 1 : len); + if (append_separator) + { + dup[len - 1] = DIR_SEPARATOR; + dup[len] = '\0'; + } + pl->prefix = dup; if (*prev) pl->next = *prev; @@ -212,34 +224,170 @@ prefix_from_string (const char *p, struc void remove_prefix (const char *prefix, struct path_prefix *pprefix) { - struct prefix_list *remove, **prev, **remove_prev = NULL; + char *dup = NULL; int max_len = 0; + size_t len = strlen (prefix); + if (prefix[len - 1] != DIR_SEPARATOR) + { + char *dup = XNEWVEC (char, len + 2); + memcpy (dup, prefix, len); + dup[len] = DIR_SEPARATOR; + dup[len + 1] = '\0'; + prefix = dup; + } if (pprefix->plist) { - prev = &pprefix->plist; - for (struct prefix_list *pl = pprefix->plist; pl->next; pl = pl->next) + prefix_list *prev = NULL; + for (struct prefix_list *pl = pprefix->plist; pl;) { if (strcmp (prefix, pl->prefix) == 0) { - remove = pl; - remove_prev = prev; - continue; + if (prev == NULL) + pprefix->plist = pl->next; + else + prev->next = pl->next; + + prefix_list *remove = pl; + free (remove); + pl = pl->next; } + else + { + prev = pl; - int l = strlen (pl->prefix); - if (l > max_len) - max_len = l; + int l = strlen (pl->prefix); + if (l > max_len) + max_len = l; - prev = &pl; - } - - if (remove_prev) - { - *remove_prev = remove->next; - free (remove); + pl = pl->next; + } } pprefix->max_len = max_len; } + + if (dup) + free (dup); +} + +#if CHECKING_P + +namespace selftest { + +/* Encode '#' and '_' to path and dir separators in order to test portability + of the test-cases. */ + +static char * +purge (const char *input) +{ + char *s = xstrdup (input); + for (char *c = s; *c != '\0'; c++) + switch (*c) + { + case '/': + case ':': + *c = 'a'; /* Poison default string values. */ + break; + case '_': + *c = PATH_SEPARATOR; + break; + case '#': + *c = DIR_SEPARATOR; + break; + default: + break; + } + + return s; +} + +const char *env1 = purge ("#home#user#bin_#home#user#bin_#bin_#usr#bin"); +const char *env2 = purge ("#root_#root_#root"); + +/* Verify creation of prefix. */ + +static void +file_find_verify_prefix_creation (void) +{ + path_prefix prefix; + memset (&prefix, 0, sizeof (prefix)); + prefix_from_string (env1, &prefix); + + ASSERT_EQ (15, prefix.max_len); + + /* All prefixes end with DIR_SEPARATOR. */ + ASSERT_STREQ (purge ("#home#user#bin#"), prefix.plist->prefix); + ASSERT_STREQ (purge ("#home#user#bin#"), prefix.plist->next->prefix); + ASSERT_STREQ (purge ("#bin#"), prefix.plist->next->next->prefix); + ASSERT_STREQ (purge ("#usr#bin#"), prefix.plist->next->next->next->prefix); + ASSERT_EQ (NULL, prefix.plist->next->next->next->next); +} + +/* Verify adding a prefix. */ + +static void +file_find_verify_prefix_add (void) +{ + path_prefix prefix; + memset (&prefix, 0, sizeof (prefix)); + prefix_from_string (env1, &prefix); + + add_prefix (&prefix, purge ("#root")); + ASSERT_STREQ (purge ("#home#user#bin#"), prefix.plist->prefix); + ASSERT_STREQ (purge ("#root#"), + prefix.plist->next->next->next->next->prefix); + + add_prefix_begin (&prefix, purge ("#var")); + ASSERT_STREQ (purge ("#var#"), prefix.plist->prefix); +} + +/* Verify adding a prefix. */ + +static void +file_find_verify_prefix_removal (void) +{ + path_prefix prefix; + memset (&prefix, 0, sizeof (prefix)); + prefix_from_string (env1, &prefix); + + /* All occurences of a prefix should be removed. */ + remove_prefix (purge ("#home#user#bin"), &prefix); + + ASSERT_EQ (9, prefix.max_len); + ASSERT_STREQ (purge ("#bin#"), prefix.plist->prefix); + ASSERT_STREQ (purge ("#usr#bin#"), prefix.plist->next->prefix); + ASSERT_EQ (NULL, prefix.plist->next->next); + + remove_prefix (purge ("#usr#bin#"), &prefix); + ASSERT_EQ (5, prefix.max_len); + ASSERT_STREQ (purge ("#bin#"), prefix.plist->prefix); + ASSERT_EQ (NULL, prefix.plist->next); + + remove_prefix (purge ("#dev#random#"), &prefix); + remove_prefix (purge ("#bi#"), &prefix); + + remove_prefix (purge ("#bin#"), &prefix); + ASSERT_EQ (NULL, prefix.plist); + ASSERT_EQ (0, prefix.max_len); + + memset (&prefix, 0, sizeof (prefix)); + prefix_from_string (env2, &prefix); + ASSERT_EQ (6, prefix.max_len); + + remove_prefix (purge ("#root#"), &prefix); + ASSERT_EQ (NULL, prefix.plist); + ASSERT_EQ (0, prefix.max_len); } + +/* Run all of the selftests within this file. */ + +void file_find_c_tests () +{ + file_find_verify_prefix_creation (); + file_find_verify_prefix_add (); + file_find_verify_prefix_removal (); +} + +} // namespace selftest +#endif /* CHECKING_P */ Index: b/src/gcc/gcc-ar.c =================================================================== --- a/src/gcc/gcc-ar.c +++ b/src/gcc/gcc-ar.c @@ -194,15 +194,20 @@ main (int ac, char **av) #ifdef CROSS_DIRECTORY_STRUCTURE real_exe_name = concat (target_machine, "-", PERSONALITY, NULL); #endif - /* Do not search original location in the same folder. */ - char *exe_folder = lrealpath (av[0]); - exe_folder[strlen (exe_folder) - strlen (lbasename (exe_folder))] = '\0'; - char *location = concat (exe_folder, PERSONALITY, NULL); + char *wrapper_file = lrealpath (av[0]); + exe_name = lrealpath (find_a_file (&path, real_exe_name, X_OK)); - if (access (location, X_OK) == 0) - remove_prefix (exe_folder, &path); + /* If the exe_name points to the wrapper, remove folder of the wrapper + from prefix and try search again. */ + if (strcmp (exe_name, wrapper_file) == 0) + { + char *exe_folder = wrapper_file; + exe_folder[strlen (exe_folder) - strlen (lbasename (exe_folder))] = '\0'; + remove_prefix (exe_folder, &path); + + exe_name = find_a_file (&path, real_exe_name, X_OK); + } - exe_name = find_a_file (&path, real_exe_name, X_OK); if (!exe_name) { fprintf (stderr, "%s: Cannot find binary '%s'\n", av[0], Index: b/src/gcc/selftest-run-tests.c =================================================================== --- a/src/gcc/selftest-run-tests.c +++ b/src/gcc/selftest-run-tests.c @@ -66,6 +66,7 @@ selftest::run_tests () sreal_c_tests (); fibonacci_heap_c_tests (); typed_splay_tree_c_tests (); + file_find_c_tests (); /* Mid-level data structures. */ input_c_tests (); Index: b/src/gcc/selftest.h =================================================================== --- a/src/gcc/selftest.h +++ b/src/gcc/selftest.h @@ -196,6 +196,7 @@ extern void tree_c_tests (); extern void tree_cfg_c_tests (); extern void vec_c_tests (); extern void wide_int_cc_tests (); +extern void file_find_c_tests (); extern int num_passes;