Blob Blame History Raw
Downstream-only patch to introduce the
/etc/sysconfig/strcasecmp-nonascii configuration file, which switches
to an implementation of strcasecmp, strcasecmp_l, strncasecmp,
strncasecmp_l that always performs case-conversion as per tolower.

The original glibc 2.17 version of these functions only ignored
case within the ASCII range due to upstream bug 15736, but it is
too late to change this regression (compared to Red Hat Enterprise
Linux 6) in Red Hat Enterprise Linux 7.

This patch only covers i686 and x86_64.  s390x is not affected.
ppc64le would require additional changes.

diff --git a/sysdeps/i386/i686/multiarch/init-arch.h b/sysdeps/i386/i686/multiarch/init-arch.h
index cd2d0befee728b50..60d0eed17d004871 100644
--- a/sysdeps/i386/i686/multiarch/init-arch.h
+++ b/sysdeps/i386/i686/multiarch/init-arch.h
@@ -1 +1,21 @@
 #include <sysdeps/x86_64/multiarch/init-arch.h>
+
+#ifdef __ASSEMBLER__
+/* Performan an access system call to check whether the configuration
+  file exists.  If it does, load SYMBOL into %eax and jump to LABEL.  */
+# define CHECK_STRCASECMP_CONFIG_FILE(symbol, label) \
+	pushl	%ebx; \
+	cfi_adjust_cfa_offset (4); \
+	cfi_rel_offset (%ebx, 0); \
+	LOAD_PIC_REG (dx); \
+	movl	$__NR_access, %eax; \
+	lea	__sysconfig_strcasecmp_nonascii@GOTOFF(%edx), %ebx; \
+	xor	%ecx, %ecx; \
+	int	$0x80; \
+	test	%eax, %eax; \
+	lea	symbol@GOTOFF(%edx), %eax; \
+	popl	%ebx; \
+	cfi_adjust_cfa_offset (-4); \
+	cfi_restore (%ebx); \
+	jz	label
+#endif
diff --git a/sysdeps/i386/i686/multiarch/strcasecmp-c.c b/sysdeps/i386/i686/multiarch/strcasecmp-c.c
index 753c6ec84ab9f8ea..b50c527525a347d0 100644
--- a/sysdeps/i386/i686/multiarch/strcasecmp-c.c
+++ b/sysdeps/i386/i686/multiarch/strcasecmp-c.c
@@ -10,3 +10,8 @@ strong_alias (__strcasecmp_nonascii, __strcasecmp_ia32)
 /* The needs of strcasecmp in libc are minimal, no need to go through
    the IFUNC.  */
 strong_alias (__strcasecmp_nonascii, __GI___strcasecmp)
+
+/* Used by the assembler IFUNC selectors.  Presence of this file
+   indicates that the C implementation shall be used.  */
+const char __sysconfig_strcasecmp_nonascii[] attribute_hidden =
+  "/etc/sysconfig/strcasecmp-nonascii";
diff --git a/sysdeps/i386/i686/multiarch/strcasecmp.S b/sysdeps/i386/i686/multiarch/strcasecmp.S
index 7efef3b1b0545b5d..9c21a2d5d8b713a1 100644
--- a/sysdeps/i386/i686/multiarch/strcasecmp.S
+++ b/sysdeps/i386/i686/multiarch/strcasecmp.S
@@ -23,6 +23,7 @@
 	.text
 ENTRY(__strcasecmp)
 	.type	__strcasecmp, @gnu_indirect_function
+	CHECK_STRCASECMP_CONFIG_FILE (__strcasecmp_nonascii, 2f)
 	LOAD_GOT_AND_RTLD_GLOBAL_RO
 	LOAD_FUNC_GOT_EAX (__strcasecmp_ia32)
 	HAS_CPU_FEATURE (SSSE3)
diff --git a/sysdeps/i386/i686/multiarch/strcasecmp_l.S b/sysdeps/i386/i686/multiarch/strcasecmp_l.S
index 711c09b0dc1fa62e..512e9bd66ed66b23 100644
--- a/sysdeps/i386/i686/multiarch/strcasecmp_l.S
+++ b/sysdeps/i386/i686/multiarch/strcasecmp_l.S
@@ -1,6 +1,7 @@
 /* Multiple versions of strcasecmp_l
    All versions must be listed in ifunc-impl-list.c.  */
 #define STRCMP __strcasecmp_l
+#define STRCMP_NONASCII __strcasecmp_l_nonascii
 #define USE_AS_STRCASECMP_L
 #include "strcmp.S"
 
diff --git a/sysdeps/i386/i686/multiarch/strcmp.S b/sysdeps/i386/i686/multiarch/strcmp.S
index 19967e8db0990c2c..7fc791a18089da6f 100644
--- a/sysdeps/i386/i686/multiarch/strcmp.S
+++ b/sysdeps/i386/i686/multiarch/strcmp.S
@@ -54,6 +54,9 @@
 	.text
 ENTRY(STRCMP)
 	.type	STRCMP, @gnu_indirect_function
+#if defined (USE_AS_STRCASECMP_L) || defined (USE_AS_STRNCASECMP_L)
+	CHECK_STRCASECMP_CONFIG_FILE (STRCMP_NONASCII, 2f)
+#endif
 	LOAD_GOT_AND_RTLD_GLOBAL_RO
 	LOAD_FUNC_GOT_EAX (__STRCMP_IA32)
 	HAS_CPU_FEATURE (SSSE3)
diff --git a/sysdeps/i386/i686/multiarch/strncase.S b/sysdeps/i386/i686/multiarch/strncase.S
index 952c7c60994f3023..36495559de590179 100644
--- a/sysdeps/i386/i686/multiarch/strncase.S
+++ b/sysdeps/i386/i686/multiarch/strncase.S
@@ -23,6 +23,7 @@
 	.text
 ENTRY(__strncasecmp)
 	.type	__strncasecmp, @gnu_indirect_function
+	CHECK_STRCASECMP_CONFIG_FILE (__strncasecmp_nonascii, 2f)
 	LOAD_GOT_AND_RTLD_GLOBAL_RO
 	LOAD_FUNC_GOT_EAX (__strncasecmp_ia32)
 	HAS_CPU_FEATURE (SSSE3)
diff --git a/sysdeps/i386/i686/multiarch/strncase_l.S b/sysdeps/i386/i686/multiarch/strncase_l.S
index 8a74ee8574c720ae..b77951b26b98b8c8 100644
--- a/sysdeps/i386/i686/multiarch/strncase_l.S
+++ b/sysdeps/i386/i686/multiarch/strncase_l.S
@@ -1,6 +1,7 @@
 /* Multiple versions of strncasecmp_l
    All versions must be listed in ifunc-impl-list.c.  */
 #define STRCMP __strncasecmp_l
+#define STRCMP_NONASCII __strncasecmp_l_nonascii
 #define USE_AS_STRNCASECMP_L
 #include "strcmp.S"
 
diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
index c6766bb2b443a28a..d75ec12e6f1237c9 100644
--- a/sysdeps/x86_64/Makefile
+++ b/sysdeps/x86_64/Makefile
@@ -14,7 +14,8 @@ tests += tst-mallocalign1
 endif
 
 ifeq ($(subdir),string)
-sysdep_routines += cacheinfo strcasecmp_l-nonascii strncase_l-nonascii
+sysdep_routines += cacheinfo strcasecmp_l-nonascii strncase_l-nonascii \
+  strcasecmp-nonascii strncase-nonascii
 gen-as-const-headers += locale-defines.sym
 endif
 
diff --git a/sysdeps/x86_64/multiarch/strcasecmp_l.S b/sysdeps/x86_64/multiarch/strcasecmp_l.S
index 49f5b9fd952d3cdc..0feefe1ac81cefac 100644
--- a/sysdeps/x86_64/multiarch/strcasecmp_l.S
+++ b/sysdeps/x86_64/multiarch/strcasecmp_l.S
@@ -1,6 +1,7 @@
 /* Multiple versions of strcasecmp and strcasecmp_l
    All versions must be listed in ifunc-impl-list.c.  */
 #define STRCMP __strcasecmp_l
+#define STRCMP_NONASCII __strcasecmp_l_nonascii
 #define USE_AS_STRCASECMP_L
 #include "strcmp.S"
 
diff --git a/sysdeps/x86_64/multiarch/strcmp.S b/sysdeps/x86_64/multiarch/strcmp.S
index 48b4db8c430a514f..ede41c8f61e8b472 100644
--- a/sysdeps/x86_64/multiarch/strcmp.S
+++ b/sysdeps/x86_64/multiarch/strcmp.S
@@ -76,6 +76,17 @@
 # endif
 #endif
 
+/* Performan an access system call to check whether the configuration
+  file exists.  If it does, load SYMBOL into %rax and jump to LABEL.  */
+#define CHECK_STRCASECMP_CONFIG_FILE(symbol, label) \
+	movl	$__NR_access, %eax; \
+	leaq	__sysconfig_strcasecmp_nonascii(%rip), %rdi; \
+	xor	%esi, %esi; \
+	syscall ; \
+	test	%eax, %eax; \
+	leaq 	symbol(%rip), %rax; \
+	jz	label
+
 /* Define multiple versions only for the definition in libc.  Don't
    define multiple versions for strncmp in static library since we
    need strncmp before the initialization happened.  */
@@ -83,6 +94,9 @@
 	.text
 ENTRY(STRCMP)
 	.type	STRCMP, @gnu_indirect_function
+# if defined (USE_AS_STRCASECMP_L) || defined (USE_AS_STRNCASECMP_L)
+	CHECK_STRCASECMP_CONFIG_FILE(STRCMP_NONASCII, 2f)
+# endif
 	LOAD_RTLD_GLOBAL_RO_RDX
 	leaq	STRCMP_SSE42(%rip), %rax
 	HAS_CPU_FEATURE (SSE4_2)
@@ -97,6 +111,7 @@ END(STRCMP)
 # ifdef USE_AS_STRCASECMP_L
 ENTRY(__strcasecmp)
 	.type	__strcasecmp, @gnu_indirect_function
+	CHECK_STRCASECMP_CONFIG_FILE(__strcasecmp_nonascii, 2f)
 	LOAD_RTLD_GLOBAL_RO_RDX
 #  ifdef HAVE_AVX_SUPPORT
 	leaq	__strcasecmp_avx(%rip), %rax
@@ -117,6 +132,7 @@ weak_alias (__strcasecmp, strcasecmp)
 # ifdef USE_AS_STRNCASECMP_L
 ENTRY(__strncasecmp)
 	.type	__strncasecmp, @gnu_indirect_function
+	CHECK_STRCASECMP_CONFIG_FILE(__strncasecmp_nonascii, 2f)
 	LOAD_RTLD_GLOBAL_RO_RDX
 #  ifdef HAVE_AVX_SUPPORT
 	leaq	__strncasecmp_avx(%rip), %rax
diff --git a/sysdeps/x86_64/multiarch/strncase_l.S b/sysdeps/x86_64/multiarch/strncase_l.S
index 9c0149788e9c11b5..259ce6b5ef57e178 100644
--- a/sysdeps/x86_64/multiarch/strncase_l.S
+++ b/sysdeps/x86_64/multiarch/strncase_l.S
@@ -1,6 +1,7 @@
 /* Multiple versions of strncasecmp and strncasecmp_l
    All versions must be listed in ifunc-impl-list.c.  */
 #define STRCMP __strncasecmp_l
+#define STRCMP_NONASCII __strncasecmp_l_nonascii
 #define USE_AS_STRNCASECMP_L
 #include "strcmp.S"
 
diff --git a/sysdeps/x86_64/strcasecmp-nonascii.c b/sysdeps/x86_64/strcasecmp-nonascii.c
new file mode 100644
index 0000000000000000..7e81a7bdb6f52c47
--- /dev/null
+++ b/sysdeps/x86_64/strcasecmp-nonascii.c
@@ -0,0 +1,13 @@
+#if IS_IN (libc)
+# include <string.h>
+
+extern int __strcasecmp_nonascii (const char *__s1, const char *__s2);
+
+# define __strcasecmp __strcasecmp_nonascii
+# include <string/strcasecmp.c>
+
+/* Used by the assembler IFUNC selectors.  Presence of this file
+   indicates that the C implementation shall be used.  */
+const char __sysconfig_strcasecmp_nonascii[] attribute_hidden =
+  "/etc/sysconfig/strcasecmp-nonascii";
+#endif
diff --git a/sysdeps/x86_64/strcasecmp_l-nonascii.c b/sysdeps/x86_64/strcasecmp_l-nonascii.c
index 30e8969603ea7817..4abd55ae2a54f94a 100644
--- a/sysdeps/x86_64/strcasecmp_l-nonascii.c
+++ b/sysdeps/x86_64/strcasecmp_l-nonascii.c
@@ -1,8 +1,10 @@
-#include <string.h>
+#if IS_IN (libc)
+# include <string.h>
 
 extern int __strcasecmp_l_nonascii (const char *__s1, const char *__s2,
 				    __locale_t __loc);
 
-#define __strcasecmp_l __strcasecmp_l_nonascii
-#define USE_IN_EXTENDED_LOCALE_MODEL    1
-#include <string/strcasecmp.c>
+# define __strcasecmp_l __strcasecmp_l_nonascii
+# define USE_IN_EXTENDED_LOCALE_MODEL    1
+# include <string/strcasecmp.c>
+#endif
diff --git a/sysdeps/x86_64/strncase-nonascii.c b/sysdeps/x86_64/strncase-nonascii.c
new file mode 100644
index 0000000000000000..4db45017c189b87a
--- /dev/null
+++ b/sysdeps/x86_64/strncase-nonascii.c
@@ -0,0 +1,7 @@
+#include <string.h>
+
+extern int __strncasecmp_nonascii (const char *__s1, const char *__s2,
+                                   size_t __n);
+
+#define __strncasecmp __strncasecmp_nonascii
+#include <string/strncase.c>