binutils-gdb/gdb/gdb_regex.h
Tom de Vries ff50752029 [gdb/build] Hardcode --with-included-regex
Currently gdb has a configure option:
...
$ ./src/gdb/configure --help
  ...
  --without-included-regex
                          don't use included regex; this is the default on
                          systems with version 2 of the GNU C library (use
                          with caution on other system)
...

The configure option controls config.h macro USE_INCLUDED_REGEX, which is
used in gdb/gdb_regex.h to choose between:
- using regex from libiberty (which is included in the binutils-gdb.git repo,
  hence the 'included' in USE_INCLUDED_REGEX), or
- using regex.h.

In the former case, the symbol regcomp is remapped to a symbol xregcomp, which
is then provided by libiberty.

In the latter case, the symbol regcomp is resolved at runtime, usually binding
to libc.  However, there is no mechanism in place to enforce this.

PR27681 is an example of where that causes problems.  On openSUSE Tumbleweed,
the ncurses package got the --with-pcre2 configure switch enabled, and solved
the resulting dependencies using:
...
 $ cat /usr/lib64/libncursesw.so
 /* GNU ld script */
-INPUT(/lib64/libncursesw.so.6 AS_NEEDED(-ltinfo -ldl))
+INPUT(/lib64/libncursesw.so.6 AS_NEEDED(-ltinfo -ldl -lpcre2-posix -lpcre2-8))
...

This lead to regcomp being bound to libpcre2-posix instead of libc.

This causes problems in several ways:
- by compiling using regex.h, we've already chosen a specific regex_t
  implementation, and the one from pcre2-posix is not the same.
- in gdb_regex.c we use GNU regex function re_search, which pcre2-posix
  doesn't provide, so while regcomp binds to pcre2-posix, re_search binds to
  libc.

A note on the latter: it's actually a bug to compile a regex using regcomp and
then pass it to re_search.  The GNU regex interface requires one to use
re_compile_pattern or re_compile_fastmap.  But as long we're using one of the
GNU regex incarnations in gnulib, glibc or libiberty, we get away with this.

The PR could be fixed by adding -lc in a specific position in the link line,
to force regcomp to be bound to glibc.  But this solution was considered
in the discussion in the PR as being brittle, and possibly causing problems
elsewhere.

Another solution offered was to restrict regex usage to posix, and no longer
use the GNU regex API.  This however could mean having to reproduce some of
that functionality locally, which would mean maintaining the same
functionality in more than one place.

The solution chosen here, is to hardcode --with-included-regex, that is, using
libiberty.

The option of using glibc for regex was introduced because glibc became the
authorative source for GNU regex, so it offered the possibility to link
against a more up-to-date regex version.

In that aspect, this patch is a step back.  But we have the option of using a
more up-to-date regex version as a follow-up step: by using the regex from
gnulib.

Tested on x86_64-linux.

gdb/ChangeLog:

2021-04-21  Tom de Vries  <tdevries@suse.de>

	PR build/27681
	* configure.ac: Remove --without-included-regex/--with-included-regex.
	* config.in: Regenerate.
	* configure: Regenerate.
	* gdb_regex.h: Assume USE_INCLUDED_REGEX is defined.
2021-04-21 21:54:03 +02:00

58 lines
1.9 KiB
C++

/* Portable <regex.h>.
Copyright (C) 2000-2021 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef GDB_REGEX_H
#define GDB_REGEX_H 1
# include "xregex.h"
/* A compiled regex. This is mainly a wrapper around regex_t. The
the constructor throws on regcomp error and the destructor is
responsible for calling regfree. The former means that it's not
possible to create an instance of compiled_regex that isn't
compiled, hence the name. */
class compiled_regex
{
public:
/* Compile a regexp and throw an exception on error, including
MESSAGE. REGEX and MESSAGE must not be NULL. */
compiled_regex (const char *regex, int cflags,
const char *message)
ATTRIBUTE_NONNULL (2) ATTRIBUTE_NONNULL (4);
~compiled_regex ();
DISABLE_COPY_AND_ASSIGN (compiled_regex);
/* Wrapper around ::regexec. */
int exec (const char *string,
size_t nmatch, regmatch_t pmatch[],
int eflags) const;
/* Wrapper around ::re_search. (Not const because re_search's
regex_t parameter isn't either.) */
int search (const char *string, int size, int startpos,
int range, struct re_registers *regs);
private:
/* The compiled pattern. */
regex_t m_pattern;
};
#endif /* not GDB_REGEX_H */