diff mbox series

[v2,1/2] posix: Add compat glob symbol to not follow dangling symbols

Message ID 1505745774-29303-1-git-send-email-adhemerval.zanella@linaro.org
State New
Headers show
Series [v2,1/2] posix: Add compat glob symbol to not follow dangling symbols | expand

Commit Message

Adhemerval Zanella Sept. 18, 2017, 2:42 p.m. UTC
Changes from previous version:

  * Fix alpha oldglob definition by making it also not follow dangling
    symlinks.

  * Add powerpc64le abilist entries.

  * Increase _GNU_GLOB_INTERFACE_VERSION to 2 to advertive a new internal
    glob semantic.

---

This patch follows commit 5554304f0 (posix: Allow glob to match dangling
symlinks [BZ #866]) by adding a compat symbol that follow previous
semantic of not following dangling symlinks and thus avoiding call
gl_lstat with GLOB_ALTDIRFUNC.

It avoids failure with old binaries that not set the alternate function
pointer for lstat (GNUmake for instance).  The following scenario, for
instance, fails with current GNUmake because glibc will access unitialized
memory when calling gl_lstat:

  $ cat src/t/t.c
  int main ()
  {
    return 0;
  }
  $ cat Makefile
  SRC = $(wildcard src/*/t.c)
  OBJ = $(patsubst src/%.c, obj/%.o, $(SRC))

  prog:           $(OBJ)
                  $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) $(OBJ) -o prog

  obj/%.o:        src/%.c
                  $(CC) $(CFLAGS) -c $< -o $@
  $ make

This works as expected with the patch applied.  Since it is for generic
ABI, default compat symbols are added with override for Linux due LFS.
Now we have two compat symbols for glob on Linux:

  1. sysdeps/unix/sysv/linux/oldglob.c which implements glob64 with
     the old dirent layout.  For this implementation I also set it to
     not follow dangling symlinks (which is the safest path).

  2. sysdeps/unix/sysv/linux/glob{64}-lstat-compat.c which implements
     the compat symbol for dangling symlinks.  As for generic glob,
     the implementation uses XSTAT_IS_XSTAT64 to define whether
     both __glob_lstat_compat and __glob64_lstat_compat should be
     different implementations.  For archictures that define
     XSTAT_IS_XSTAT64, __glob_lstat_compat is aliased to
     __glob64_lstat_compat.

  3. sysdeps/unix/sysv/linux/alpha/oldglob.c with a different glob_t
     layout.  As for 1. this patch changes it to not follow dangling
     symlinks.

The patch also bumps _GNU_GLOB_INTERFACE_VERSION to 2 to advertise the
new semantic.  On GNUmake, for instance, it will force to it use its
internal glob implementation instead and avoiding triggering the same
failure on builds against newer GLIBCs.

Checked on x86_64-linux-gnu and i686-linux-gnu.  I also checked
with a build against the major ABIs required to check for the abilist.

The changes should also work on gnulib (I run gnulib-tool.py check glob
and it shown no regressions).

	* include/gnu-versions.h (_GNU_GLOB_INTERFACE_VERSION): Increase
	version to 2.
	* posix/Makefile (routines): Add glob-lstat-compat and
	glob64-lstat-compat.
	* posix/Versions (GLIBC_2.27, glob, glob64): Add symbol version.
	* posix/glob-lstat-compat.c: New file.
	* posix/glob64-lstat-compat.c: Likewise.
	* posix/tst-glob_lstat_compat.c: Likewise.
	* sysdeps/unix/sysv/linux/glob-lstat-compat.c: Likewise.
	* sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c: Likewise.
	* sysdeps/unix/sysv/linux/glob64-lstat-compat.c: Likewise.
	* sysdeps/unix/sysv/linux/alpha/glob.c: Remove file.
	* posix/glob.c (glob_lstat): New function.
	(glob): Rename to __glob and add versioned symbol to 2.27.
	(glob_in_dir): Use glob_lstat.
	* posix/glob64.c (glob64): Add GLOB_ATTRIBUTE.
	* sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/glob.c (glob): Add versioned symbol for
	2.27.
	* sysdeps/unix/sysv/linux/glob64.c (glob64): Likewise.
	* sysdeps/unix/sysv/linux/oldglob.c (GLOB_LSTAT_COMPAT): Define.
	* sysdeps/unix/sysv/linux/alpha/oldglob.c (__old_glob): Do not use
	gl_lstat on glob call.
	* sysdeps/unix/sysv/linux/aarch64/libc.abilist: Add GLIBC_2.27 glob
	and glob64 symbols.
	* sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
	Likewise.
	* sysdeps/unix/linux/powerpc/powerpc32/nofpu/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.
---
 ChangeLog                                          |  54 +++++
 include/gnu-versions.h                             |   2 +-
 posix/Makefile                                     |   4 +-
 posix/Versions                                     |   3 +
 posix/glob-lstat-compat.c                          |  36 +++
 posix/glob.c                                       |  65 +++--
 posix/glob64-lstat-compat.c                        |  36 +++
 posix/glob64.c                                     |   5 +
 posix/tst-glob_lstat_compat.c                      | 263 +++++++++++++++++++++
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |   3 +
 sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c  |   2 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |   3 +
 sysdeps/unix/sysv/linux/alpha/oldglob.c            |   6 +-
 sysdeps/unix/sysv/linux/arm/libc.abilist           |   3 +
 .../linux/{alpha/glob.c => glob-lstat-compat.c}    |  50 ++--
 sysdeps/unix/sysv/linux/glob.c                     |   5 +-
 sysdeps/unix/sysv/linux/glob64-lstat-compat.c      |  51 ++++
 sysdeps/unix/sysv/linux/glob64.c                   |   7 +-
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |   3 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |   3 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |   3 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |   3 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |   3 +
 sysdeps/unix/sysv/linux/microblaze/libc.abilist    |   3 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |   3 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |   3 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |   3 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |   3 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |   3 +
 sysdeps/unix/sysv/linux/oldglob.c                  |   5 +-
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |   3 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |   3 +
 .../sysv/linux/powerpc/powerpc64/libc-le.abilist   |   3 +
 .../unix/sysv/linux/powerpc/powerpc64/libc.abilist |   3 +
 sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist  |   3 +
 sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist  |   3 +
 sysdeps/unix/sysv/linux/sh/libc.abilist            |   3 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |   3 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |   3 +
 .../sysv/linux/tile/tilegx/tilegx32/libc.abilist   |   3 +
 .../sysv/linux/tile/tilegx/tilegx64/libc.abilist   |   3 +
 sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist  |   3 +
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |   3 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |   3 +
 44 files changed, 619 insertions(+), 59 deletions(-)
 create mode 100644 posix/glob-lstat-compat.c
 create mode 100644 posix/glob64-lstat-compat.c
 create mode 100644 posix/tst-glob_lstat_compat.c
 create mode 100644 sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c
 rename sysdeps/unix/sysv/linux/{alpha/glob.c => glob-lstat-compat.c} (50%)
 create mode 100644 sysdeps/unix/sysv/linux/glob64-lstat-compat.c

-- 
2.7.4

Comments

Paul Eggert Sept. 18, 2017, 4:53 p.m. UTC | #1
I looked only at the posix/glob.c changes, since they're shared with Gnulib.

The macro GLOB_LSTAT_COMPAT has a confusing name. The name sounds like it 
involves glob using lstat. But the name really means "glob should not call 
lstat, to be compatible with older versions". I suggest renaming it to something 
like GLOB_NO_LSTAT to make this clearer.

Why have a named type 'union glob_stat'? It's used only once, and the old code 
didn't give it a name, so why give it a name now?

> +  return __builtin_expect (flags & GLOB_ALTDIRFUNC, 0)                         

> +/* Use on glob-lstat-compat.c to provide a compat symbol which does not        

> +   use lstat / gl_lstat.  */                                                   

> +#ifdef GLOB_LSTAT_COMPAT                                                       

> +         ? (*pglob->gl_stat) (fullname, &ust.st)                               

> +         : __stat64 (fullname, &ust.st64);                                     

> +#else                                                                          

> +         ? (*pglob->gl_lstat) (fullname, &ust.st)                              

> +         : __lstat64 (fullname, &ust.st64);                                    

> +#endif                                                                         


Please reformulate so that the #ifdef does not appear within a statement or 
expression; it's confusing to have #ifs containing just parts of statements.

A minor point: there is no need for the '*' prefix operator; the use of '*' in 
this code goes back to pre-C89 compilers and we don't need to worry about that 
any more.

Perhaps something like the following instead? It addresses the above points.

#ifdef GLOB_NO_STAT
# define GL_LSTAT gl_stat
# define LSTAT64 __stat64
#else
# define GL_LSTAT gl_lstat
# define LSTAT64 __lstat64
#endif

...

   union
   {
     struct stat st;
     struct_stat64 st64;
   } ust;
   return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)
           ? pglob->GL_LSTAT (fullname, &ust.st)
           : LSTAT64 (fullname, &ust.st64));
Szabolcs Nagy Sept. 19, 2017, 11:14 a.m. UTC | #2
On 18/09/17 15:42, Adhemerval Zanella wrote:
> Changes from previous version:

> 

>   * Fix alpha oldglob definition by making it also not follow dangling

>     symlinks.

> 

>   * Add powerpc64le abilist entries.

> 

>   * Increase _GNU_GLOB_INTERFACE_VERSION to 2 to advertive a new internal

>     glob semantic.

> 

> ---

> 

> This patch follows commit 5554304f0 (posix: Allow glob to match dangling

> symlinks [BZ #866]) by adding a compat symbol that follow previous

> semantic of not following dangling symlinks and thus avoiding call

> gl_lstat with GLOB_ALTDIRFUNC.

> 

> It avoids failure with old binaries that not set the alternate function

> pointer for lstat (GNUmake for instance).  The following scenario, for

> instance, fails with current GNUmake because glibc will access unitialized

> memory when calling gl_lstat:

> 


i still think the original change should be reverted
until there is a released version of make with the fix.

build scripts will use a released version of make
and the breakage will go unnoticed until make is
run on the newly built system.
Adhemerval Zanella Sept. 19, 2017, 12:12 p.m. UTC | #3
On 19/09/2017 08:14, Szabolcs Nagy wrote:
> On 18/09/17 15:42, Adhemerval Zanella wrote:

>> Changes from previous version:

>>

>>   * Fix alpha oldglob definition by making it also not follow dangling

>>     symlinks.

>>

>>   * Add powerpc64le abilist entries.

>>

>>   * Increase _GNU_GLOB_INTERFACE_VERSION to 2 to advertive a new internal

>>     glob semantic.

>>

>> ---

>>

>> This patch follows commit 5554304f0 (posix: Allow glob to match dangling

>> symlinks [BZ #866]) by adding a compat symbol that follow previous

>> semantic of not following dangling symlinks and thus avoiding call

>> gl_lstat with GLOB_ALTDIRFUNC.

>>

>> It avoids failure with old binaries that not set the alternate function

>> pointer for lstat (GNUmake for instance).  The following scenario, for

>> instance, fails with current GNUmake because glibc will access unitialized

>> memory when calling gl_lstat:

>>

> 

> i still think the original change should be reverted

> until there is a released version of make with the fix.

> 

> build scripts will use a released version of make

> and the breakage will go unnoticed until make is

> run on the newly built system.

> 


With this patch this scenario should not happen, either GNUmake will be
built against _GNU_GLOB_INTERFACE_VERSION equal to 1 and use the compat
symbol or use its own glob version for newer builds.

When GNUmake fixes its GLOB_ALTDIRFUNC usage it also should update the
config script to check for _GNU_GLOB_INTERFACE_VERSION to 1 and/or 2.
Adhemerval Zanella Sept. 19, 2017, 1:08 p.m. UTC | #4
On 18/09/2017 13:53, Paul Eggert wrote:
> I looked only at the posix/glob.c changes, since they're shared with Gnulib.

> 

> The macro GLOB_LSTAT_COMPAT has a confusing name. The name sounds like it involves glob using lstat. But the name really means "glob should not call lstat, to be compatible with older versions". I suggest renaming it to something like GLOB_NO_LSTAT to make this clearer.

> 

> Why have a named type 'union glob_stat'? It's used only once, and the old code didn't give it a name, so why give it a name now?

> 

>> +  return __builtin_expect (flags & GLOB_ALTDIRFUNC, 0)                         +/* Use on glob-lstat-compat.c to provide a compat symbol which does not        +   use lstat / gl_lstat.  */                                                   +#ifdef GLOB_LSTAT_COMPAT                                                       +         ? (*pglob->gl_stat) (fullname, &ust.st)                               +         : __stat64 (fullname, &ust.st64);                                     +#else                                                                          +         ? (*pglob->gl_lstat) (fullname, &ust.st)                              +         : __lstat64 (fullname, &ust.st64);                                    +#endif                                                                         

> 

> Please reformulate so that the #ifdef does not appear within a statement or expression; it's confusing to have #ifs containing just parts of statements.

> 

> A minor point: there is no need for the '*' prefix operator; the use of '*' in this code goes back to pre-C89 compilers and we don't need to worry about that any more.

> 

> Perhaps something like the following instead? It addresses the above points.

> 

> #ifdef GLOB_NO_STAT

> # define GL_LSTAT gl_stat

> # define LSTAT64 __stat64

> #else

> # define GL_LSTAT gl_lstat

> # define LSTAT64 __lstat64

> #endif

> 

> ...

> 

>   union

>   {

>     struct stat st;

>     struct_stat64 st64;

>   } ust;

>   return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)

>           ? pglob->GL_LSTAT (fullname, &ust.st)

>           : LSTAT64 (fullname, &ust.st64));


Thanks for the reviews, all points addresses in the patch below:

---

	* include/gnu-versions.h (_GNU_GLOB_INTERFACE_VERSION): Increase
	version to 2.
	* posix/Makefile (routines): Add glob-lstat-compat and
	glob64-lstat-compat.
	* posix/Versions (GLIBC_2.27, glob, glob64): Add symbol version.
	* posix/glob-lstat-compat.c: New file.
	* posix/glob64-lstat-compat.c: Likewise.
	* posix/tst-glob_lstat_compat.c: Likewise.
	* sysdeps/unix/sysv/linux/glob-lstat-compat.c: Likewise.
	* sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c: Likewise.
	* sysdeps/unix/sysv/linux/glob64-lstat-compat.c: Likewise.
	* sysdeps/unix/sysv/linux/alpha/glob.c: Remove file.
	* posix/glob.c (glob_lstat): New function.
	(glob): Rename to __glob and add versioned symbol to 2.27.
	(glob_in_dir): Use glob_lstat.
	* posix/glob64.c (glob64): Add GLOB_ATTRIBUTE.
	* sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/glob.c (glob): Add versioned symbol for
	2.27.
	* sysdeps/unix/sysv/linux/glob64.c (glob64): Likewise.
	* sysdeps/unix/sysv/linux/oldglob.c (GLOB_NO_LSTAT): Define.
	* sysdeps/unix/sysv/linux/alpha/oldglob.c (__old_glob): Do not use
	gl_lstat on glob call.
	* sysdeps/unix/sysv/linux/aarch64/libc.abilist: Add GLIBC_2.27 glob
	and glob64 symbols.
	* sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
	Likewise.
	* sysdeps/unix/linux/powerpc/powerpc32/nofpu/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.

---

diff --git a/include/gnu-versions.h b/include/gnu-versions.h
index 40f2bfc..ce26254 100644
--- a/include/gnu-versions.h
+++ b/include/gnu-versions.h
@@ -45,7 +45,7 @@
 
 #define _GNU_OBSTACK_INTERFACE_VERSION	1 /* vs malloc/obstack.c */
 #define _GNU_REGEX_INTERFACE_VERSION	1 /* vs posix/regex.c */
-#define _GNU_GLOB_INTERFACE_VERSION	1 /* vs posix/glob.c */
+#define _GNU_GLOB_INTERFACE_VERSION	2 /* vs posix/glob.c */
 #define _GNU_GETOPT_INTERFACE_VERSION	2 /* vs posix/getopt.c and
 					     posix/getopt1.c */
 
diff --git a/posix/Makefile b/posix/Makefile
index 7188cba..203555a 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -46,6 +46,7 @@ routines :=								      \
 	getresuid getresgid setresuid setresgid				      \
 	pathconf sysconf fpathconf					      \
 	glob glob64 globfree globfree64 glob_pattern_p fnmatch regex	      \
+	glob-lstat-compat glob64-lstat-compat				      \
 	confstr								      \
 	getopt getopt1 							      \
 	sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax  \
@@ -95,7 +96,8 @@ tests		:= test-errno tstgetopt testfnm runtests runptests \
 		   tst-posix_fadvise tst-posix_fadvise64 \
 		   tst-sysconf-empty-chroot tst-glob_symlinks
 tests-internal	:= bug-regex5 bug-regex20 bug-regex33 \
-		   tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3
+		   tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \
+		   tst-glob_lstat_compat
 xtests		:= bug-ga2
 ifeq (yes,$(build-shared))
 test-srcs	:= globtest
diff --git a/posix/Versions b/posix/Versions
index bb481a5..65e9687 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -134,6 +134,9 @@ libc {
   GLIBC_2.11 {
     execvpe;
   }
+  GLIBC_2.27 {
+    glob; glob64;
+  }
   GLIBC_PRIVATE {
     __libc_fork; __libc_pread; __libc_pwrite;
   }
diff --git a/posix/glob-lstat-compat.c b/posix/glob-lstat-compat.c
new file mode 100644
index 0000000..e30d343
--- /dev/null
+++ b/posix/glob-lstat-compat.c
@@ -0,0 +1,36 @@
+/* Compat glob which does not use gl_lstat for GLOB_ALTDIRFUNC.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_27)
+
+# include <glob.h>
+
+# define __glob(pattern, flags, errfunc, pglob) \
+  __glob_lstat_compat (pattern, flags, errfunc, pglob)
+
+# define GLOB_ATTRIBUTE attribute_compat_text_section
+
+/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */
+# define GLOB_NO_LSTAT
+
+# include <posix/glob.c>
+
+compat_symbol (libc, __glob_lstat_compat, glob, GLIBC_2_0);
+#endif
diff --git a/posix/glob.c b/posix/glob.c
index c699177..795cebe 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -57,7 +57,9 @@
 # endif
 # define struct_stat64		struct stat64
 # define FLEXIBLE_ARRAY_MEMBER
+# include <shlib-compat.h>
 #else /* !_LIBC */
+# define __glob                 glob
 # define __getlogin_r(buf, len) getlogin_r (buf, len)
 # define __lstat64(fname, buf)  lstat (fname, buf)
 # define __stat64(fname, buf)   stat (fname, buf)
@@ -179,6 +181,29 @@ convert_dirent64 (const struct dirent64 *source)
     ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)
 #endif
 
+static int
+glob_lstat (glob_t *pglob, int flags, const char *fullname)
+{
+/* Use on glob-lstat-compat.c to provide a compat symbol which does not
+   use lstat / gl_lstat.  */
+#ifdef GLOB_NO_LSTAT
+# define GL_LSTAT gl_stat
+# define LSTAT64 __stat64
+#else
+# define GL_LSTAT gl_lstat
+# define LSTAT64 __lstat64
+#endif
+
+  union
+  {
+    struct stat st;
+    struct_stat64 st64;
+  } ust;
+  return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)
+          ? pglob->GL_LSTAT (fullname, &ust.st)
+          : LSTAT64 (fullname, &ust.st64));
+}
+
 /* Set *R = A + B.  Return true if the answer is mathematically
    incorrect due to overflow; in this case, *R is the low order
    bits of the correct answer.  */
@@ -248,6 +273,9 @@ next_brace_sub (const char *cp, int flags)
   return *cp != '\0' ? cp : NULL;
 }
 
+#ifndef GLOB_ATTRIBUTE
+# define GLOB_ATTRIBUTE
+#endif
 
 /* Do glob searching for PATTERN, placing results in PGLOB.
    The bits defined above may be set in FLAGS.
@@ -258,11 +286,9 @@ next_brace_sub (const char *cp, int flags)
    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
    Otherwise, 'glob' returns zero.  */
 int
-#ifdef GLOB_ATTRIBUTE
 GLOB_ATTRIBUTE
-#endif
-glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
-      glob_t *pglob)
+__glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
+	glob_t *pglob)
 {
   const char *filename;
   char *dirname = NULL;
@@ -406,9 +432,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 	      /* Construct the new glob expression.  */
 	      mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
 
-	      result = glob (onealt,
-			     ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
-			      | GLOB_APPEND), errfunc, pglob);
+	      result = __glob (onealt,
+			       ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
+			       | GLOB_APPEND), errfunc, pglob);
 
 	      /* If we got an error, return it.  */
 	      if (result && result != GLOB_NOMATCH)
@@ -557,7 +583,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 		  flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
 		}
 	    }
-	  int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
+	  int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob);
 	  if (val == 0)
 	    pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
 			       | (flags & GLOB_MARK));
@@ -931,11 +957,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 	  dirs.gl_lstat = pglob->gl_lstat;
 	}
 
-      status = glob (dirname,
-		     ((flags & (GLOB_ERR | GLOB_NOESCAPE
-				| GLOB_ALTDIRFUNC))
-		      | GLOB_NOSORT | GLOB_ONLYDIR),
-		     errfunc, &dirs);
+      status = __glob (dirname,
+		       ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC))
+		       | GLOB_NOSORT | GLOB_ONLYDIR),
+		       errfunc, &dirs);
       if (status != 0)
 	{
 	  if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
@@ -1133,8 +1158,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 
   return retval;
 }
-#if defined _LIBC && !defined glob
-libc_hidden_def (glob)
+#if defined _LIBC && !defined __glob
+versioned_symbol (libc, __glob, glob, GLIBC_2_27);
+libc_hidden_ver (__glob, glob)
 #endif
 
 
@@ -1250,11 +1276,6 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
     }
   else if (meta == GLOBPAT_NONE)
     {
-      union
-      {
-	struct stat st;
-	struct_stat64 st64;
-      } ust;
       size_t patlen = strlen (pattern);
       size_t fullsize;
       bool alloca_fullname
@@ -1273,10 +1294,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
       mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
 			"/", 1),
 	       pattern, patlen + 1);
-      if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
-	   ? (*pglob->gl_lstat) (fullname, &ust.st)
-	    : __lstat64 (fullname, &ust.st64))
-	   == 0)
+      if (glob_lstat (pglob, flags, fullname) == 0
 	  || errno == EOVERFLOW)
 	/* We found this file to be existing.  Now tell the rest
 	   of the function to copy this name into the result.  */
diff --git a/posix/glob64-lstat-compat.c b/posix/glob64-lstat-compat.c
new file mode 100644
index 0000000..1fabf86
--- /dev/null
+++ b/posix/glob64-lstat-compat.c
@@ -0,0 +1,36 @@
+/* Compat glob which does not use gl_lstat for GLOB_ALTDIRFUNC.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_27)
+
+# include <glob.h>
+
+# define glob(pattern, flags, errfunc, pglob) \
+  __glob64_lstat_compat (pattern, flags, errfunc, pglob)
+
+# define GLOB_ATTRIBUTE attribute_compat_text_section
+
+/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */
+# define GLOB_NO_LSTAT
+
+# include <posix/glob64.c>
+
+compat_symbol (libc, __glob64_lstat_compat, glob64, GLIBC_2_0);
+#endif
diff --git a/posix/glob64.c b/posix/glob64.c
index a515a1c..ee7ef84 100644
--- a/posix/glob64.c
+++ b/posix/glob64.c
@@ -20,6 +20,10 @@
 #include <glob.h>
 #include <errno.h>
 
+#ifdef GLOB_ATTRIBUTE
+# define GLOB_ATTRIBUTE
+#endif
+
 /* Do glob searching for PATTERN, placing results in PGLOB.
    The bits defined above may be set in FLAGS.
    If a directory cannot be opened or read and ERRFUNC is not nil,
@@ -29,6 +33,7 @@
    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
    Otherwise, `glob' returns zero.  */
 int
+GLOB_ATTRIBUTE
 glob64 (const char *pattern, int flags,
 	int (*errfunc) (const char *, int), glob64_t *pglob)
 {
diff --git a/posix/tst-glob_lstat_compat.c b/posix/tst-glob_lstat_compat.c
new file mode 100644
index 0000000..c5b9a27
--- /dev/null
+++ b/posix/tst-glob_lstat_compat.c
@@ -0,0 +1,263 @@
+/* Test glob compat symbol which avoid call GLOB_ALTDIRFUNC/gl_lstat.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <glob.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <stdio.h>
+
+#include <shlib-compat.h>
+#include <support/check.h>
+#include <support/temp_file.h>
+
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_27)
+
+__typeof (glob) glob;
+compat_symbol_reference (libc, glob, glob, GLIBC_2_0);
+
+/* Compat glob should not call gl_lstat since for some old binaries it
+   might be unitialized (for instance GNUmake).  Check if it is indeed
+   not called.  */
+static bool stat_called;
+static bool lstat_called;
+
+static struct
+{
+  const char *name;
+  int level;
+  int type;
+} filesystem[] =
+{
+  { ".", 1, DT_DIR },
+  { "..", 1, DT_DIR },
+  { "dir1lev1", 1, DT_UNKNOWN },
+    { ".", 2, DT_DIR },
+    { "..", 2, DT_DIR },
+    { "file1lev2", 2, DT_REG },
+    { "file2lev2", 2, DT_REG },
+};
+static const size_t nfiles = sizeof (filesystem) / sizeof (filesystem [0]);
+
+typedef struct
+{
+  int level;
+  int idx;
+  struct dirent d;
+  char room_for_dirent[NAME_MAX];
+} my_DIR;
+
+static long int
+find_file (const char *s)
+{
+  int level = 1;
+  long int idx = 0;
+
+  while (s[0] == '/')
+    {
+      if (s[1] == '\0')
+	{
+	  s = ".";
+	  break;
+	}
+      ++s;
+    }
+
+  if (strcmp (s, ".") == 0)
+    return 0;
+
+  if (s[0] == '.' && s[1] == '/')
+    s += 2;
+
+  while (*s != '\0')
+    {
+      char *endp = strchrnul (s, '/');
+
+      while (idx < nfiles && filesystem[idx].level >= level)
+	{
+	  if (filesystem[idx].level == level
+	      && memcmp (s, filesystem[idx].name, endp - s) == 0
+	      && filesystem[idx].name[endp - s] == '\0')
+	    break;
+	  ++idx;
+	}
+
+      if (idx == nfiles || filesystem[idx].level < level)
+	{
+	  errno = ENOENT;
+	  return -1;
+	}
+
+      if (*endp == '\0')
+	return idx + 1;
+
+      if (filesystem[idx].type != DT_DIR
+	  && (idx + 1 >= nfiles
+	      || filesystem[idx].level >= filesystem[idx + 1].level))
+	{
+	  errno = ENOTDIR;
+	  return -1;
+	}
+
+      ++idx;
+
+      s = endp + 1;
+      ++level;
+    }
+
+  errno = ENOENT;
+  return -1;
+}
+
+static void *
+my_opendir (const char *s)
+{
+  long int idx = find_file (s);
+  if (idx == -1 || filesystem[idx].type != DT_DIR)
+    return NULL;
+
+  my_DIR *dir = malloc (sizeof (my_DIR));
+  if (dir == NULL)
+    FAIL_EXIT1 ("cannot allocate directory handle");
+
+  dir->level = filesystem[idx].level;
+  dir->idx = idx;
+
+  return dir;
+}
+
+static struct dirent *
+my_readdir (void *gdir)
+{
+  my_DIR *dir = gdir;
+
+  if (dir->idx == -1)
+    return NULL;
+
+  while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)
+    ++dir->idx;
+
+  if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)
+    {
+      dir->idx = -1;
+      return NULL;
+    }
+
+  dir->d.d_ino = 1;		/* glob should not skip this entry.  */
+
+#ifdef _DIRENT_HAVE_D_TYPE
+  dir->d.d_type = filesystem[dir->idx].type;
+#endif
+
+  strcpy (dir->d.d_name, filesystem[dir->idx].name);
+
+  ++dir->idx;
+
+  return &dir->d;
+}
+
+static void
+my_closedir (void *dir)
+{
+  free (dir);
+}
+
+static int
+my_stat (const char *name, struct stat *st)
+{
+  stat_called = true;
+
+  long int idx = find_file (name);
+  if (idx == -1)
+    return -1;
+
+  memset (st, '\0', sizeof (*st));
+
+  if (filesystem[idx].type == DT_UNKNOWN)
+    st->st_mode = DTTOIF (idx + 1 < nfiles
+			  && filesystem[idx].level < filesystem[idx + 1].level
+			  ? DT_DIR : DT_REG) | 0777;
+  else
+    st->st_mode = DTTOIF (filesystem[idx].type) | 0777;
+  return 0;
+}
+
+static int
+my_lstat (const char *name, struct stat *st)
+{
+  lstat_called = true;
+
+  long int idx = find_file (name);
+  if (idx == -1)
+    return -1;
+
+  memset (st, '\0', sizeof (*st));
+
+  if (filesystem[idx].type == DT_UNKNOWN)
+    st->st_mode = DTTOIF (idx + 1 < nfiles
+			  && filesystem[idx].level < filesystem[idx + 1].level
+			  ? DT_DIR : DT_REG) | 0777;
+  else
+    st->st_mode = DTTOIF (filesystem[idx].type) | 0777;
+  return 0;
+}
+
+static int
+do_test (void)
+{
+  glob_t gl;
+
+  memset (&gl, '\0', sizeof (gl));
+
+  gl.gl_closedir = my_closedir;
+  gl.gl_readdir = my_readdir;
+  gl.gl_opendir = my_opendir;
+  gl.gl_lstat = my_lstat;
+  gl.gl_stat = my_stat;
+
+  int flags = GLOB_ALTDIRFUNC;
+
+  stat_called = false;
+  lstat_called = false;
+
+  TEST_VERIFY_EXIT (glob ("*/file1lev2", flags, NULL, &gl) == 0);
+  TEST_VERIFY_EXIT (gl.gl_pathc == 1);
+  TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], "dir1lev1/file1lev2") == 0);
+
+  TEST_VERIFY_EXIT (stat_called == true);
+  TEST_VERIFY_EXIT (lstat_called == false);
+
+  return 0;
+}
+
+#else /* TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_27)  */
+
+static int
+do_test (void)
+{ 
+  return 77;
+}
+#endif
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 81e4fe9..e7438c5 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2103,3 +2103,6 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c b/sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c
new file mode 100644
index 0000000..a76471d
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c
@@ -0,0 +1,2 @@
+#define GLOB_LSTAT_VERSION GLIBC_2_1
+#include <sysdeps/unix/sysv/linux/glob-lstat-compat.c>
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index fab7331..4836ea0 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2014,6 +2014,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/alpha/oldglob.c b/sysdeps/unix/sysv/linux/alpha/oldglob.c
index 988c92b..b54624c 100644
--- a/sysdeps/unix/sysv/linux/alpha/oldglob.c
+++ b/sysdeps/unix/sysv/linux/alpha/oldglob.c
@@ -59,7 +59,9 @@ __old_glob (const char *pattern, int flags,
   correct.gl_closedir = pglob->gl_closedir;
   correct.gl_readdir = pglob->gl_readdir;
   correct.gl_opendir = pglob->gl_opendir;
-  correct.gl_lstat = pglob->gl_lstat;
+  /* Set gl_lstat and gl_stat for both gl_stat for compatibility with old
+     implementation that did not follow dangling symlinks.  */
+  correct.gl_lstat = pglob->gl_stat;
   correct.gl_stat = pglob->gl_stat;
 
   result = glob (pattern, flags, errfunc, &correct);
@@ -72,7 +74,7 @@ __old_glob (const char *pattern, int flags,
   pglob->gl_closedir = correct.gl_closedir;
   pglob->gl_readdir = correct.gl_readdir;
   pglob->gl_opendir = correct.gl_opendir;
-  pglob->gl_lstat = correct.gl_lstat;
+  /* Only need to restore gl_stat.  */
   pglob->gl_stat = correct.gl_stat;
 
   return result;
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index d2a206a..5b70e1b 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -104,6 +104,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/alpha/glob.c b/sysdeps/unix/sysv/linux/glob-lstat-compat.c
similarity index 50%
rename from sysdeps/unix/sysv/linux/alpha/glob.c
rename to sysdeps/unix/sysv/linux/glob-lstat-compat.c
index 1b813c1..9867e2f 100644
--- a/sysdeps/unix/sysv/linux/alpha/glob.c
+++ b/sysdeps/unix/sysv/linux/glob-lstat-compat.c
@@ -1,4 +1,6 @@
-/* Copyright (C) 1998-2017 Free Software Foundation, Inc.
+/* Compat glob which does not use gl_lstat for GLOB_ALTDIRFUNC.
+   Linux version which handles LFS when required.
+   Copyright (C) 2017 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -12,36 +14,34 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
+   License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#define glob64 __no_glob64_decl
-#define globfree64 __no_globfree64_decl
-
-#include <sys/types.h>
-#include <glob.h>
+#include <sys/stat.h>
+#include <kernel_stat.h>
 #include <shlib-compat.h>
 
-/* For Linux/Alpha we have to make the glob symbols versioned.  */
-#define glob(pattern, flags, errfunc, pglob) \
-  __new_glob (pattern, flags, errfunc, pglob)
-#define globfree(pglob) \
-  __new_globfree (pglob)
+#define glob64 __no_glob64_decl
+#include <glob.h>
+#undef glob64
 
-/* We need prototypes for these new names.  */
-extern int __new_glob (const char *__pattern, int __flags,
-		       int (*__errfunc) (const char *, int),
-		       glob_t *__pglob);
-extern void __new_globfree (glob_t *__pglob);
+#define __glob __glob_lstat_compat
 
-#include <posix/glob.c>
+#define GLOB_ATTRIBUTE attribute_compat_text_section
 
-#undef glob
-#undef globfree
-#undef glob64
-#undef globfree64
+/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */
+#define GLOB_NO_LSTAT
 
-versioned_symbol (libc, __new_glob, glob, GLIBC_2_1);
-libc_hidden_ver (__new_glob, glob)
+#include <posix/glob.c>
 
-weak_alias (__new_glob, glob64)
+#ifndef GLOB_LSTAT_VERSION
+# define GLOB_LSTAT_VERSION GLIBC_2_0
+#endif
+
+#if SHLIB_COMPAT(libc, GLOB_LSTAT_VERSION, GLIBC_2_27)
+compat_symbol (libc, __glob_lstat_compat, glob, GLOB_LSTAT_VERSION);
+# if XSTAT_IS_XSTAT64
+strong_alias (__glob_lstat_compat, __glob64_lstat_compat)
+compat_symbol (libc, __glob64_lstat_compat, glob64, GLOB_LSTAT_VERSION);
+# endif
+#endif
diff --git a/sysdeps/unix/sysv/linux/glob.c b/sysdeps/unix/sysv/linux/glob.c
index 057ae7f..e354799 100644
--- a/sysdeps/unix/sysv/linux/glob.c
+++ b/sysdeps/unix/sysv/linux/glob.c
@@ -20,9 +20,12 @@
 #include <kernel_stat.h>
 
 #define glob64 __no_glob64_decl
+#define __glob64 __no___glob64_decl
 #include <posix/glob.c>
 #undef glob64
+#undef __glob64
 
 #if XSTAT_IS_XSTAT64
-weak_alias (glob, glob64)
+strong_alias (__glob, __glob64)
+versioned_symbol (libc, __glob64, glob64, GLIBC_2_27);
 #endif
diff --git a/sysdeps/unix/sysv/linux/glob64-lstat-compat.c b/sysdeps/unix/sysv/linux/glob64-lstat-compat.c
new file mode 100644
index 0000000..f4e468d
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/glob64-lstat-compat.c
@@ -0,0 +1,51 @@
+/* Compat glob which does not use gl_lstat for GLOB_ALTDIRFUNC.
+   Linux version which handles LFS when required.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sys/stat.h>
+#include <kernel_stat.h>
+
+#if !XSTAT_IS_XSTAT64
+# include <glob.h>
+# include <dirent.h>
+# include <sys/stat.h>
+# include <shlib-compat.h>
+
+# define dirent dirent64
+# define __readdir(dirp) __readdir64 (dirp)
+
+# define glob_t glob64_t
+# define __glob __glob64_lstat_compat
+# define globfree globfree64
+
+# undef stat
+# define stat stat64
+
+# define COMPILE_GLOB64	1
+
+# define GLOB_ATTRIBUTE attribute_compat_text_section
+
+/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */
+# define GLOB_NO_LSTAT
+
+# include <posix/glob.c>
+
+# if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_27)
+compat_symbol (libc, __glob64_lstat_compat, glob64, GLIBC_2_2);
+# endif
+#endif /* XSTAT_IS_XSTAT64  */
diff --git a/sysdeps/unix/sysv/linux/glob64.c b/sysdeps/unix/sysv/linux/glob64.c
index 428bbac..0189d1c 100644
--- a/sysdeps/unix/sysv/linux/glob64.c
+++ b/sysdeps/unix/sysv/linux/glob64.c
@@ -28,8 +28,7 @@
 # define __readdir(dirp) __readdir64 (dirp)
 
 # define glob_t glob64_t
-# define glob(pattern, flags, errfunc, pglob) \
-  __glob64 (pattern, flags, errfunc, pglob)
+# define __glob __glob64
 # define globfree(pglob) globfree64 (pglob)
 
 # undef stat
@@ -39,13 +38,13 @@
 
 # include <posix/glob.c>
 
-# include "shlib-compat.h"
+# include <shlib-compat.h>
 
 # ifdef GLOB_NO_OLD_VERSION
 strong_alias (__glob64, glob64)
 libc_hidden_def (glob64)
 # else
-versioned_symbol (libc, __glob64, glob64, GLIBC_2_2);
+versioned_symbol (libc, __glob64, glob64, GLIBC_2_27);
 libc_hidden_ver (__glob64, glob64)
 # endif
 #endif /* XSTAT_IS_XSTAT64  */
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 24bb730..6a2500a 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1868,6 +1868,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 12e77bd..9ab4e36 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2033,6 +2033,9 @@ GLIBC_2.26 strtof128 F
 GLIBC_2.26 strtof128_l F
 GLIBC_2.26 wcstof128 F
 GLIBC_2.26 wcstof128_l F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 62b67b8..81bb623 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1897,6 +1897,9 @@ GLIBC_2.26 strtof128 F
 GLIBC_2.26 strtof128_l F
 GLIBC_2.26 wcstof128 F
 GLIBC_2.26 wcstof128_l F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index b594ebd..5a33b57 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -105,6 +105,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index a36739d..50a86e7 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1982,6 +1982,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 16aa254..250ef30 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2103,3 +2103,6 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 907ab33..87a1dc4 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1957,6 +1957,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 36ee235..f2b35f2 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1955,6 +1955,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 783aa73..e119842 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1953,6 +1953,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index e1275df..67f10f5 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1948,6 +1948,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index be25228..c599dd9 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2144,3 +2144,6 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/oldglob.c b/sysdeps/unix/sysv/linux/oldglob.c
index 5402450..a034c2d 100644
--- a/sysdeps/unix/sysv/linux/oldglob.c
+++ b/sysdeps/unix/sysv/linux/oldglob.c
@@ -21,7 +21,7 @@ libc_hidden_proto (__old_glob64);
 #define __readdir(dirp) __old_readdir64 (dirp)
 
 #define glob_t glob64_t
-#define glob(pattern, flags, errfunc, pglob) \
+#define __glob(pattern, flags, errfunc, pglob) \
   __old_glob64 (pattern, flags, errfunc, pglob)
 #define globfree(pglob) globfree64(pglob)
 
@@ -33,6 +33,9 @@ libc_hidden_proto (__old_glob64);
 #undef __stat
 #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
 
+/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */
+#define GLOB_NO_LSTAT
+
 #define GLOB_ATTRIBUTE attribute_compat_text_section
 
 #include <posix/glob.c>
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index e213895..385409a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1986,6 +1986,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index d25aefd..e99cb45 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1991,6 +1991,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index 51a8d19..173672a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2198,3 +2198,6 @@ GLIBC_2.26 strtof128 F
 GLIBC_2.26 strtof128_l F
 GLIBC_2.26 wcstof128 F
 GLIBC_2.26 wcstof128_l F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 5eb056b..8a65443 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -105,6 +105,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 _Exit F
 GLIBC_2.3 _IO_2_1_stderr_ D 0xe0
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 63d33e8..271eccc 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1986,6 +1986,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index b1b2b29..8b96e16 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1887,6 +1887,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index f3a70a0..0f840e6 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1872,6 +1872,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 8c4c2e5..7f7449f 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1978,6 +1978,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 1653164..a50485e 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1916,6 +1916,9 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index 41647d4..38a96d3 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2110,3 +2110,6 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index 1088923..572b917 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2110,3 +2110,6 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index 41647d4..38a96d3 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2110,3 +2110,6 @@ GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 8bff2b2..b83d25c 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1874,6 +1874,9 @@ GLIBC_2.26 strtof128 F
 GLIBC_2.26 strtof128_l F
 GLIBC_2.26 wcstof128 F
 GLIBC_2.26 wcstof128_l F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index d91a038..cba1d59 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2117,3 +2117,6 @@ GLIBC_2.26 strtof128 F
 GLIBC_2.26 strtof128_l F
 GLIBC_2.26 wcstof128 F
 GLIBC_2.26 wcstof128_l F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
-- 
2.7.4
Adhemerval Zanella Sept. 22, 2017, 1:02 p.m. UTC | #5
On 19/09/2017 10:08, Adhemerval Zanella wrote:
> 

> 

> On 18/09/2017 13:53, Paul Eggert wrote:

>> I looked only at the posix/glob.c changes, since they're shared with Gnulib.

>>

>> The macro GLOB_LSTAT_COMPAT has a confusing name. The name sounds like it involves glob using lstat. But the name really means "glob should not call lstat, to be compatible with older versions". I suggest renaming it to something like GLOB_NO_LSTAT to make this clearer.

>>

>> Why have a named type 'union glob_stat'? It's used only once, and the old code didn't give it a name, so why give it a name now?

>>

>>> +  return __builtin_expect (flags & GLOB_ALTDIRFUNC, 0)                         +/* Use on glob-lstat-compat.c to provide a compat symbol which does not        +   use lstat / gl_lstat.  */                                                   +#ifdef GLOB_LSTAT_COMPAT                                                       +         ? (*pglob->gl_stat) (fullname, &ust.st)                               +         : __stat64 (fullname, &ust.st64);                                     +#else                                                                          +         ? (*pglob->gl_lstat) (fullname, &ust.st)                              +         : __lstat64 (fullname, &ust.st64);                                    +#endif                                                                         

>>

>> Please reformulate so that the #ifdef does not appear within a statement or expression; it's confusing to have #ifs containing just parts of statements.

>>

>> A minor point: there is no need for the '*' prefix operator; the use of '*' in this code goes back to pre-C89 compilers and we don't need to worry about that any more.

>>

>> Perhaps something like the following instead? It addresses the above points.

>>

>> #ifdef GLOB_NO_STAT

>> # define GL_LSTAT gl_stat

>> # define LSTAT64 __stat64

>> #else

>> # define GL_LSTAT gl_lstat

>> # define LSTAT64 __lstat64

>> #endif

>>

>> ...

>>

>>   union

>>   {

>>     struct stat st;

>>     struct_stat64 st64;

>>   } ust;

>>   return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)

>>           ? pglob->GL_LSTAT (fullname, &ust.st)

>>           : LSTAT64 (fullname, &ust.st64));

> 

> Thanks for the reviews, all points addresses in the patch below:


Paul, any objection to this version?

> 

> ---

> 

> 	* include/gnu-versions.h (_GNU_GLOB_INTERFACE_VERSION): Increase

> 	version to 2.

> 	* posix/Makefile (routines): Add glob-lstat-compat and

> 	glob64-lstat-compat.

> 	* posix/Versions (GLIBC_2.27, glob, glob64): Add symbol version.

> 	* posix/glob-lstat-compat.c: New file.

> 	* posix/glob64-lstat-compat.c: Likewise.

> 	* posix/tst-glob_lstat_compat.c: Likewise.

> 	* sysdeps/unix/sysv/linux/glob-lstat-compat.c: Likewise.

> 	* sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c: Likewise.

> 	* sysdeps/unix/sysv/linux/glob64-lstat-compat.c: Likewise.

> 	* sysdeps/unix/sysv/linux/alpha/glob.c: Remove file.

> 	* posix/glob.c (glob_lstat): New function.

> 	(glob): Rename to __glob and add versioned symbol to 2.27.

> 	(glob_in_dir): Use glob_lstat.

> 	* posix/glob64.c (glob64): Add GLOB_ATTRIBUTE.

> 	* sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/glob.c (glob): Add versioned symbol for

> 	2.27.

> 	* sysdeps/unix/sysv/linux/glob64.c (glob64): Likewise.

> 	* sysdeps/unix/sysv/linux/oldglob.c (GLOB_NO_LSTAT): Define.

> 	* sysdeps/unix/sysv/linux/alpha/oldglob.c (__old_glob): Do not use

> 	gl_lstat on glob call.

> 	* sysdeps/unix/sysv/linux/aarch64/libc.abilist: Add GLIBC_2.27 glob

> 	and glob64 symbols.

> 	* sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:

> 	Likewise.

> 	* sysdeps/unix/linux/powerpc/powerpc32/nofpu/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.

> 	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.

> 

> ---

> 

> diff --git a/include/gnu-versions.h b/include/gnu-versions.h

> index 40f2bfc..ce26254 100644

> --- a/include/gnu-versions.h

> +++ b/include/gnu-versions.h

> @@ -45,7 +45,7 @@

>  

>  #define _GNU_OBSTACK_INTERFACE_VERSION	1 /* vs malloc/obstack.c */

>  #define _GNU_REGEX_INTERFACE_VERSION	1 /* vs posix/regex.c */

> -#define _GNU_GLOB_INTERFACE_VERSION	1 /* vs posix/glob.c */

> +#define _GNU_GLOB_INTERFACE_VERSION	2 /* vs posix/glob.c */

>  #define _GNU_GETOPT_INTERFACE_VERSION	2 /* vs posix/getopt.c and

>  					     posix/getopt1.c */

>  

> diff --git a/posix/Makefile b/posix/Makefile

> index 7188cba..203555a 100644

> --- a/posix/Makefile

> +++ b/posix/Makefile

> @@ -46,6 +46,7 @@ routines :=								      \

>  	getresuid getresgid setresuid setresgid				      \

>  	pathconf sysconf fpathconf					      \

>  	glob glob64 globfree globfree64 glob_pattern_p fnmatch regex	      \

> +	glob-lstat-compat glob64-lstat-compat				      \

>  	confstr								      \

>  	getopt getopt1 							      \

>  	sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax  \

> @@ -95,7 +96,8 @@ tests		:= test-errno tstgetopt testfnm runtests runptests \

>  		   tst-posix_fadvise tst-posix_fadvise64 \

>  		   tst-sysconf-empty-chroot tst-glob_symlinks

>  tests-internal	:= bug-regex5 bug-regex20 bug-regex33 \

> -		   tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3

> +		   tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \

> +		   tst-glob_lstat_compat

>  xtests		:= bug-ga2

>  ifeq (yes,$(build-shared))

>  test-srcs	:= globtest

> diff --git a/posix/Versions b/posix/Versions

> index bb481a5..65e9687 100644

> --- a/posix/Versions

> +++ b/posix/Versions

> @@ -134,6 +134,9 @@ libc {

>    GLIBC_2.11 {

>      execvpe;

>    }

> +  GLIBC_2.27 {

> +    glob; glob64;

> +  }

>    GLIBC_PRIVATE {

>      __libc_fork; __libc_pread; __libc_pwrite;

>    }

> diff --git a/posix/glob-lstat-compat.c b/posix/glob-lstat-compat.c

> new file mode 100644

> index 0000000..e30d343

> --- /dev/null

> +++ b/posix/glob-lstat-compat.c

> @@ -0,0 +1,36 @@

> +/* Compat glob which does not use gl_lstat for GLOB_ALTDIRFUNC.

> +   Copyright (C) 2017 Free Software Foundation, Inc.

> +   This file is part of the GNU C Library.

> +

> +   The GNU C Library is free software; you can redistribute it and/or

> +   modify it under the terms of the GNU Lesser General Public

> +   License as published by the Free Software Foundation; either

> +   version 2.1 of the License, or (at your option) any later version.

> +

> +   The GNU C Library 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

> +   Lesser General Public License for more details.

> +

> +   You should have received a copy of the GNU Lesser General Public

> +   License along with the GNU C Library; if not, see

> +   <http://www.gnu.org/licenses/>.  */

> +

> +#include <shlib-compat.h>

> +

> +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_27)

> +

> +# include <glob.h>

> +

> +# define __glob(pattern, flags, errfunc, pglob) \

> +  __glob_lstat_compat (pattern, flags, errfunc, pglob)

> +

> +# define GLOB_ATTRIBUTE attribute_compat_text_section

> +

> +/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */

> +# define GLOB_NO_LSTAT

> +

> +# include <posix/glob.c>

> +

> +compat_symbol (libc, __glob_lstat_compat, glob, GLIBC_2_0);

> +#endif

> diff --git a/posix/glob.c b/posix/glob.c

> index c699177..795cebe 100644

> --- a/posix/glob.c

> +++ b/posix/glob.c

> @@ -57,7 +57,9 @@

>  # endif

>  # define struct_stat64		struct stat64

>  # define FLEXIBLE_ARRAY_MEMBER

> +# include <shlib-compat.h>

>  #else /* !_LIBC */

> +# define __glob                 glob

>  # define __getlogin_r(buf, len) getlogin_r (buf, len)

>  # define __lstat64(fname, buf)  lstat (fname, buf)

>  # define __stat64(fname, buf)   stat (fname, buf)

> @@ -179,6 +181,29 @@ convert_dirent64 (const struct dirent64 *source)

>      ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)

>  #endif

>  

> +static int

> +glob_lstat (glob_t *pglob, int flags, const char *fullname)

> +{

> +/* Use on glob-lstat-compat.c to provide a compat symbol which does not

> +   use lstat / gl_lstat.  */

> +#ifdef GLOB_NO_LSTAT

> +# define GL_LSTAT gl_stat

> +# define LSTAT64 __stat64

> +#else

> +# define GL_LSTAT gl_lstat

> +# define LSTAT64 __lstat64

> +#endif

> +

> +  union

> +  {

> +    struct stat st;

> +    struct_stat64 st64;

> +  } ust;

> +  return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)

> +          ? pglob->GL_LSTAT (fullname, &ust.st)

> +          : LSTAT64 (fullname, &ust.st64));

> +}

> +

>  /* Set *R = A + B.  Return true if the answer is mathematically

>     incorrect due to overflow; in this case, *R is the low order

>     bits of the correct answer.  */

> @@ -248,6 +273,9 @@ next_brace_sub (const char *cp, int flags)

>    return *cp != '\0' ? cp : NULL;

>  }

>  

> +#ifndef GLOB_ATTRIBUTE

> +# define GLOB_ATTRIBUTE

> +#endif

>  

>  /* Do glob searching for PATTERN, placing results in PGLOB.

>     The bits defined above may be set in FLAGS.

> @@ -258,11 +286,9 @@ next_brace_sub (const char *cp, int flags)

>     If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.

>     Otherwise, 'glob' returns zero.  */

>  int

> -#ifdef GLOB_ATTRIBUTE

>  GLOB_ATTRIBUTE

> -#endif

> -glob (const char *pattern, int flags, int (*errfunc) (const char *, int),

> -      glob_t *pglob)

> +__glob (const char *pattern, int flags, int (*errfunc) (const char *, int),

> +	glob_t *pglob)

>  {

>    const char *filename;

>    char *dirname = NULL;

> @@ -406,9 +432,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),

>  	      /* Construct the new glob expression.  */

>  	      mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);

>  

> -	      result = glob (onealt,

> -			     ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))

> -			      | GLOB_APPEND), errfunc, pglob);

> +	      result = __glob (onealt,

> +			       ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))

> +			       | GLOB_APPEND), errfunc, pglob);

>  

>  	      /* If we got an error, return it.  */

>  	      if (result && result != GLOB_NOMATCH)

> @@ -557,7 +583,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),

>  		  flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);

>  		}

>  	    }

> -	  int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);

> +	  int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob);

>  	  if (val == 0)

>  	    pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)

>  			       | (flags & GLOB_MARK));

> @@ -931,11 +957,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),

>  	  dirs.gl_lstat = pglob->gl_lstat;

>  	}

>  

> -      status = glob (dirname,

> -		     ((flags & (GLOB_ERR | GLOB_NOESCAPE

> -				| GLOB_ALTDIRFUNC))

> -		      | GLOB_NOSORT | GLOB_ONLYDIR),

> -		     errfunc, &dirs);

> +      status = __glob (dirname,

> +		       ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC))

> +		       | GLOB_NOSORT | GLOB_ONLYDIR),

> +		       errfunc, &dirs);

>        if (status != 0)

>  	{

>  	  if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)

> @@ -1133,8 +1158,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),

>  

>    return retval;

>  }

> -#if defined _LIBC && !defined glob

> -libc_hidden_def (glob)

> +#if defined _LIBC && !defined __glob

> +versioned_symbol (libc, __glob, glob, GLIBC_2_27);

> +libc_hidden_ver (__glob, glob)

>  #endif

>  

>  

> @@ -1250,11 +1276,6 @@ glob_in_dir (const char *pattern, const char *directory, int flags,

>      }

>    else if (meta == GLOBPAT_NONE)

>      {

> -      union

> -      {

> -	struct stat st;

> -	struct_stat64 st64;

> -      } ust;

>        size_t patlen = strlen (pattern);

>        size_t fullsize;

>        bool alloca_fullname

> @@ -1273,10 +1294,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,

>        mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),

>  			"/", 1),

>  	       pattern, patlen + 1);

> -      if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)

> -	   ? (*pglob->gl_lstat) (fullname, &ust.st)

> -	    : __lstat64 (fullname, &ust.st64))

> -	   == 0)

> +      if (glob_lstat (pglob, flags, fullname) == 0

>  	  || errno == EOVERFLOW)

>  	/* We found this file to be existing.  Now tell the rest

>  	   of the function to copy this name into the result.  */

> diff --git a/posix/glob64-lstat-compat.c b/posix/glob64-lstat-compat.c

> new file mode 100644

> index 0000000..1fabf86

> --- /dev/null

> +++ b/posix/glob64-lstat-compat.c

> @@ -0,0 +1,36 @@

> +/* Compat glob which does not use gl_lstat for GLOB_ALTDIRFUNC.

> +   Copyright (C) 2017 Free Software Foundation, Inc.

> +   This file is part of the GNU C Library.

> +

> +   The GNU C Library is free software; you can redistribute it and/or

> +   modify it under the terms of the GNU Lesser General Public

> +   License as published by the Free Software Foundation; either

> +   version 2.1 of the License, or (at your option) any later version.

> +

> +   The GNU C Library 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

> +   Lesser General Public License for more details.

> +

> +   You should have received a copy of the GNU Lesser General Public

> +   License along with the GNU C Library; if not, see

> +   <http://www.gnu.org/licenses/>.  */

> +

> +#include <shlib-compat.h>

> +

> +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_27)

> +

> +# include <glob.h>

> +

> +# define glob(pattern, flags, errfunc, pglob) \

> +  __glob64_lstat_compat (pattern, flags, errfunc, pglob)

> +

> +# define GLOB_ATTRIBUTE attribute_compat_text_section

> +

> +/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */

> +# define GLOB_NO_LSTAT

> +

> +# include <posix/glob64.c>

> +

> +compat_symbol (libc, __glob64_lstat_compat, glob64, GLIBC_2_0);

> +#endif

> diff --git a/posix/glob64.c b/posix/glob64.c

> index a515a1c..ee7ef84 100644

> --- a/posix/glob64.c

> +++ b/posix/glob64.c

> @@ -20,6 +20,10 @@

>  #include <glob.h>

>  #include <errno.h>

>  

> +#ifdef GLOB_ATTRIBUTE

> +# define GLOB_ATTRIBUTE

> +#endif

> +

>  /* Do glob searching for PATTERN, placing results in PGLOB.

>     The bits defined above may be set in FLAGS.

>     If a directory cannot be opened or read and ERRFUNC is not nil,

> @@ -29,6 +33,7 @@

>     If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.

>     Otherwise, `glob' returns zero.  */

>  int

> +GLOB_ATTRIBUTE

>  glob64 (const char *pattern, int flags,

>  	int (*errfunc) (const char *, int), glob64_t *pglob)

>  {

> diff --git a/posix/tst-glob_lstat_compat.c b/posix/tst-glob_lstat_compat.c

> new file mode 100644

> index 0000000..c5b9a27

> --- /dev/null

> +++ b/posix/tst-glob_lstat_compat.c

> @@ -0,0 +1,263 @@

> +/* Test glob compat symbol which avoid call GLOB_ALTDIRFUNC/gl_lstat.

> +   Copyright (C) 2017 Free Software Foundation, Inc.

> +   This file is part of the GNU C Library.

> +

> +   The GNU C Library is free software; you can redistribute it and/or

> +   modify it under the terms of the GNU Lesser General Public

> +   License as published by the Free Software Foundation; either

> +   version 2.1 of the License, or (at your option) any later version.

> +

> +   The GNU C Library 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

> +   Lesser General Public License for more details.

> +

> +   You should have received a copy of the GNU Lesser General Public

> +   License along with the GNU C Library; if not, see

> +   <http://www.gnu.org/licenses/>.  */

> +

> +#include <glob.h>

> +#include <errno.h>

> +#include <stdlib.h>

> +#include <string.h>

> +#include <sys/types.h>

> +#include <dirent.h>

> +#include <sys/types.h>

> +#include <sys/stat.h>

> +#include <unistd.h>

> +

> +#include <stdio.h>

> +

> +#include <shlib-compat.h>

> +#include <support/check.h>

> +#include <support/temp_file.h>

> +

> +#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_27)

> +

> +__typeof (glob) glob;

> +compat_symbol_reference (libc, glob, glob, GLIBC_2_0);

> +

> +/* Compat glob should not call gl_lstat since for some old binaries it

> +   might be unitialized (for instance GNUmake).  Check if it is indeed

> +   not called.  */

> +static bool stat_called;

> +static bool lstat_called;

> +

> +static struct

> +{

> +  const char *name;

> +  int level;

> +  int type;

> +} filesystem[] =

> +{

> +  { ".", 1, DT_DIR },

> +  { "..", 1, DT_DIR },

> +  { "dir1lev1", 1, DT_UNKNOWN },

> +    { ".", 2, DT_DIR },

> +    { "..", 2, DT_DIR },

> +    { "file1lev2", 2, DT_REG },

> +    { "file2lev2", 2, DT_REG },

> +};

> +static const size_t nfiles = sizeof (filesystem) / sizeof (filesystem [0]);

> +

> +typedef struct

> +{

> +  int level;

> +  int idx;

> +  struct dirent d;

> +  char room_for_dirent[NAME_MAX];

> +} my_DIR;

> +

> +static long int

> +find_file (const char *s)

> +{

> +  int level = 1;

> +  long int idx = 0;

> +

> +  while (s[0] == '/')

> +    {

> +      if (s[1] == '\0')

> +	{

> +	  s = ".";

> +	  break;

> +	}

> +      ++s;

> +    }

> +

> +  if (strcmp (s, ".") == 0)

> +    return 0;

> +

> +  if (s[0] == '.' && s[1] == '/')

> +    s += 2;

> +

> +  while (*s != '\0')

> +    {

> +      char *endp = strchrnul (s, '/');

> +

> +      while (idx < nfiles && filesystem[idx].level >= level)

> +	{

> +	  if (filesystem[idx].level == level

> +	      && memcmp (s, filesystem[idx].name, endp - s) == 0

> +	      && filesystem[idx].name[endp - s] == '\0')

> +	    break;

> +	  ++idx;

> +	}

> +

> +      if (idx == nfiles || filesystem[idx].level < level)

> +	{

> +	  errno = ENOENT;

> +	  return -1;

> +	}

> +

> +      if (*endp == '\0')

> +	return idx + 1;

> +

> +      if (filesystem[idx].type != DT_DIR

> +	  && (idx + 1 >= nfiles

> +	      || filesystem[idx].level >= filesystem[idx + 1].level))

> +	{

> +	  errno = ENOTDIR;

> +	  return -1;

> +	}

> +

> +      ++idx;

> +

> +      s = endp + 1;

> +      ++level;

> +    }

> +

> +  errno = ENOENT;

> +  return -1;

> +}

> +

> +static void *

> +my_opendir (const char *s)

> +{

> +  long int idx = find_file (s);

> +  if (idx == -1 || filesystem[idx].type != DT_DIR)

> +    return NULL;

> +

> +  my_DIR *dir = malloc (sizeof (my_DIR));

> +  if (dir == NULL)

> +    FAIL_EXIT1 ("cannot allocate directory handle");

> +

> +  dir->level = filesystem[idx].level;

> +  dir->idx = idx;

> +

> +  return dir;

> +}

> +

> +static struct dirent *

> +my_readdir (void *gdir)

> +{

> +  my_DIR *dir = gdir;

> +

> +  if (dir->idx == -1)

> +    return NULL;

> +

> +  while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)

> +    ++dir->idx;

> +

> +  if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)

> +    {

> +      dir->idx = -1;

> +      return NULL;

> +    }

> +

> +  dir->d.d_ino = 1;		/* glob should not skip this entry.  */

> +

> +#ifdef _DIRENT_HAVE_D_TYPE

> +  dir->d.d_type = filesystem[dir->idx].type;

> +#endif

> +

> +  strcpy (dir->d.d_name, filesystem[dir->idx].name);

> +

> +  ++dir->idx;

> +

> +  return &dir->d;

> +}

> +

> +static void

> +my_closedir (void *dir)

> +{

> +  free (dir);

> +}

> +

> +static int

> +my_stat (const char *name, struct stat *st)

> +{

> +  stat_called = true;

> +

> +  long int idx = find_file (name);

> +  if (idx == -1)

> +    return -1;

> +

> +  memset (st, '\0', sizeof (*st));

> +

> +  if (filesystem[idx].type == DT_UNKNOWN)

> +    st->st_mode = DTTOIF (idx + 1 < nfiles

> +			  && filesystem[idx].level < filesystem[idx + 1].level

> +			  ? DT_DIR : DT_REG) | 0777;

> +  else

> +    st->st_mode = DTTOIF (filesystem[idx].type) | 0777;

> +  return 0;

> +}

> +

> +static int

> +my_lstat (const char *name, struct stat *st)

> +{

> +  lstat_called = true;

> +

> +  long int idx = find_file (name);

> +  if (idx == -1)

> +    return -1;

> +

> +  memset (st, '\0', sizeof (*st));

> +

> +  if (filesystem[idx].type == DT_UNKNOWN)

> +    st->st_mode = DTTOIF (idx + 1 < nfiles

> +			  && filesystem[idx].level < filesystem[idx + 1].level

> +			  ? DT_DIR : DT_REG) | 0777;

> +  else

> +    st->st_mode = DTTOIF (filesystem[idx].type) | 0777;

> +  return 0;

> +}

> +

> +static int

> +do_test (void)

> +{

> +  glob_t gl;

> +

> +  memset (&gl, '\0', sizeof (gl));

> +

> +  gl.gl_closedir = my_closedir;

> +  gl.gl_readdir = my_readdir;

> +  gl.gl_opendir = my_opendir;

> +  gl.gl_lstat = my_lstat;

> +  gl.gl_stat = my_stat;

> +

> +  int flags = GLOB_ALTDIRFUNC;

> +

> +  stat_called = false;

> +  lstat_called = false;

> +

> +  TEST_VERIFY_EXIT (glob ("*/file1lev2", flags, NULL, &gl) == 0);

> +  TEST_VERIFY_EXIT (gl.gl_pathc == 1);

> +  TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], "dir1lev1/file1lev2") == 0);

> +

> +  TEST_VERIFY_EXIT (stat_called == true);

> +  TEST_VERIFY_EXIT (lstat_called == false);

> +

> +  return 0;

> +}

> +

> +#else /* TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_27)  */

> +

> +static int

> +do_test (void)

> +{ 

> +  return 77;

> +}

> +#endif

> +

> +#include <support/test-driver.c>

> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist

> index 81e4fe9..e7438c5 100644

> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist

> @@ -2103,3 +2103,6 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

> diff --git a/sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c b/sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c

> new file mode 100644

> index 0000000..a76471d

> --- /dev/null

> +++ b/sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c

> @@ -0,0 +1,2 @@

> +#define GLOB_LSTAT_VERSION GLIBC_2_1

> +#include <sysdeps/unix/sysv/linux/glob-lstat-compat.c>

> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist

> index fab7331..4836ea0 100644

> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist

> @@ -2014,6 +2014,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/alpha/oldglob.c b/sysdeps/unix/sysv/linux/alpha/oldglob.c

> index 988c92b..b54624c 100644

> --- a/sysdeps/unix/sysv/linux/alpha/oldglob.c

> +++ b/sysdeps/unix/sysv/linux/alpha/oldglob.c

> @@ -59,7 +59,9 @@ __old_glob (const char *pattern, int flags,

>    correct.gl_closedir = pglob->gl_closedir;

>    correct.gl_readdir = pglob->gl_readdir;

>    correct.gl_opendir = pglob->gl_opendir;

> -  correct.gl_lstat = pglob->gl_lstat;

> +  /* Set gl_lstat and gl_stat for both gl_stat for compatibility with old

> +     implementation that did not follow dangling symlinks.  */

> +  correct.gl_lstat = pglob->gl_stat;

>    correct.gl_stat = pglob->gl_stat;

>  

>    result = glob (pattern, flags, errfunc, &correct);

> @@ -72,7 +74,7 @@ __old_glob (const char *pattern, int flags,

>    pglob->gl_closedir = correct.gl_closedir;

>    pglob->gl_readdir = correct.gl_readdir;

>    pglob->gl_opendir = correct.gl_opendir;

> -  pglob->gl_lstat = correct.gl_lstat;

> +  /* Only need to restore gl_stat.  */

>    pglob->gl_stat = correct.gl_stat;

>  

>    return result;

> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist

> index d2a206a..5b70e1b 100644

> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist

> @@ -104,6 +104,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.4 GLIBC_2.4 A

>  GLIBC_2.4 _Exit F

>  GLIBC_2.4 _IO_2_1_stderr_ D 0xa0

> diff --git a/sysdeps/unix/sysv/linux/alpha/glob.c b/sysdeps/unix/sysv/linux/glob-lstat-compat.c

> similarity index 50%

> rename from sysdeps/unix/sysv/linux/alpha/glob.c

> rename to sysdeps/unix/sysv/linux/glob-lstat-compat.c

> index 1b813c1..9867e2f 100644

> --- a/sysdeps/unix/sysv/linux/alpha/glob.c

> +++ b/sysdeps/unix/sysv/linux/glob-lstat-compat.c

> @@ -1,4 +1,6 @@

> -/* Copyright (C) 1998-2017 Free Software Foundation, Inc.

> +/* Compat glob which does not use gl_lstat for GLOB_ALTDIRFUNC.

> +   Linux version which handles LFS when required.

> +   Copyright (C) 2017 Free Software Foundation, Inc.

>     This file is part of the GNU C Library.

>  

>     The GNU C Library is free software; you can redistribute it and/or

> @@ -12,36 +14,34 @@

>     Lesser General Public License for more details.

>  

>     You should have received a copy of the GNU Lesser General Public

> -   License along with the GNU C Library.  If not, see

> +   License along with the GNU C Library; if not, see

>     <http://www.gnu.org/licenses/>.  */

>  

> -#define glob64 __no_glob64_decl

> -#define globfree64 __no_globfree64_decl

> -

> -#include <sys/types.h>

> -#include <glob.h>

> +#include <sys/stat.h>

> +#include <kernel_stat.h>

>  #include <shlib-compat.h>

>  

> -/* For Linux/Alpha we have to make the glob symbols versioned.  */

> -#define glob(pattern, flags, errfunc, pglob) \

> -  __new_glob (pattern, flags, errfunc, pglob)

> -#define globfree(pglob) \

> -  __new_globfree (pglob)

> +#define glob64 __no_glob64_decl

> +#include <glob.h>

> +#undef glob64

>  

> -/* We need prototypes for these new names.  */

> -extern int __new_glob (const char *__pattern, int __flags,

> -		       int (*__errfunc) (const char *, int),

> -		       glob_t *__pglob);

> -extern void __new_globfree (glob_t *__pglob);

> +#define __glob __glob_lstat_compat

>  

> -#include <posix/glob.c>

> +#define GLOB_ATTRIBUTE attribute_compat_text_section

>  

> -#undef glob

> -#undef globfree

> -#undef glob64

> -#undef globfree64

> +/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */

> +#define GLOB_NO_LSTAT

>  

> -versioned_symbol (libc, __new_glob, glob, GLIBC_2_1);

> -libc_hidden_ver (__new_glob, glob)

> +#include <posix/glob.c>

>  

> -weak_alias (__new_glob, glob64)

> +#ifndef GLOB_LSTAT_VERSION

> +# define GLOB_LSTAT_VERSION GLIBC_2_0

> +#endif

> +

> +#if SHLIB_COMPAT(libc, GLOB_LSTAT_VERSION, GLIBC_2_27)

> +compat_symbol (libc, __glob_lstat_compat, glob, GLOB_LSTAT_VERSION);

> +# if XSTAT_IS_XSTAT64

> +strong_alias (__glob_lstat_compat, __glob64_lstat_compat)

> +compat_symbol (libc, __glob64_lstat_compat, glob64, GLOB_LSTAT_VERSION);

> +# endif

> +#endif

> diff --git a/sysdeps/unix/sysv/linux/glob.c b/sysdeps/unix/sysv/linux/glob.c

> index 057ae7f..e354799 100644

> --- a/sysdeps/unix/sysv/linux/glob.c

> +++ b/sysdeps/unix/sysv/linux/glob.c

> @@ -20,9 +20,12 @@

>  #include <kernel_stat.h>

>  

>  #define glob64 __no_glob64_decl

> +#define __glob64 __no___glob64_decl

>  #include <posix/glob.c>

>  #undef glob64

> +#undef __glob64

>  

>  #if XSTAT_IS_XSTAT64

> -weak_alias (glob, glob64)

> +strong_alias (__glob, __glob64)

> +versioned_symbol (libc, __glob64, glob64, GLIBC_2_27);

>  #endif

> diff --git a/sysdeps/unix/sysv/linux/glob64-lstat-compat.c b/sysdeps/unix/sysv/linux/glob64-lstat-compat.c

> new file mode 100644

> index 0000000..f4e468d

> --- /dev/null

> +++ b/sysdeps/unix/sysv/linux/glob64-lstat-compat.c

> @@ -0,0 +1,51 @@

> +/* Compat glob which does not use gl_lstat for GLOB_ALTDIRFUNC.

> +   Linux version which handles LFS when required.

> +   Copyright (C) 2017 Free Software Foundation, Inc.

> +   This file is part of the GNU C Library.

> +

> +   The GNU C Library is free software; you can redistribute it and/or

> +   modify it under the terms of the GNU Lesser General Public

> +   License as published by the Free Software Foundation; either

> +   version 2.1 of the License, or (at your option) any later version.

> +

> +   The GNU C Library 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

> +   Lesser General Public License for more details.

> +

> +   You should have received a copy of the GNU Lesser General Public

> +   License along with the GNU C Library; if not, see

> +   <http://www.gnu.org/licenses/>.  */

> +

> +#include <sys/stat.h>

> +#include <kernel_stat.h>

> +

> +#if !XSTAT_IS_XSTAT64

> +# include <glob.h>

> +# include <dirent.h>

> +# include <sys/stat.h>

> +# include <shlib-compat.h>

> +

> +# define dirent dirent64

> +# define __readdir(dirp) __readdir64 (dirp)

> +

> +# define glob_t glob64_t

> +# define __glob __glob64_lstat_compat

> +# define globfree globfree64

> +

> +# undef stat

> +# define stat stat64

> +

> +# define COMPILE_GLOB64	1

> +

> +# define GLOB_ATTRIBUTE attribute_compat_text_section

> +

> +/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */

> +# define GLOB_NO_LSTAT

> +

> +# include <posix/glob.c>

> +

> +# if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_27)

> +compat_symbol (libc, __glob64_lstat_compat, glob64, GLIBC_2_2);

> +# endif

> +#endif /* XSTAT_IS_XSTAT64  */

> diff --git a/sysdeps/unix/sysv/linux/glob64.c b/sysdeps/unix/sysv/linux/glob64.c

> index 428bbac..0189d1c 100644

> --- a/sysdeps/unix/sysv/linux/glob64.c

> +++ b/sysdeps/unix/sysv/linux/glob64.c

> @@ -28,8 +28,7 @@

>  # define __readdir(dirp) __readdir64 (dirp)

>  

>  # define glob_t glob64_t

> -# define glob(pattern, flags, errfunc, pglob) \

> -  __glob64 (pattern, flags, errfunc, pglob)

> +# define __glob __glob64

>  # define globfree(pglob) globfree64 (pglob)

>  

>  # undef stat

> @@ -39,13 +38,13 @@

>  

>  # include <posix/glob.c>

>  

> -# include "shlib-compat.h"

> +# include <shlib-compat.h>

>  

>  # ifdef GLOB_NO_OLD_VERSION

>  strong_alias (__glob64, glob64)

>  libc_hidden_def (glob64)

>  # else

> -versioned_symbol (libc, __glob64, glob64, GLIBC_2_2);

> +versioned_symbol (libc, __glob64, glob64, GLIBC_2_27);

>  libc_hidden_ver (__glob64, glob64)

>  # endif

>  #endif /* XSTAT_IS_XSTAT64  */

> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist

> index 24bb730..6a2500a 100644

> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist

> @@ -1868,6 +1868,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist

> index 12e77bd..9ab4e36 100644

> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist

> @@ -2033,6 +2033,9 @@ GLIBC_2.26 strtof128 F

>  GLIBC_2.26 strtof128_l F

>  GLIBC_2.26 wcstof128 F

>  GLIBC_2.26 wcstof128_l F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist

> index 62b67b8..81bb623 100644

> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist

> @@ -1897,6 +1897,9 @@ GLIBC_2.26 strtof128 F

>  GLIBC_2.26 strtof128_l F

>  GLIBC_2.26 wcstof128 F

>  GLIBC_2.26 wcstof128_l F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist

> index b594ebd..5a33b57 100644

> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist

> @@ -105,6 +105,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.4 GLIBC_2.4 A

>  GLIBC_2.4 _Exit F

>  GLIBC_2.4 _IO_2_1_stderr_ D 0x98

> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist

> index a36739d..50a86e7 100644

> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist

> @@ -1982,6 +1982,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist

> index 16aa254..250ef30 100644

> --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist

> @@ -2103,3 +2103,6 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist

> index 907ab33..87a1dc4 100644

> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist

> @@ -1957,6 +1957,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist

> index 36ee235..f2b35f2 100644

> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist

> @@ -1955,6 +1955,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist

> index 783aa73..e119842 100644

> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist

> @@ -1953,6 +1953,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist

> index e1275df..67f10f5 100644

> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist

> @@ -1948,6 +1948,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist

> index be25228..c599dd9 100644

> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist

> @@ -2144,3 +2144,6 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

> diff --git a/sysdeps/unix/sysv/linux/oldglob.c b/sysdeps/unix/sysv/linux/oldglob.c

> index 5402450..a034c2d 100644

> --- a/sysdeps/unix/sysv/linux/oldglob.c

> +++ b/sysdeps/unix/sysv/linux/oldglob.c

> @@ -21,7 +21,7 @@ libc_hidden_proto (__old_glob64);

>  #define __readdir(dirp) __old_readdir64 (dirp)

>  

>  #define glob_t glob64_t

> -#define glob(pattern, flags, errfunc, pglob) \

> +#define __glob(pattern, flags, errfunc, pglob) \

>    __old_glob64 (pattern, flags, errfunc, pglob)

>  #define globfree(pglob) globfree64(pglob)

>  

> @@ -33,6 +33,9 @@ libc_hidden_proto (__old_glob64);

>  #undef __stat

>  #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)

>  

> +/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */

> +#define GLOB_NO_LSTAT

> +

>  #define GLOB_ATTRIBUTE attribute_compat_text_section

>  

>  #include <posix/glob.c>

> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist

> index e213895..385409a 100644

> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist

> @@ -1986,6 +1986,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist

> index d25aefd..e99cb45 100644

> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist

> @@ -1991,6 +1991,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist

> index 51a8d19..173672a 100644

> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist

> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist

> @@ -2198,3 +2198,6 @@ GLIBC_2.26 strtof128 F

>  GLIBC_2.26 strtof128_l F

>  GLIBC_2.26 wcstof128 F

>  GLIBC_2.26 wcstof128_l F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist

> index 5eb056b..8a65443 100644

> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist

> @@ -105,6 +105,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 _Exit F

>  GLIBC_2.3 _IO_2_1_stderr_ D 0xe0

> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist

> index 63d33e8..271eccc 100644

> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist

> @@ -1986,6 +1986,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist

> index b1b2b29..8b96e16 100644

> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist

> @@ -1887,6 +1887,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist

> index f3a70a0..0f840e6 100644

> --- a/sysdeps/unix/sysv/linux/sh/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist

> @@ -1872,6 +1872,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist

> index 8c4c2e5..7f7449f 100644

> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist

> @@ -1978,6 +1978,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist

> index 1653164..a50485e 100644

> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist

> @@ -1916,6 +1916,9 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist

> index 41647d4..38a96d3 100644

> --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist

> @@ -2110,3 +2110,6 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

> diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist

> index 1088923..572b917 100644

> --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist

> @@ -2110,3 +2110,6 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

> diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist

> index 41647d4..38a96d3 100644

> --- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist

> @@ -2110,3 +2110,6 @@ GLIBC_2.26 preadv64v2 F

>  GLIBC_2.26 pwritev2 F

>  GLIBC_2.26 pwritev64v2 F

>  GLIBC_2.26 reallocarray F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist

> index 8bff2b2..b83d25c 100644

> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist

> @@ -1874,6 +1874,9 @@ GLIBC_2.26 strtof128 F

>  GLIBC_2.26 strtof128_l F

>  GLIBC_2.26 wcstof128 F

>  GLIBC_2.26 wcstof128_l F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>  GLIBC_2.3 GLIBC_2.3 A

>  GLIBC_2.3 __ctype_b_loc F

>  GLIBC_2.3 __ctype_tolower_loc F

> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist

> index d91a038..cba1d59 100644

> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist

> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist

> @@ -2117,3 +2117,6 @@ GLIBC_2.26 strtof128 F

>  GLIBC_2.26 strtof128_l F

>  GLIBC_2.26 wcstof128 F

>  GLIBC_2.26 wcstof128_l F

> +GLIBC_2.27 GLIBC_2.27 A

> +GLIBC_2.27 glob F

> +GLIBC_2.27 glob64 F

>
Paul Eggert Sept. 22, 2017, 9:43 p.m. UTC | #6
On 09/22/2017 06:02 AM, Adhemerval Zanella wrote:
> +		       ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC))

> +		       | GLOB_NOSORT | GLOB_ONLYDIR),


The indenting is not quite right here: the "|" should be under the 2nd 
"(" in the previous line, not under the 1st.

> +	      result = __glob (onealt,

> +			       ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))

> +			       | GLOB_APPEND), errfunc, pglob);


As long as we're changing indenting anyway, we should fix the indenting 
here to match the usual GNU style. Something like this:

               result = __glob (onealt,
                                ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
                                 | GLOB_APPEND),
                                errfunc, pglob);

Other than these minor indenting things it looks OK. glibc's glob.c is 
wrongly indented elsewhere, but that can be fixed separately.

Proposed corresponding gnulib patch attached; it would keep gnulib 
glob.c in sync with glibc's, except for whitespace and the https: thing. 
CC'ing this to bug-gnulib.
From b5e099566022dd7390afe58cf84e5b991683776c Mon Sep 17 00:00:00 2001
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>

Date: Fri, 22 Sep 2017 14:41:52 -0700
Subject: [PATCH] glob: add compat to not follow dangling symlinks

Merged from this proposed change to glibc:
https://sourceware.org/ml/libc-alpha/2017-09/msg00848.html
* lib/glob.c [_LIBC]: Include <shlib-compat.h>.
(__glob, GLOB_ATTRIBUTE) [!_LIBC]: New macros.
(glob_lstat): New function.
(GL_LSTAT, LSTAT64): New macros.
(glob): Rename to __glob and add versioned symbol to 2.27.
(glob_in_dir): Use glob_lstat.
---
 ChangeLog  | 12 +++++++++++
 lib/glob.c | 70 +++++++++++++++++++++++++++++++++++++++-----------------------
 2 files changed, 56 insertions(+), 26 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 82ecf539a..313d359a0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2017-09-22  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+
+	glob: add compat to not follow dangling symlinks
+	Merged from this proposed change to glibc:
+	https://sourceware.org/ml/libc-alpha/2017-09/msg00848.html
+	* lib/glob.c [_LIBC]: Include <shlib-compat.h>.
+	(__glob, GLOB_ATTRIBUTE) [!_LIBC]: New macros.
+	(glob_lstat): New function.
+	(GL_LSTAT, LSTAT64): New macros.
+	(glob): Rename to __glob and add versioned symbol to 2.27.
+	(glob_in_dir): Use glob_lstat.
+
 2017-09-21  Paul Eggert  <eggert@cs.ucla.edu>
 
 	mktime: port to OpenVMS
diff --git a/lib/glob.c b/lib/glob.c
index 2a5e6642e..a9b519c2f 100644
--- a/lib/glob.c
+++ b/lib/glob.c
@@ -57,7 +57,9 @@
 # endif
 # define struct_stat64          struct stat64
 # define FLEXIBLE_ARRAY_MEMBER
+# include <shlib-compat.h>
 #else /* !_LIBC */
+# define __glob                 glob
 # define __getlogin_r(buf, len) getlogin_r (buf, len)
 # define __lstat64(fname, buf)  lstat (fname, buf)
 # define __stat64(fname, buf)   stat (fname, buf)
@@ -179,6 +181,29 @@ convert_dirent64 (const struct dirent64 *source)
     ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)
 #endif
 
+static int
+glob_lstat (glob_t *pglob, int flags, const char *fullname)
+{
+/* Use on glob-lstat-compat.c to provide a compat symbol which does not
+   use lstat / gl_lstat.  */
+#ifdef GLOB_NO_LSTAT
+# define GL_LSTAT gl_stat
+# define LSTAT64 __stat64
+#else
+# define GL_LSTAT gl_lstat
+# define LSTAT64 __lstat64
+#endif
+
+  union
+  {
+    struct stat st;
+    struct_stat64 st64;
+  } ust;
+  return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)
+          ? pglob->GL_LSTAT (fullname, &ust.st)
+          : LSTAT64 (fullname, &ust.st64));
+}
+
 /* Set *R = A + B.  Return true if the answer is mathematically
    incorrect due to overflow; in this case, *R is the low order
    bits of the correct answer.  */
@@ -248,6 +273,9 @@ next_brace_sub (const char *cp, int flags)
   return *cp != '\0' ? cp : NULL;
 }
 
+#ifndef GLOB_ATTRIBUTE
+# define GLOB_ATTRIBUTE
+#endif
 
 /* Do glob searching for PATTERN, placing results in PGLOB.
    The bits defined above may be set in FLAGS.
@@ -258,11 +286,9 @@ next_brace_sub (const char *cp, int flags)
    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
    Otherwise, 'glob' returns zero.  */
 int
-#ifdef GLOB_ATTRIBUTE
 GLOB_ATTRIBUTE
-#endif
-glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
-      glob_t *pglob)
+__glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
+        glob_t *pglob)
 {
   const char *filename;
   char *dirname = NULL;
@@ -343,7 +369,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
       if (begin != NULL)
         {
           /* Allocate working buffer large enough for our work.  Note that
-             we have at least an opening and closing brace.  */
+            we have at least an opening and closing brace.  */
           size_t firstc;
           char *alt_start;
           const char *p;
@@ -406,9 +432,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
               /* Construct the new glob expression.  */
               mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
 
-              result = glob (onealt,
-                             ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
-                              | GLOB_APPEND), errfunc, pglob);
+              result = __glob (onealt,
+                               ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
+                                | GLOB_APPEND),
+                               errfunc, pglob);
 
               /* If we got an error, return it.  */
               if (result && result != GLOB_NOMATCH)
@@ -499,7 +526,6 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
     {
       char *newp;
       dirlen = filename - pattern;
-
 #if defined __MSDOS__ || defined WINDOWS32
       if (*filename == ':'
           || (filename > pattern + 1 && filename[-1] == ':'))
@@ -558,7 +584,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                   flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
                 }
             }
-          int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
+          int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob);
           if (val == 0)
             pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
                                | (flags & GLOB_MARK));
@@ -932,11 +958,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
           dirs.gl_lstat = pglob->gl_lstat;
         }
 
-      status = glob (dirname,
-                     ((flags & (GLOB_ERR | GLOB_NOESCAPE
-                                | GLOB_ALTDIRFUNC))
-                      | GLOB_NOSORT | GLOB_ONLYDIR),
-                     errfunc, &dirs);
+      status = __glob (dirname,
+                       ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC))
+                        | GLOB_NOSORT | GLOB_ONLYDIR),
+                       errfunc, &dirs);
       if (status != 0)
         {
           if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
@@ -1134,8 +1159,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 
   return retval;
 }
-#if defined _LIBC && !defined glob
-libc_hidden_def (glob)
+#if defined _LIBC && !defined __glob
+versioned_symbol (libc, __glob, glob, GLIBC_2_27);
+libc_hidden_ver (__glob, glob)
 #endif
 
 
@@ -1251,11 +1277,6 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
     }
   else if (meta == GLOBPAT_NONE)
     {
-      union
-      {
-        struct stat st;
-        struct_stat64 st64;
-      } ust;
       size_t patlen = strlen (pattern);
       size_t fullsize;
       bool alloca_fullname
@@ -1274,10 +1295,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
       mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
                         "/", 1),
                pattern, patlen + 1);
-      if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
-            ? (*pglob->gl_lstat) (fullname, &ust.st)
-            : __lstat64 (fullname, &ust.st64))
-           == 0)
+      if (glob_lstat (pglob, flags, fullname) == 0
           || errno == EOVERFLOW)
         /* We found this file to be existing.  Now tell the rest
            of the function to copy this name into the result.  */
-- 
2.13.5
Adhemerval Zanella Sept. 25, 2017, 5:03 p.m. UTC | #7
On 22/09/2017 18:43, Paul Eggert wrote:
> On 09/22/2017 06:02 AM, Adhemerval Zanella wrote:

>> +               ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC))

>> +               | GLOB_NOSORT | GLOB_ONLYDIR),

>

> The indenting is not quite right here: the "|" should be under the 2nd

> "(" in the previous line, not under the 1st.

Ack.

>

>> +          result = __glob (onealt,

>> +                   ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))

>> +                   | GLOB_APPEND), errfunc, pglob);

>

> As long as we're changing indenting anyway, we should fix the

> indenting here to match the usual GNU style. Something like this:

>

>               result = __glob (onealt,

>                                ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))

>                                 | GLOB_APPEND),

>                                errfunc, pglob);


Ack.

>

> Other than these minor indenting things it looks OK. glibc's glob.c is

> wrongly indented elsewhere, but that can be fixed separately.

>

> Proposed corresponding gnulib patch attached; it would keep gnulib

> glob.c in sync with glibc's, except for whitespace and the https:

> thing. CC'ing this to bug-gnulib.

I will commit both patch shortly, thanks for the review.
Andreas Schwab Sept. 26, 2017, 3:29 p.m. UTC | #8
Current version of make won't build against this (undefined reference to
__alloca from included glob sources).

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."
Adhemerval Zanella Sept. 26, 2017, 5:24 p.m. UTC | #9
On 26/09/2017 08:29, Andreas Schwab wrote:
> Current version of make won't build against this (undefined reference to

> __alloca from included glob sources).

>

> Andreas.

>

I am not very familiar of the process to incorporate gnulib code
in external projects, but I see other possible issues that would
need to be fixed as well:

  * FLEXIBLE_ARRAY_MEMBER definition for !__LIBC.
  * __glob_pattern_type duplicated prototype.
  * __set_errno and mempcpy definition.

I could build gnumake with forced internal glob implementation
(make_cv_sys_gnu_glob=no) with the patch following patch.  Looking
gnulib I am not sure if the correct way to use mempcpy for !_LIBC.

---

diff --git a/posix/glob.c b/posix/glob.c
index 98122dac88..31e3aba4dd 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -65,11 +65,15 @@
 # define __stat64(fname, buf)   stat (fname, buf)
 # define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)
 # define struct_stat64          struct stat
-# ifndef __MVS__
-#  define __alloca              alloca
-# endif
+# define __alloca               alloca
 # define __readdir              readdir
+# define FLEXIBLE_ARRAY_MEMBER 0
 # define COMPILE_GLOB64
+static inline void *
+mempcpy (void *dest, const void *src, size_t n)
+{
+  return memcpy (dest, src, n) + n;
+}
 #endif /* _LIBC */
 
 #include <fnmatch.h>
@@ -230,8 +234,6 @@ glob_use_alloca (size_t alloca_used, size_t len)
 static int glob_in_dir (const char *pattern, const char *directory,
                        int flags, int (*errfunc) (const char *, int),
                        glob_t *pglob, size_t alloca_used);
-extern int __glob_pattern_type (const char *pattern, int quote)
-    attribute_hidden;
 
 static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL;
 static int collated_compare (const void *, const void *) __THROWNL;
Paul Eggert Sept. 26, 2017, 6:10 p.m. UTC | #10
On 09/26/2017 10:24 AM, Adhemerval Zanella wrote:
> I see other possible issues that would

> need to be fixed as well:

>

>    * FLEXIBLE_ARRAY_MEMBER definition for !__LIBC.

>    * __glob_pattern_type duplicated prototype.

>    * __set_errno and mempcpy definition.


Thanks for reporting the duplicated prototype; that is a portability 
issue that I fixed in Gnulib by applying the attached patch to Gnulib 
master. Gnulib glob.c already handles FLEXIBLE_ARRAY_MEMBER, 
__set_errno, and mempcpy automatically, because its 'glob' module has 
the modules 'flexmember', 'libc-config', and 'mempcpy' as prerequisites, 
and these supply the necessary definitions.

You can test Gnulib glob.c's portabililty by running this shell command 
in Gnulib's top directory:

./gnulib-tool --create-testdir --dir foo glob

and then by copying the newly-created 'foo' directory to the platform of 
your choice and running './configure; make check' there.

Gnu Make does not use Gnulib. Instead, it ships an old version of 
glob.c, which it took directly from glibc in 1999; this all predates 
Gnulib. If GNU Make ever updates to a more-modern glob.c I suggest that 
it use the Gnulib glob module, along with that module's prerequisites. I 
could help do that, if the GNU Make maintainer wants to go that route. 
[I'll CC: this to bug-make to give its maintainer a heads-up about this 
libc-alpha discussion, which can be followed from here:

https://sourceware.org/ml/libc-alpha/2017-09/msg00972.html

]

> I could build gnumake with forced internal glob implementation

> (make_cv_sys_gnu_glob=no) with the patch following patch.  Looking

> gnulib I am not sure if the correct way to use mempcpy for !_LIBC.


Sorry, but I'm confused by that patch (quoted below). It is a patch to 
glibc, so at first I assumed that you applied it to a copy of the glibc 
source, built a new glibc with it, and then used the newly-built glibc 
to configure and build GNU Make 4.2.1.  But that assumption cannot be 
right, since the patch modifies only code that is unused when building 
glibc. And one cannot simply copy current or patched glibc posix/glob.c 
into make's lib/glob.c, as (among other things) glibc's posix/glob.c 
includes <flexmember.h> when compiled outside of glibc, and GNU Make 
does not have that include file. So how did you use this patch?

> diff --git a/posix/glob.c b/posix/glob.c

> index 98122dac88..31e3aba4dd 100644

> --- a/posix/glob.c

> +++ b/posix/glob.c

> @@ -65,11 +65,15 @@

>   # define __stat64(fname, buf)   stat (fname, buf)

>   # define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)

>   # define struct_stat64          struct stat

> -# ifndef __MVS__

> -#  define __alloca              alloca

> -# endif

> +# define __alloca               alloca

>   # define __readdir              readdir

> +# define FLEXIBLE_ARRAY_MEMBER 0

>   # define COMPILE_GLOB64

> +static inline void *

> +mempcpy (void *dest, const void *src, size_t n)

> +{

> +  return memcpy (dest, src, n) + n;

> +}

>   #endif /* _LIBC */

>   

>   #include <fnmatch.h>

> @@ -230,8 +234,6 @@ glob_use_alloca (size_t alloca_used, size_t len)

>   static int glob_in_dir (const char *pattern, const char *directory,

>                          int flags, int (*errfunc) (const char *, int),

>                          glob_t *pglob, size_t alloca_used);

> -extern int __glob_pattern_type (const char *pattern, int quote)

> -    attribute_hidden;

>   

>   static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL;

>   static int collated_compare (const void *, const void *) __THROWNL;

>

>
From 3869eefa5b430ec8b23e71b5f150c6a7d8aacb50 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>

Date: Tue, 26 Sep 2017 11:02:26 -0700
Subject: [PATCH] glob: remove bogus extern decl

* lib/glob.c (__glob_pattern_type): Remove now-spurious
extern declaration.  Problem reported by Adhemerval Zanella in:
https://sourceware.org/ml/libc-alpha/2017-09/msg00972.html
---
 ChangeLog  | 7 +++++++
 lib/glob.c | 3 ---
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 4585cf12b..440b90686 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2017-09-26  Paul Eggert  <eggert@cs.ucla.edu>
+
+	glob: remove bogus extern decl
+	* lib/glob.c (__glob_pattern_type): Remove now-spurious
+	extern declaration.  Problem reported by Adhemerval Zanella in:
+	https://sourceware.org/ml/libc-alpha/2017-09/msg00972.html
+
 2017-09-25  Paul Eggert  <eggert@cs.ucla.edu>
 
 	uniname/uniname-tests: integer overflow fix
diff --git a/lib/glob.c b/lib/glob.c
index 2a5e6642e..9d677d982 100644
--- a/lib/glob.c
+++ b/lib/glob.c
@@ -205,9 +205,6 @@ glob_use_alloca (size_t alloca_used, size_t len)
 static int glob_in_dir (const char *pattern, const char *directory,
                         int flags, int (*errfunc) (const char *, int),
                         glob_t *pglob, size_t alloca_used);
-extern int __glob_pattern_type (const char *pattern, int quote)
-    attribute_hidden;
-
 static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL;
 static int collated_compare (const void *, const void *) __THROWNL;
 
-- 
2.13.5
Adhemerval Zanella Sept. 26, 2017, 9:40 p.m. UTC | #11
On 26/09/2017 11:10, Paul Eggert wrote:
> On 09/26/2017 10:24 AM, Adhemerval Zanella wrote:

>> I see other possible issues that would

>> need to be fixed as well:

>>

>>    * FLEXIBLE_ARRAY_MEMBER definition for !__LIBC.

>>    * __glob_pattern_type duplicated prototype.

>>    * __set_errno and mempcpy definition.

>

> Thanks for reporting the duplicated prototype; that is a portability

> issue that I fixed in Gnulib by applying the attached patch to Gnulib

> master. Gnulib glob.c already handles FLEXIBLE_ARRAY_MEMBER,

> __set_errno, and mempcpy automatically, because its 'glob' module has

> the modules 'flexmember', 'libc-config', and 'mempcpy' as

> prerequisites, and these supply the necessary definitions.

Thanks, I will sync this change with glibc.

>

> You can test Gnulib glob.c's portabililty by running this shell

> command in Gnulib's top directory:

>

> ./gnulib-tool --create-testdir --dir foo glob

>

> and then by copying the newly-created 'foo' directory to the platform

> of your choice and running './configure; make check' there.

>

> Gnu Make does not use Gnulib. Instead, it ships an old version of

> glob.c, which it took directly from glibc in 1999; this all predates

> Gnulib. If GNU Make ever updates to a more-modern glob.c I suggest

> that it use the Gnulib glob module, along with that module's

> prerequisites. I could help do that, if the GNU Make maintainer wants

> to go that route. [I'll CC: this to bug-make to give its maintainer a

> heads-up about this libc-alpha discussion, which can be followed from

> here:

>

> https://sourceware.org/ml/libc-alpha/2017-09/msg00972.html


Besides update GNU make glob implementation I think it should also update
its configure.ac to accept not only _GNU_GLOB_INTERFACE_VERSION equal
to 1, but also _GNU_GLOB_INTERFACE_VERSION to 2 now that your suggestion [1]
has been fixed.

[1] http://lists.gnu.org/archive/html/bug-make/2017-09/msg00014.html

>

> ]

>

>> I could build gnumake with forced internal glob implementation

>> (make_cv_sys_gnu_glob=no) with the patch following patch.  Looking

>> gnulib I am not sure if the correct way to use mempcpy for !_LIBC.

>

> Sorry, but I'm confused by that patch (quoted below). It is a patch to

> glibc, so at first I assumed that you applied it to a copy of the

> glibc source, built a new glibc with it, and then used the newly-built

> glibc to configure and build GNU Make 4.2.1.  But that assumption

> cannot be right, since the patch modifies only code that is unused

> when building glibc. And one cannot simply copy current or patched

> glibc posix/glob.c into make's lib/glob.c, as (among other things)

> glibc's posix/glob.c includes <flexmember.h> when compiled outside of

> glibc, and GNU Make does not have that include file. So how did you

> use this patch?

Sorry if I were not explicit, the patch is indeed against glibc and what
I did was
basically copy glob.c and all required files (flexmember.h and
glob_internal)
on glob folder. It is just a ad hoc way to verify if its build correctly.

>

>> diff --git a/posix/glob.c b/posix/glob.c

>> index 98122dac88..31e3aba4dd 100644

>> --- a/posix/glob.c

>> +++ b/posix/glob.c

>> @@ -65,11 +65,15 @@

>>   # define __stat64(fname, buf)   stat (fname, buf)

>>   # define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)

>>   # define struct_stat64          struct stat

>> -# ifndef __MVS__

>> -#  define __alloca              alloca

>> -# endif

>> +# define __alloca               alloca

>>   # define __readdir              readdir

>> +# define FLEXIBLE_ARRAY_MEMBER 0

>>   # define COMPILE_GLOB64

>> +static inline void *

>> +mempcpy (void *dest, const void *src, size_t n)

>> +{

>> +  return memcpy (dest, src, n) + n;

>> +}

>>   #endif /* _LIBC */

>>     #include <fnmatch.h>

>> @@ -230,8 +234,6 @@ glob_use_alloca (size_t alloca_used, size_t len)

>>   static int glob_in_dir (const char *pattern, const char *directory,

>>                          int flags, int (*errfunc) (const char *, int),

>>                          glob_t *pglob, size_t alloca_used);

>> -extern int __glob_pattern_type (const char *pattern, int quote)

>> -    attribute_hidden;

>>     static int prefix_array (const char *prefix, char **array, size_t

>> n) __THROWNL;

>>   static int collated_compare (const void *, const void *) __THROWNL;

>>

>>
Andreas Schwab Sept. 27, 2017, 8:07 a.m. UTC | #12
I can confirm that make works properly with the compat glob symbol.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."
diff mbox series

Patch

diff --git a/include/gnu-versions.h b/include/gnu-versions.h
index 40f2bfc..ce26254 100644
--- a/include/gnu-versions.h
+++ b/include/gnu-versions.h
@@ -45,7 +45,7 @@ 
 
 #define _GNU_OBSTACK_INTERFACE_VERSION	1 /* vs malloc/obstack.c */
 #define _GNU_REGEX_INTERFACE_VERSION	1 /* vs posix/regex.c */
-#define _GNU_GLOB_INTERFACE_VERSION	1 /* vs posix/glob.c */
+#define _GNU_GLOB_INTERFACE_VERSION	2 /* vs posix/glob.c */
 #define _GNU_GETOPT_INTERFACE_VERSION	2 /* vs posix/getopt.c and
 					     posix/getopt1.c */
 
diff --git a/posix/Makefile b/posix/Makefile
index 7188cba..203555a 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -46,6 +46,7 @@  routines :=								      \
 	getresuid getresgid setresuid setresgid				      \
 	pathconf sysconf fpathconf					      \
 	glob glob64 globfree globfree64 glob_pattern_p fnmatch regex	      \
+	glob-lstat-compat glob64-lstat-compat				      \
 	confstr								      \
 	getopt getopt1 							      \
 	sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax  \
@@ -95,7 +96,8 @@  tests		:= test-errno tstgetopt testfnm runtests runptests \
 		   tst-posix_fadvise tst-posix_fadvise64 \
 		   tst-sysconf-empty-chroot tst-glob_symlinks
 tests-internal	:= bug-regex5 bug-regex20 bug-regex33 \
-		   tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3
+		   tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \
+		   tst-glob_lstat_compat
 xtests		:= bug-ga2
 ifeq (yes,$(build-shared))
 test-srcs	:= globtest
diff --git a/posix/Versions b/posix/Versions
index bb481a5..65e9687 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -134,6 +134,9 @@  libc {
   GLIBC_2.11 {
     execvpe;
   }
+  GLIBC_2.27 {
+    glob; glob64;
+  }
   GLIBC_PRIVATE {
     __libc_fork; __libc_pread; __libc_pwrite;
   }
diff --git a/posix/glob-lstat-compat.c b/posix/glob-lstat-compat.c
new file mode 100644
index 0000000..f408d68
--- /dev/null
+++ b/posix/glob-lstat-compat.c
@@ -0,0 +1,36 @@ 
+/* Compat glob which does not use gl_lstat for GLOB_ALTDIRFUNC.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_27)
+
+# include <glob.h>
+
+# define __glob(pattern, flags, errfunc, pglob) \
+  __glob_lstat_compat (pattern, flags, errfunc, pglob)
+
+# define GLOB_ATTRIBUTE attribute_compat_text_section
+
+/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */
+# define GLOB_LSTAT_COMPAT
+
+# include <posix/glob.c>
+
+compat_symbol (libc, __glob_lstat_compat, glob, GLIBC_2_0);
+#endif
diff --git a/posix/glob.c b/posix/glob.c
index c699177..9e01ac7 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -57,7 +57,9 @@ 
 # endif
 # define struct_stat64		struct stat64
 # define FLEXIBLE_ARRAY_MEMBER
+# include <shlib-compat.h>
 #else /* !_LIBC */
+# define __glob                 glob
 # define __getlogin_r(buf, len) getlogin_r (buf, len)
 # define __lstat64(fname, buf)  lstat (fname, buf)
 # define __stat64(fname, buf)   stat (fname, buf)
@@ -179,6 +181,28 @@  convert_dirent64 (const struct dirent64 *source)
     ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)
 #endif
 
+union glob_stat
+{
+  struct stat st;
+  struct_stat64 st64;
+};
+
+static int
+glob_lstat (glob_t *pglob, int flags, const char *fullname)
+{
+  union glob_stat ust;
+  return __builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+/* Use on glob-lstat-compat.c to provide a compat symbol which does not
+   use lstat / gl_lstat.  */
+#ifdef GLOB_LSTAT_COMPAT
+	 ? (*pglob->gl_stat) (fullname, &ust.st)
+	 : __stat64 (fullname, &ust.st64);
+#else
+	 ? (*pglob->gl_lstat) (fullname, &ust.st)
+	 : __lstat64 (fullname, &ust.st64);
+#endif
+}
+
 /* Set *R = A + B.  Return true if the answer is mathematically
    incorrect due to overflow; in this case, *R is the low order
    bits of the correct answer.  */
@@ -248,6 +272,9 @@  next_brace_sub (const char *cp, int flags)
   return *cp != '\0' ? cp : NULL;
 }
 
+#ifndef GLOB_ATTRIBUTE
+# define GLOB_ATTRIBUTE
+#endif
 
 /* Do glob searching for PATTERN, placing results in PGLOB.
    The bits defined above may be set in FLAGS.
@@ -258,11 +285,9 @@  next_brace_sub (const char *cp, int flags)
    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
    Otherwise, 'glob' returns zero.  */
 int
-#ifdef GLOB_ATTRIBUTE
 GLOB_ATTRIBUTE
-#endif
-glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
-      glob_t *pglob)
+__glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
+	glob_t *pglob)
 {
   const char *filename;
   char *dirname = NULL;
@@ -406,9 +431,9 @@  glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 	      /* Construct the new glob expression.  */
 	      mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
 
-	      result = glob (onealt,
-			     ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
-			      | GLOB_APPEND), errfunc, pglob);
+	      result = __glob (onealt,
+			       ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
+			       | GLOB_APPEND), errfunc, pglob);
 
 	      /* If we got an error, return it.  */
 	      if (result && result != GLOB_NOMATCH)
@@ -557,7 +582,7 @@  glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 		  flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
 		}
 	    }
-	  int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
+	  int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob);
 	  if (val == 0)
 	    pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
 			       | (flags & GLOB_MARK));
@@ -931,11 +956,10 @@  glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 	  dirs.gl_lstat = pglob->gl_lstat;
 	}
 
-      status = glob (dirname,
-		     ((flags & (GLOB_ERR | GLOB_NOESCAPE
-				| GLOB_ALTDIRFUNC))
-		      | GLOB_NOSORT | GLOB_ONLYDIR),
-		     errfunc, &dirs);
+      status = __glob (dirname,
+		       ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC))
+		       | GLOB_NOSORT | GLOB_ONLYDIR),
+		       errfunc, &dirs);
       if (status != 0)
 	{
 	  if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
@@ -1133,8 +1157,9 @@  glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 
   return retval;
 }
-#if defined _LIBC && !defined glob
-libc_hidden_def (glob)
+#if defined _LIBC && !defined __glob
+versioned_symbol (libc, __glob, glob, GLIBC_2_27);
+libc_hidden_ver (__glob, glob)
 #endif
 
 
@@ -1250,11 +1275,6 @@  glob_in_dir (const char *pattern, const char *directory, int flags,
     }
   else if (meta == GLOBPAT_NONE)
     {
-      union
-      {
-	struct stat st;
-	struct_stat64 st64;
-      } ust;
       size_t patlen = strlen (pattern);
       size_t fullsize;
       bool alloca_fullname
@@ -1273,10 +1293,7 @@  glob_in_dir (const char *pattern, const char *directory, int flags,
       mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
 			"/", 1),
 	       pattern, patlen + 1);
-      if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
-	   ? (*pglob->gl_lstat) (fullname, &ust.st)
-	    : __lstat64 (fullname, &ust.st64))
-	   == 0)
+      if (glob_lstat (pglob, flags, fullname) == 0
 	  || errno == EOVERFLOW)
 	/* We found this file to be existing.  Now tell the rest
 	   of the function to copy this name into the result.  */
diff --git a/posix/glob64-lstat-compat.c b/posix/glob64-lstat-compat.c
new file mode 100644
index 0000000..a953f9d
--- /dev/null
+++ b/posix/glob64-lstat-compat.c
@@ -0,0 +1,36 @@ 
+/* Compat glob which does not use gl_lstat for GLOB_ALTDIRFUNC.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_27)
+
+# include <glob.h>
+
+# define glob(pattern, flags, errfunc, pglob) \
+  __glob64_lstat_compat (pattern, flags, errfunc, pglob)
+
+# define GLOB_ATTRIBUTE attribute_compat_text_section
+
+/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */
+# define GLOB_LSTAT_COMPAT
+
+# include <posix/glob64.c>
+
+compat_symbol (libc, __glob64_lstat_compat, glob64, GLIBC_2_0);
+#endif
diff --git a/posix/glob64.c b/posix/glob64.c
index a515a1c..ee7ef84 100644
--- a/posix/glob64.c
+++ b/posix/glob64.c
@@ -20,6 +20,10 @@ 
 #include <glob.h>
 #include <errno.h>
 
+#ifdef GLOB_ATTRIBUTE
+# define GLOB_ATTRIBUTE
+#endif
+
 /* Do glob searching for PATTERN, placing results in PGLOB.
    The bits defined above may be set in FLAGS.
    If a directory cannot be opened or read and ERRFUNC is not nil,
@@ -29,6 +33,7 @@ 
    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
    Otherwise, `glob' returns zero.  */
 int
+GLOB_ATTRIBUTE
 glob64 (const char *pattern, int flags,
 	int (*errfunc) (const char *, int), glob64_t *pglob)
 {
diff --git a/posix/tst-glob_lstat_compat.c b/posix/tst-glob_lstat_compat.c
new file mode 100644
index 0000000..c5b9a27
--- /dev/null
+++ b/posix/tst-glob_lstat_compat.c
@@ -0,0 +1,263 @@ 
+/* Test glob compat symbol which avoid call GLOB_ALTDIRFUNC/gl_lstat.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <glob.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <stdio.h>
+
+#include <shlib-compat.h>
+#include <support/check.h>
+#include <support/temp_file.h>
+
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_27)
+
+__typeof (glob) glob;
+compat_symbol_reference (libc, glob, glob, GLIBC_2_0);
+
+/* Compat glob should not call gl_lstat since for some old binaries it
+   might be unitialized (for instance GNUmake).  Check if it is indeed
+   not called.  */
+static bool stat_called;
+static bool lstat_called;
+
+static struct
+{
+  const char *name;
+  int level;
+  int type;
+} filesystem[] =
+{
+  { ".", 1, DT_DIR },
+  { "..", 1, DT_DIR },
+  { "dir1lev1", 1, DT_UNKNOWN },
+    { ".", 2, DT_DIR },
+    { "..", 2, DT_DIR },
+    { "file1lev2", 2, DT_REG },
+    { "file2lev2", 2, DT_REG },
+};
+static const size_t nfiles = sizeof (filesystem) / sizeof (filesystem [0]);
+
+typedef struct
+{
+  int level;
+  int idx;
+  struct dirent d;
+  char room_for_dirent[NAME_MAX];
+} my_DIR;
+
+static long int
+find_file (const char *s)
+{
+  int level = 1;
+  long int idx = 0;
+
+  while (s[0] == '/')
+    {
+      if (s[1] == '\0')
+	{
+	  s = ".";
+	  break;
+	}
+      ++s;
+    }
+
+  if (strcmp (s, ".") == 0)
+    return 0;
+
+  if (s[0] == '.' && s[1] == '/')
+    s += 2;
+
+  while (*s != '\0')
+    {
+      char *endp = strchrnul (s, '/');
+
+      while (idx < nfiles && filesystem[idx].level >= level)
+	{
+	  if (filesystem[idx].level == level
+	      && memcmp (s, filesystem[idx].name, endp - s) == 0
+	      && filesystem[idx].name[endp - s] == '\0')
+	    break;
+	  ++idx;
+	}
+
+      if (idx == nfiles || filesystem[idx].level < level)
+	{
+	  errno = ENOENT;
+	  return -1;
+	}
+
+      if (*endp == '\0')
+	return idx + 1;
+
+      if (filesystem[idx].type != DT_DIR
+	  && (idx + 1 >= nfiles
+	      || filesystem[idx].level >= filesystem[idx + 1].level))
+	{
+	  errno = ENOTDIR;
+	  return -1;
+	}
+
+      ++idx;
+
+      s = endp + 1;
+      ++level;
+    }
+
+  errno = ENOENT;
+  return -1;
+}
+
+static void *
+my_opendir (const char *s)
+{
+  long int idx = find_file (s);
+  if (idx == -1 || filesystem[idx].type != DT_DIR)
+    return NULL;
+
+  my_DIR *dir = malloc (sizeof (my_DIR));
+  if (dir == NULL)
+    FAIL_EXIT1 ("cannot allocate directory handle");
+
+  dir->level = filesystem[idx].level;
+  dir->idx = idx;
+
+  return dir;
+}
+
+static struct dirent *
+my_readdir (void *gdir)
+{
+  my_DIR *dir = gdir;
+
+  if (dir->idx == -1)
+    return NULL;
+
+  while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)
+    ++dir->idx;
+
+  if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)
+    {
+      dir->idx = -1;
+      return NULL;
+    }
+
+  dir->d.d_ino = 1;		/* glob should not skip this entry.  */
+
+#ifdef _DIRENT_HAVE_D_TYPE
+  dir->d.d_type = filesystem[dir->idx].type;
+#endif
+
+  strcpy (dir->d.d_name, filesystem[dir->idx].name);
+
+  ++dir->idx;
+
+  return &dir->d;
+}
+
+static void
+my_closedir (void *dir)
+{
+  free (dir);
+}
+
+static int
+my_stat (const char *name, struct stat *st)
+{
+  stat_called = true;
+
+  long int idx = find_file (name);
+  if (idx == -1)
+    return -1;
+
+  memset (st, '\0', sizeof (*st));
+
+  if (filesystem[idx].type == DT_UNKNOWN)
+    st->st_mode = DTTOIF (idx + 1 < nfiles
+			  && filesystem[idx].level < filesystem[idx + 1].level
+			  ? DT_DIR : DT_REG) | 0777;
+  else
+    st->st_mode = DTTOIF (filesystem[idx].type) | 0777;
+  return 0;
+}
+
+static int
+my_lstat (const char *name, struct stat *st)
+{
+  lstat_called = true;
+
+  long int idx = find_file (name);
+  if (idx == -1)
+    return -1;
+
+  memset (st, '\0', sizeof (*st));
+
+  if (filesystem[idx].type == DT_UNKNOWN)
+    st->st_mode = DTTOIF (idx + 1 < nfiles
+			  && filesystem[idx].level < filesystem[idx + 1].level
+			  ? DT_DIR : DT_REG) | 0777;
+  else
+    st->st_mode = DTTOIF (filesystem[idx].type) | 0777;
+  return 0;
+}
+
+static int
+do_test (void)
+{
+  glob_t gl;
+
+  memset (&gl, '\0', sizeof (gl));
+
+  gl.gl_closedir = my_closedir;
+  gl.gl_readdir = my_readdir;
+  gl.gl_opendir = my_opendir;
+  gl.gl_lstat = my_lstat;
+  gl.gl_stat = my_stat;
+
+  int flags = GLOB_ALTDIRFUNC;
+
+  stat_called = false;
+  lstat_called = false;
+
+  TEST_VERIFY_EXIT (glob ("*/file1lev2", flags, NULL, &gl) == 0);
+  TEST_VERIFY_EXIT (gl.gl_pathc == 1);
+  TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], "dir1lev1/file1lev2") == 0);
+
+  TEST_VERIFY_EXIT (stat_called == true);
+  TEST_VERIFY_EXIT (lstat_called == false);
+
+  return 0;
+}
+
+#else /* TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_27)  */
+
+static int
+do_test (void)
+{ 
+  return 77;
+}
+#endif
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 81e4fe9..e7438c5 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2103,3 +2103,6 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c b/sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c
new file mode 100644
index 0000000..a76471d
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/alpha/glob-lstat-compat.c
@@ -0,0 +1,2 @@ 
+#define GLOB_LSTAT_VERSION GLIBC_2_1
+#include <sysdeps/unix/sysv/linux/glob-lstat-compat.c>
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index fab7331..4836ea0 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2014,6 +2014,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/alpha/oldglob.c b/sysdeps/unix/sysv/linux/alpha/oldglob.c
index 988c92b..b54624c 100644
--- a/sysdeps/unix/sysv/linux/alpha/oldglob.c
+++ b/sysdeps/unix/sysv/linux/alpha/oldglob.c
@@ -59,7 +59,9 @@  __old_glob (const char *pattern, int flags,
   correct.gl_closedir = pglob->gl_closedir;
   correct.gl_readdir = pglob->gl_readdir;
   correct.gl_opendir = pglob->gl_opendir;
-  correct.gl_lstat = pglob->gl_lstat;
+  /* Set gl_lstat and gl_stat for both gl_stat for compatibility with old
+     implementation that did not follow dangling symlinks.  */
+  correct.gl_lstat = pglob->gl_stat;
   correct.gl_stat = pglob->gl_stat;
 
   result = glob (pattern, flags, errfunc, &correct);
@@ -72,7 +74,7 @@  __old_glob (const char *pattern, int flags,
   pglob->gl_closedir = correct.gl_closedir;
   pglob->gl_readdir = correct.gl_readdir;
   pglob->gl_opendir = correct.gl_opendir;
-  pglob->gl_lstat = correct.gl_lstat;
+  /* Only need to restore gl_stat.  */
   pglob->gl_stat = correct.gl_stat;
 
   return result;
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index d2a206a..5b70e1b 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -104,6 +104,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/alpha/glob.c b/sysdeps/unix/sysv/linux/glob-lstat-compat.c
similarity index 50%
rename from sysdeps/unix/sysv/linux/alpha/glob.c
rename to sysdeps/unix/sysv/linux/glob-lstat-compat.c
index 1b813c1..13b9182 100644
--- a/sysdeps/unix/sysv/linux/alpha/glob.c
+++ b/sysdeps/unix/sysv/linux/glob-lstat-compat.c
@@ -1,4 +1,6 @@ 
-/* Copyright (C) 1998-2017 Free Software Foundation, Inc.
+/* Compat glob which does not use gl_lstat for GLOB_ALTDIRFUNC.
+   Linux version which handles LFS when required.
+   Copyright (C) 2017 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -12,36 +14,34 @@ 
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
+   License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#define glob64 __no_glob64_decl
-#define globfree64 __no_globfree64_decl
-
-#include <sys/types.h>
-#include <glob.h>
+#include <sys/stat.h>
+#include <kernel_stat.h>
 #include <shlib-compat.h>
 
-/* For Linux/Alpha we have to make the glob symbols versioned.  */
-#define glob(pattern, flags, errfunc, pglob) \
-  __new_glob (pattern, flags, errfunc, pglob)
-#define globfree(pglob) \
-  __new_globfree (pglob)
+#define glob64 __no_glob64_decl
+#include <glob.h>
+#undef glob64
 
-/* We need prototypes for these new names.  */
-extern int __new_glob (const char *__pattern, int __flags,
-		       int (*__errfunc) (const char *, int),
-		       glob_t *__pglob);
-extern void __new_globfree (glob_t *__pglob);
+#define __glob __glob_lstat_compat
 
-#include <posix/glob.c>
+#define GLOB_ATTRIBUTE attribute_compat_text_section
 
-#undef glob
-#undef globfree
-#undef glob64
-#undef globfree64
+/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */
+#define GLOB_LSTAT_COMPAT
 
-versioned_symbol (libc, __new_glob, glob, GLIBC_2_1);
-libc_hidden_ver (__new_glob, glob)
+#include <posix/glob.c>
 
-weak_alias (__new_glob, glob64)
+#ifndef GLOB_LSTAT_VERSION
+# define GLOB_LSTAT_VERSION GLIBC_2_0
+#endif
+
+#if SHLIB_COMPAT(libc, GLOB_LSTAT_VERSION, GLIBC_2_27)
+compat_symbol (libc, __glob_lstat_compat, glob, GLOB_LSTAT_VERSION);
+# if XSTAT_IS_XSTAT64
+strong_alias (__glob_lstat_compat, __glob64_lstat_compat)
+compat_symbol (libc, __glob64_lstat_compat, glob64, GLOB_LSTAT_VERSION);
+# endif
+#endif
diff --git a/sysdeps/unix/sysv/linux/glob.c b/sysdeps/unix/sysv/linux/glob.c
index 057ae7f..e354799 100644
--- a/sysdeps/unix/sysv/linux/glob.c
+++ b/sysdeps/unix/sysv/linux/glob.c
@@ -20,9 +20,12 @@ 
 #include <kernel_stat.h>
 
 #define glob64 __no_glob64_decl
+#define __glob64 __no___glob64_decl
 #include <posix/glob.c>
 #undef glob64
+#undef __glob64
 
 #if XSTAT_IS_XSTAT64
-weak_alias (glob, glob64)
+strong_alias (__glob, __glob64)
+versioned_symbol (libc, __glob64, glob64, GLIBC_2_27);
 #endif
diff --git a/sysdeps/unix/sysv/linux/glob64-lstat-compat.c b/sysdeps/unix/sysv/linux/glob64-lstat-compat.c
new file mode 100644
index 0000000..2654302
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/glob64-lstat-compat.c
@@ -0,0 +1,51 @@ 
+/* Compat glob which does not use gl_lstat for GLOB_ALTDIRFUNC.
+   Linux version which handles LFS when required.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sys/stat.h>
+#include <kernel_stat.h>
+
+#if !XSTAT_IS_XSTAT64
+# include <glob.h>
+# include <dirent.h>
+# include <sys/stat.h>
+# include <shlib-compat.h>
+
+# define dirent dirent64
+# define __readdir(dirp) __readdir64 (dirp)
+
+# define glob_t glob64_t
+# define __glob __glob64_lstat_compat
+# define globfree globfree64
+
+# undef stat
+# define stat stat64
+
+# define COMPILE_GLOB64	1
+
+# define GLOB_ATTRIBUTE attribute_compat_text_section
+
+/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */
+# define GLOB_LSTAT_COMPAT
+
+# include <posix/glob.c>
+
+# if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_27)
+compat_symbol (libc, __glob64_lstat_compat, glob64, GLIBC_2_2);
+# endif
+#endif /* XSTAT_IS_XSTAT64  */
diff --git a/sysdeps/unix/sysv/linux/glob64.c b/sysdeps/unix/sysv/linux/glob64.c
index 428bbac..0189d1c 100644
--- a/sysdeps/unix/sysv/linux/glob64.c
+++ b/sysdeps/unix/sysv/linux/glob64.c
@@ -28,8 +28,7 @@ 
 # define __readdir(dirp) __readdir64 (dirp)
 
 # define glob_t glob64_t
-# define glob(pattern, flags, errfunc, pglob) \
-  __glob64 (pattern, flags, errfunc, pglob)
+# define __glob __glob64
 # define globfree(pglob) globfree64 (pglob)
 
 # undef stat
@@ -39,13 +38,13 @@ 
 
 # include <posix/glob.c>
 
-# include "shlib-compat.h"
+# include <shlib-compat.h>
 
 # ifdef GLOB_NO_OLD_VERSION
 strong_alias (__glob64, glob64)
 libc_hidden_def (glob64)
 # else
-versioned_symbol (libc, __glob64, glob64, GLIBC_2_2);
+versioned_symbol (libc, __glob64, glob64, GLIBC_2_27);
 libc_hidden_ver (__glob64, glob64)
 # endif
 #endif /* XSTAT_IS_XSTAT64  */
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 24bb730..6a2500a 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1868,6 +1868,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 12e77bd..9ab4e36 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2033,6 +2033,9 @@  GLIBC_2.26 strtof128 F
 GLIBC_2.26 strtof128_l F
 GLIBC_2.26 wcstof128 F
 GLIBC_2.26 wcstof128_l F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 62b67b8..81bb623 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1897,6 +1897,9 @@  GLIBC_2.26 strtof128 F
 GLIBC_2.26 strtof128_l F
 GLIBC_2.26 wcstof128 F
 GLIBC_2.26 wcstof128_l F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index b594ebd..5a33b57 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -105,6 +105,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index a36739d..50a86e7 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1982,6 +1982,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 16aa254..250ef30 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2103,3 +2103,6 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 907ab33..87a1dc4 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1957,6 +1957,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 36ee235..f2b35f2 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1955,6 +1955,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 783aa73..e119842 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1953,6 +1953,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index e1275df..67f10f5 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1948,6 +1948,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index be25228..c599dd9 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2144,3 +2144,6 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/oldglob.c b/sysdeps/unix/sysv/linux/oldglob.c
index 5402450..ba53c90 100644
--- a/sysdeps/unix/sysv/linux/oldglob.c
+++ b/sysdeps/unix/sysv/linux/oldglob.c
@@ -21,7 +21,7 @@  libc_hidden_proto (__old_glob64);
 #define __readdir(dirp) __old_readdir64 (dirp)
 
 #define glob_t glob64_t
-#define glob(pattern, flags, errfunc, pglob) \
+#define __glob(pattern, flags, errfunc, pglob) \
   __old_glob64 (pattern, flags, errfunc, pglob)
 #define globfree(pglob) globfree64(pglob)
 
@@ -33,6 +33,9 @@  libc_hidden_proto (__old_glob64);
 #undef __stat
 #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
 
+/* Avoid calling gl_lstat with GLOB_ALTDIRFUNC.  */
+#define GLOB_LSTAT_COMPAT
+
 #define GLOB_ATTRIBUTE attribute_compat_text_section
 
 #include <posix/glob.c>
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index e213895..385409a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1986,6 +1986,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index d25aefd..e99cb45 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1991,6 +1991,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index 51a8d19..173672a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2198,3 +2198,6 @@  GLIBC_2.26 strtof128 F
 GLIBC_2.26 strtof128_l F
 GLIBC_2.26 wcstof128 F
 GLIBC_2.26 wcstof128_l F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 5eb056b..8a65443 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -105,6 +105,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 _Exit F
 GLIBC_2.3 _IO_2_1_stderr_ D 0xe0
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 63d33e8..271eccc 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1986,6 +1986,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index b1b2b29..8b96e16 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1887,6 +1887,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index f3a70a0..0f840e6 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1872,6 +1872,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 8c4c2e5..7f7449f 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1978,6 +1978,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 1653164..a50485e 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1916,6 +1916,9 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index 41647d4..38a96d3 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2110,3 +2110,6 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index 1088923..572b917 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2110,3 +2110,6 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index 41647d4..38a96d3 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2110,3 +2110,6 @@  GLIBC_2.26 preadv64v2 F
 GLIBC_2.26 pwritev2 F
 GLIBC_2.26 pwritev64v2 F
 GLIBC_2.26 reallocarray F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 8bff2b2..b83d25c 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1874,6 +1874,9 @@  GLIBC_2.26 strtof128 F
 GLIBC_2.26 strtof128_l F
 GLIBC_2.26 wcstof128 F
 GLIBC_2.26 wcstof128_l F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index d91a038..cba1d59 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2117,3 +2117,6 @@  GLIBC_2.26 strtof128 F
 GLIBC_2.26 strtof128_l F
 GLIBC_2.26 wcstof128 F
 GLIBC_2.26 wcstof128_l F
+GLIBC_2.27 GLIBC_2.27 A
+GLIBC_2.27 glob F
+GLIBC_2.27 glob64 F