From 31b0248b05e433c0589fe2736e61852515427d9a Mon Sep 17 00:00:00 2001 From: Jan-Marek Glogowski Date: Sun, 26 Dec 2021 08:32:58 +0100 Subject: [PATCH] [ELF] Fix '?' for globbing + version scripts For globbing, '?' matches a single character, so must be replaced with '.'. As a result, don't skip the later regex matching for version scripts, if the pattern contains either '*' or '?'. Signed-off-by: Jan-Marek Glogowski --- elf/main.cc | 5 +++- elf/passes.cc | 3 ++- test/elf/version-script8.sh | 46 +++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100755 test/elf/version-script8.sh diff --git a/elf/main.cc b/elf/main.cc index 1081df472c..00e573f30c 100644 --- a/elf/main.cc +++ b/elf/main.cc @@ -22,12 +22,15 @@ std::string glob_to_regex(std::string_view pattern) { switch (c) { case '.': case '[': case ']': case '^': case '$': case '\\': case '(': case ')': - case '+': case '?': case '|': + case '+': case '|': ss << "\\" << c; break; case '*': ss << ".*"; break; + case '?': + ss << "."; + break; default: ss << c; break; diff --git a/elf/passes.cc b/elf/passes.cc index 2b4aa9cbc1..4f8710534e 100644 --- a/elf/passes.cc +++ b/elf/passes.cc @@ -609,8 +609,9 @@ void apply_version_script(Context &ctx) { for (VersionPattern &elem : ctx.arg.version_patterns) { std::vector vec; + std::regex re_glob("[*?]", std::regex_constants::optimize | std::regex_constants::nosubs); for (std::string_view pat : elem.patterns) { - if (pat.find('*') == pat.npos) { + if (!std::regex_search(pat.begin(), pat.end(), re_glob)) { Symbol *sym = intern(ctx, pat); if (sym->file && !sym->file->is_dso) sym->ver_idx = elem.ver_idx; diff --git a/test/elf/version-script8.sh b/test/elf/version-script8.sh new file mode 100755 index 0000000000..cc6d99db6a --- /dev/null +++ b/test/elf/version-script8.sh @@ -0,0 +1,46 @@ +#!/bin/bash +export LANG= +set -e +cd $(dirname $0) +mold=`pwd`/../../mold +echo -n "Testing $(basename -s .sh $0) ... " +t=$(pwd)/../../out/test/elf/$(basename -s .sh $0) +mkdir -p $t + +cat < $t/a.ver +ver1 { + global: ?oo; + local: *; +}; + +ver2 { + global: b?r; +}; +EOF + +cat < $t/log +fgrep -q 'foo@@ver1' $t/log +fgrep -q 'bar@@ver2' $t/log +! fgrep -q 'baz' $t/log || false + +echo OK