This is the mail archive of the
mailing list for the glibc project.
[PATCH v2][BZ #17979][BZ #17721] Fix issues with sys/cdefs.h and uchar.h when using non-gcc compiler.
- From: "Dwight Guth" <dwight dot guth at runtimeverification dot com>
- To: libc-alpha at sourceware dot org
- Date: Mon, 1 Feb 2016 03:44:19 -0600
- Subject: [PATCH v2][BZ #17979][BZ #17721] Fix issues with sys/cdefs.h and uchar.h when using non-gcc compiler.
- Authentication-results: sourceware.org; auth=none
If linking against Glibc with a compiler for which the __GNUC__ macro is not
defined, problems arise when including header files that use the __restrict
or __inline keyword and when including uchar.h.
Glibc strips __restrict from the prototypes of C library functions in this
case. This is undesirable if the compiler is a C99-compliant compiler,
C99 includes the restrict keyword and uses it in the declaration of a number
of functions in the C library. While this is broadly correct, lack of this
information can have undesirable effects on analysis tools. The same thing
occurs with the __inline keyword, which is also defined in C99 but stripped
if the compiler is not GNU C. Here we except the case where the compiler
declares itself to be C99-compliant from these checks in order to allow
C99 compliance for non-GNU-C compilers which link against Glibc.
Glibc defines char16_t and char32_t in uchar.h as __CHAR16_TYPE__ and
__CHAR32_TYPE__ when the __GNUC__ macro is defined, but when linking against
Glibc with a different compiler, these types are not defined at all,
which is a violation of C11 sec. 7.28 paragraph 2, as well as a syntax
error because these types are used in the prototypes of functions declared
later in the file. According to this section of the standard, these types
must be defined in this header file and must be the same type as
uint_least16_t and uint_least32_t, which are defined in stdint.h as
"unsigned short int" and "unsigned int" respectively. Here we modify the
header so that if __GNUC__ is not defined, we still provide these typedefs,
but we obtain them from bits/stdint.h, where they are defined to be equal
to uint_least16_t and uint_least32_t, if __CHAR16_TYPE__ and __CHAR32_TYPE__
are not defined by the compiler.
I had trouble testing this patch because I ran into unrelated errors in the
test suite. No tests seem to fail on my machine after the patch that were
passing before, however. It seems to happen because it can't dynamically
link against libgcc_s, but I'm not 100% sure what the correct way to pass
to make check is. Can someone point me to where this documentation is?
Changed from previous version:
* Updated patch description based on comments on mailing list.
* Added a bits/stdint.h which defines __uint_least16_t and __uint_least32_t
and which is included from stdint.h and uchar.h.
I didn't move stdint.h out of sysdeps because I wasn't sure how controversial
that would be, but I can do that in a third version of the patch if need be.
I was under impression that the issue was that uchar.h was outside sysdeps
and could not directly assume a particular version of stdint.h, but that
assuming that whatever particular version of bits/stdint.h you had would
a certain type, and including that header from outside sysdeps should be
If this is not the case, apologies, just let me know.
2016-01-28 Dwight Guth <email@example.com>
* wcsmbs/uchar.h (char16_t, char32_t): Define types if __GNUC__,
__CHAR16_TYPE__, or __CHAR32_TYPE__ are not defined.
* sysdeps/generic/bits/stdint.h: Created.
* sysdeps/generic/stdint.h (uint_least16_t, uint_least32_t): Defined
based on types from bits/stdint.h.
* misc/sys/cdefs.h (__restrict, __inline): Define as keywords if
__GNUC__ is not defined but __STDC_VERSION__ is at least C99.
diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index 7fd4154..af23ff7 100644
@@ -69,8 +69,11 @@
#else /* Not GCC. */
-# define __inline /* No inline functions. */
+# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+# define __inline inline
+# define __inline /* No inline functions. */
# define __THROW
# define __THROWNL
# define __NTH(fct) fct
@@ -360,7 +363,11 @@
/* __restrict is known in EGCS 1.2 and above. */
#if !__GNUC_PREREQ (2,92)
-# define __restrict /* Ignore */
+# if !defined __GNUC__ && defined __STDC_VERSION__ && __STDC_VERSION__ >=
+# define __restrict restrict
+# define __restrict /* Ignore */
/* ISO C99 also allows to declare arrays as non-overlapping. The syntax is
diff --git a/sysdeps/generic/bits/stdint.h b/sysdeps/generic/bits/stdint.h
new file mode 100644
@@ -0,0 +1,29 @@
+/* uint_least16_t and uint_least32_t definitions
+ Copyright (C) 2016 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/>. */
+#define _BITS_STDINT_H 1
+/* uint_least16_t and char16_t must be the same type, as must
+ uint_least32_t and char32_t. We define here a reserved identifier
+ for these types so that they will always remain the same type. */
+typedef unsigned short int __uint_least16_t;
+typedef unsigned int __uint_least32_t;
+#endif /* bits/stdint.h */
diff --git a/sysdeps/generic/stdint.h b/sysdeps/generic/stdint.h
index 4427627..2f4ebd2 100644
@@ -25,6 +25,7 @@
/* Exact integral types. */
@@ -74,8 +75,8 @@ typedef long long int int_least64_t;
/* Unsigned. */
typedef unsigned char uint_least8_t;
-typedef unsigned short int uint_least16_t;
-typedef unsigned int uint_least32_t;
+typedef __uint_least16_t uint_least16_t;
+typedef __uint_least32_t uint_least32_t;
#if __WORDSIZE == 64
typedef unsigned long int uint_least64_t;
diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h
index ce92b25..875919a 100644
@@ -30,6 +30,8 @@
/* Public type. */
@@ -39,14 +41,16 @@ __END_NAMESPACE_C99
-#if defined __GNUC__ && !defined __USE_ISOCXX11
+#if !defined __USE_ISOCXX11
/* Define the 16-bit and 32-bit character types. Use the information
provided by the compiler. */
# if !defined __CHAR16_TYPE__ || !defined __CHAR32_TYPE__
# if defined __STDC_VERSION__ && __STDC_VERSION__ < 201000L
# error "<uchar.h> requires ISO C11 mode"
-# error "definitions of __CHAR16_TYPE__ and/or __CHAR32_TYPE__ missing"
+/* Same as uint_least16_t and uint_least32_t in stdint.h. */
+typedef __uint_least16_t __CHAR16_TYPE__;
+typedef __uint_least32_t __CHAR32_TYPE__;
typedef __CHAR16_TYPE__ char16_t;