diff mbox series

[v3,08/10] wcsmbs: Improve fortify with clang

Message ID 20240208184622.332678-9-adhemerval.zanella@linaro.org
State Accepted
Commit 68444c045077368446eced143510419c901e31b1
Headers show
Series Improve fortify support with clang | expand

Commit Message

Adhemerval Zanella Netto Feb. 8, 2024, 6:46 p.m. UTC
It improve fortify checks for wmemcpy, wmemmove, wmemset, wcscpy,
wcpcpy, wcsncpy, wcpncpy, wcscat, wcsncat, wcslcpy, wcslcat, swprintf,
fgetws, fgetws_unlocked, wcrtomb, mbsrtowcs, wcsrtombs, mbsnrtowcs, and
wcsnrtombs.  The compile and runtime checks have similar coverage as
with GCC.

Checked on aarch64, armhf, x86_64, and i686.
---
 wcsmbs/bits/wchar2.h | 167 ++++++++++++++++++++++++++++++-------------
 1 file changed, 119 insertions(+), 48 deletions(-)

Comments

Carlos O'Donell Feb. 20, 2024, 10:05 p.m. UTC | #1
On 2/8/24 13:46, Adhemerval Zanella wrote:
> It improve fortify checks for wmemcpy, wmemmove, wmemset, wcscpy,
> wcpcpy, wcsncpy, wcpncpy, wcscat, wcsncat, wcslcpy, wcslcat, swprintf,
> fgetws, fgetws_unlocked, wcrtomb, mbsrtowcs, wcsrtombs, mbsnrtowcs, and
> wcsnrtombs.  The compile and runtime checks have similar coverage as
> with GCC.

LGTM.

Tested on x86_64 and i686.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>

> 
> Checked on aarch64, armhf, x86_64, and i686.
> ---
>  wcsmbs/bits/wchar2.h | 167 ++++++++++++++++++++++++++++++-------------
>  1 file changed, 119 insertions(+), 48 deletions(-)
> 
> diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
> index 49f19bca19..9fdff47ee2 100644
> --- a/wcsmbs/bits/wchar2.h
> +++ b/wcsmbs/bits/wchar2.h
> @@ -20,17 +20,24 @@
>  # error "Never include <bits/wchar2.h> directly; use <wchar.h> instead."
>  #endif
>  
> -__fortify_function wchar_t *
> -__NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
> -		size_t __n))
> +__fortify_function __attribute_overloadable__ wchar_t *
> +__NTH (wmemcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
> +		const wchar_t *__restrict __s2, size_t __n))
> +     __fortify_clang_warning_only_if_bos0_lt2 (__n, __s1, sizeof (wchar_t),
> +					       "wmemcpy called with length bigger "
> +					       "than size of destination buffer")
>  {
>    return __glibc_fortify_n (wmemcpy, __n, sizeof (wchar_t),
>  			    __glibc_objsize0 (__s1),
>  			    __s1, __s2, __n);
>  }
>  
> -__fortify_function wchar_t *
> -__NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
> +__fortify_function __attribute_overloadable__ wchar_t *
> +__NTH (wmemmove (__fortify_clang_overload_arg (wchar_t *, ,__s1),
> +		 const wchar_t *__s2, size_t __n))
> +     __fortify_clang_warning_only_if_bos0_lt2 (__n, __s1, sizeof (wchar_t),
> +					       "wmemmove called with length bigger "
> +					       "than size of destination buffer")
>  {
>    return __glibc_fortify_n (wmemmove, __n, sizeof (wchar_t),
>  			    __glibc_objsize0 (__s1),
> @@ -38,9 +45,12 @@ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
>  }
>  
>  #ifdef __USE_GNU
> -__fortify_function wchar_t *
> -__NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
> -		 size_t __n))
> +__fortify_function __attribute_overloadable__ wchar_t *
> +__NTH (wmempcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
> +		 const wchar_t *__restrict __s2, size_t __n))
> +     __fortify_clang_warning_only_if_bos0_lt2 (__n, __s1, sizeof (wchar_t),
> +					       "wmempcpy called with length bigger "
> +					       "than size of destination buffer")
>  {
>    return __glibc_fortify_n (wmempcpy, __n, sizeof (wchar_t),
>  			    __glibc_objsize0 (__s1),
> @@ -48,16 +58,21 @@ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
>  }
>  #endif
>  
> -__fortify_function wchar_t *
> -__NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n))
> +__fortify_function __attribute_overloadable__ wchar_t *
> +__NTH (wmemset (__fortify_clang_overload_arg (wchar_t *, ,__s), wchar_t __c,
> +		size_t __n))
> +     __fortify_clang_warning_only_if_bos0_lt2 (__n, __s, sizeof (wchar_t),
> +					       "wmemset called with length bigger "
> +					       "than size of destination buffer")
>  {
>    return __glibc_fortify_n (wmemset, __n, sizeof (wchar_t),
>  			    __glibc_objsize0 (__s),
>  			    __s, __c, __n);
>  }
>  
> -__fortify_function wchar_t *
> -__NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
> +__fortify_function __attribute_overloadable__ wchar_t *
> +__NTH (wcscpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
> +	       const wchar_t *__restrict __src))
>  {
>    size_t sz = __glibc_objsize (__dest);
>    if (sz != (size_t) -1)
> @@ -65,8 +80,9 @@ __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
>    return __wcscpy_alias (__dest, __src);
>  }
>  
> -__fortify_function wchar_t *
> -__NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
> +__fortify_function __attribute_overloadable__ wchar_t *
> +__NTH (wcpcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
> +	       const wchar_t *__restrict __src))
>  {
>    size_t sz = __glibc_objsize (__dest);
>    if (sz != (size_t) -1)
> @@ -74,26 +90,33 @@ __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
>    return __wcpcpy_alias (__dest, __src);
>  }
>  
> -__fortify_function wchar_t *
> -__NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
> -		size_t __n))
> +__fortify_function __attribute_overloadable__ wchar_t *
> +__NTH (wcsncpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
> +		const wchar_t *__restrict __src, size_t __n))
> +     __fortify_clang_warning_only_if_bos0_lt2 (__n, __dest, sizeof (wchar_t),
> +					       "wcsncpy called with length bigger "
> +					       "than size of destination buffer")
>  {
>    return __glibc_fortify_n (wcsncpy, __n, sizeof (wchar_t),
>  			    __glibc_objsize (__dest),
>  			    __dest, __src, __n);
>  }
>  
> -__fortify_function wchar_t *
> -__NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
> -		size_t __n))
> +__fortify_function __attribute_overloadable__ wchar_t *
> +__NTH (wcpncpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
> +		const wchar_t *__restrict __src, size_t __n))
> +     __fortify_clang_warning_only_if_bos0_lt2 (__n, __dest, sizeof (wchar_t),
> +					       "wcpncpy called with length bigger "
> +					       "than size of destination buffer")
>  {
>    return __glibc_fortify_n (wcpncpy, __n, sizeof (wchar_t),
>  			    __glibc_objsize (__dest),
>  			    __dest, __src, __n);
>  }
>  
> -__fortify_function wchar_t *
> -__NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
> +__fortify_function __attribute_overloadable__ wchar_t *
> +__NTH (wcscat (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
> +	       const wchar_t *__restrict __src))
>  {
>    size_t sz = __glibc_objsize (__dest);
>    if (sz != (size_t) -1)
> @@ -101,9 +124,9 @@ __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
>    return __wcscat_alias (__dest, __src);
>  }
>  
> -__fortify_function wchar_t *
> -__NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
> -		size_t __n))
> +__fortify_function __attribute_overloadable__ wchar_t *
> +__NTH (wcsncat (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
> +	       const wchar_t *__restrict __src, size_t __n))
>  {
>    size_t sz = __glibc_objsize (__dest);
>    if (sz != (size_t) -1)
> @@ -112,9 +135,12 @@ __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
>  }
>  
>  #ifdef __USE_MISC
> -__fortify_function size_t
> -__NTH (wcslcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
> -		size_t __n))
> +__fortify_function __attribute_overloadable__ size_t
> +__NTH (wcslcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
> +		const wchar_t *__restrict __src, size_t __n))
> +     __fortify_clang_warning_only_if_bos0_lt2 (__n, __dest, sizeof (wchar_t),
> +					       "wcslcpy called with length bigger "
> +					       "than size of destination buffer")
>  {
>    if (__glibc_objsize (__dest) != (size_t) -1
>        && (!__builtin_constant_p (__n
> @@ -125,9 +151,9 @@ __NTH (wcslcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
>    return __wcslcpy_alias (__dest, __src, __n);
>  }
>  
> -__fortify_function size_t
> -__NTH (wcslcat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
> -		size_t __n))
> +__fortify_function __attribute_overloadable__ size_t
> +__NTH (wcslcat (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
> +		const wchar_t *__restrict __src, size_t __n))
>  {
>    if (__glibc_objsize (__dest) != (size_t) -1
>        && (!__builtin_constant_p (__n > __glibc_objsize (__dest)
> @@ -150,6 +176,23 @@ __NTH (swprintf (wchar_t *__restrict __s, size_t __n,
>  			   sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
>    return __swprintf_alias (__s, __n, __fmt, __va_arg_pack ());
>  }
> +#elif __fortify_use_clang
> +__fortify_function_error_function __attribute_overloadable__ int
> +__NTH (swprintf (__fortify_clang_overload_arg (wchar_t *, __restrict, __s),
> +		 size_t __n, const wchar_t *__restrict __fmt, ...))
> +{
> +  __gnuc_va_list __fortify_ap;
> +  __builtin_va_start (__fortify_ap, __fmt);
> +  int __r;
> +  if (__glibc_objsize (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
> +    __r = __vswprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
> +			   __glibc_objsize (__s) / sizeof (wchar_t),
> +			   __fmt, __fortify_ap);
> +  else
> +    __r = __vswprintf_alias (__s, __n, __fmt, __fortify_ap);
> +  __builtin_va_end (__fortify_ap);
> +  return __r;
> +}
>  #elif !defined __cplusplus
>  /* XXX We might want to have support in gcc for swprintf.  */
>  # define swprintf(s, n, ...) \
> @@ -207,34 +250,46 @@ vfwprintf (__FILE *__restrict __stream,
>  }
>  
>  #endif
> -__fortify_function __wur wchar_t *
> -fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
> +__fortify_function __attribute_overloadable__ __wur wchar_t *
> +fgetws (__fortify_clang_overload_arg (wchar_t *, __restrict, __s), int __n,
> +	__FILE *__restrict __stream)
> +     __fortify_clang_warning_only_if_bos_lt2 (__n, __s, sizeof (wchar_t),
> +					      "fgetws called with length bigger "
> +					      "than size of destination buffer")
>  {
>    size_t sz = __glibc_objsize (__s);
>    if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
>      return __fgetws_alias (__s, __n, __stream);
> +#if !__fortify_use_clang
>    if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
>      return __fgetws_chk_warn (__s, sz / sizeof (wchar_t), __n, __stream);
> +#endif
>    return __fgetws_chk (__s, sz / sizeof (wchar_t), __n, __stream);
>  }
>  
>  #ifdef __USE_GNU
> -__fortify_function __wur wchar_t *
> -fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
> +__fortify_function __attribute_overloadable__ __wur wchar_t *
> +fgetws_unlocked (__fortify_clang_overload_arg (wchar_t *, __restrict, __s),
> +		 int __n, __FILE *__restrict __stream)
> +     __fortify_clang_warning_only_if_bos_lt2 (__n, __s, sizeof (wchar_t),
> +					      "fgetws_unlocked called with length bigger "
> +					      "than size of destination buffer")
>  {
>    size_t sz = __glibc_objsize (__s);
>    if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
>      return __fgetws_unlocked_alias (__s, __n, __stream);
> +# if !__fortify_use_clang
>    if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
>      return __fgetws_unlocked_chk_warn (__s, sz / sizeof (wchar_t), __n,
>  				       __stream);
> +# endif
>    return __fgetws_unlocked_chk (__s, sz / sizeof (wchar_t), __n, __stream);
>  }
>  #endif
>  
> -__fortify_function __wur size_t
> -__NTH (wcrtomb (char *__restrict __s, wchar_t __wchar,
> -		mbstate_t *__restrict __ps))
> +__fortify_function __attribute_overloadable__ __wur size_t
> +__NTH (wcrtomb (__fortify_clang_overload_arg (char *, __restrict, __s),
> +		wchar_t __wchar, mbstate_t *__restrict __ps))
>  {
>    /* We would have to include <limits.h> to get a definition of MB_LEN_MAX.
>       But this would only disturb the namespace.  So we define our own
> @@ -249,18 +304,26 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar,
>    return __wcrtomb_alias (__s, __wchar, __ps);
>  }
>  
> -__fortify_function size_t
> -__NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
> +__fortify_function __attribute_overloadable__ size_t
> +__NTH (mbsrtowcs (__fortify_clang_overload_arg (wchar_t *, __restrict, __dst),
> +		  const char **__restrict __src,
>  		  size_t __len, mbstate_t *__restrict __ps))
> +     __fortify_clang_warning_only_if_bos_lt2 (__len, __dst, sizeof (wchar_t),
> +					      "mbsrtowcs called with dst buffer "
> +					      "smaller than len * sizeof (wchar_t)")
>  {
>    return __glibc_fortify_n (mbsrtowcs, __len, sizeof (wchar_t),
>  			    __glibc_objsize (__dst),
>  			    __dst, __src, __len, __ps);
>  }
>  
> -__fortify_function size_t
> -__NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
> +__fortify_function __attribute_overloadable__ size_t
> +__NTH (wcsrtombs (__fortify_clang_overload_arg (char *, __restrict, __dst),
> +		  const wchar_t **__restrict __src,
>  		  size_t __len, mbstate_t *__restrict __ps))
> +     __fortify_clang_warning_only_if_bos_lt (__len, __dst,
> +					     "wcsrtombs called with dst buffer "
> +					     "smaller than len")
>  {
>    return __glibc_fortify (wcsrtombs, __len, sizeof (char),
>  			  __glibc_objsize (__dst),
> @@ -269,18 +332,26 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
>  
>  
>  #ifdef	__USE_XOPEN2K8
> -__fortify_function size_t
> -__NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
> -		   size_t __nmc, size_t __len, mbstate_t *__restrict __ps))
> +__fortify_function __attribute_overloadable__ size_t
> +__NTH (mbsnrtowcs (__fortify_clang_overload_arg (wchar_t *, __restrict, __dst),
> +		   const char **__restrict __src, size_t __nmc, size_t __len,
> +		   mbstate_t *__restrict __ps))
> +     __fortify_clang_warning_only_if_bos_lt (sizeof (wchar_t) * __len, __dst,
> +					     "mbsnrtowcs called with dst buffer "
> +					     "smaller than len * sizeof (wchar_t)")
>  {
>    return __glibc_fortify_n (mbsnrtowcs, __len, sizeof (wchar_t),
>  			    __glibc_objsize (__dst),
>  			    __dst, __src, __nmc, __len, __ps);
>  }
>  
> -__fortify_function size_t
> -__NTH (wcsnrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
> -		   size_t __nwc, size_t __len, mbstate_t *__restrict __ps))
> +__fortify_function __attribute_overloadable__ size_t
> +__NTH (wcsnrtombs (__fortify_clang_overload_arg (char *, __restrict, __dst),
> +		   const wchar_t **__restrict __src, size_t __nwc,
> +		   size_t __len, mbstate_t *__restrict __ps))
> +     __fortify_clang_warning_only_if_bos_lt (__len, __dst,
> +					     "wcsnrtombs called with dst buffer "
> +					     "smaller than len")
>  {
>    return __glibc_fortify (wcsnrtombs, __len, sizeof (char),
>  			  __glibc_objsize (__dst),
diff mbox series

Patch

diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
index 49f19bca19..9fdff47ee2 100644
--- a/wcsmbs/bits/wchar2.h
+++ b/wcsmbs/bits/wchar2.h
@@ -20,17 +20,24 @@ 
 # error "Never include <bits/wchar2.h> directly; use <wchar.h> instead."
 #endif
 
-__fortify_function wchar_t *
-__NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
-		size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wmemcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
+		const wchar_t *__restrict __s2, size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __s1, sizeof (wchar_t),
+					       "wmemcpy called with length bigger "
+					       "than size of destination buffer")
 {
   return __glibc_fortify_n (wmemcpy, __n, sizeof (wchar_t),
 			    __glibc_objsize0 (__s1),
 			    __s1, __s2, __n);
 }
 
-__fortify_function wchar_t *
-__NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wmemmove (__fortify_clang_overload_arg (wchar_t *, ,__s1),
+		 const wchar_t *__s2, size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __s1, sizeof (wchar_t),
+					       "wmemmove called with length bigger "
+					       "than size of destination buffer")
 {
   return __glibc_fortify_n (wmemmove, __n, sizeof (wchar_t),
 			    __glibc_objsize0 (__s1),
@@ -38,9 +45,12 @@  __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
 }
 
 #ifdef __USE_GNU
-__fortify_function wchar_t *
-__NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
-		 size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wmempcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
+		 const wchar_t *__restrict __s2, size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __s1, sizeof (wchar_t),
+					       "wmempcpy called with length bigger "
+					       "than size of destination buffer")
 {
   return __glibc_fortify_n (wmempcpy, __n, sizeof (wchar_t),
 			    __glibc_objsize0 (__s1),
@@ -48,16 +58,21 @@  __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
 }
 #endif
 
-__fortify_function wchar_t *
-__NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wmemset (__fortify_clang_overload_arg (wchar_t *, ,__s), wchar_t __c,
+		size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __s, sizeof (wchar_t),
+					       "wmemset called with length bigger "
+					       "than size of destination buffer")
 {
   return __glibc_fortify_n (wmemset, __n, sizeof (wchar_t),
 			    __glibc_objsize0 (__s),
 			    __s, __c, __n);
 }
 
-__fortify_function wchar_t *
-__NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wcscpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+	       const wchar_t *__restrict __src))
 {
   size_t sz = __glibc_objsize (__dest);
   if (sz != (size_t) -1)
@@ -65,8 +80,9 @@  __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
   return __wcscpy_alias (__dest, __src);
 }
 
-__fortify_function wchar_t *
-__NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wcpcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+	       const wchar_t *__restrict __src))
 {
   size_t sz = __glibc_objsize (__dest);
   if (sz != (size_t) -1)
@@ -74,26 +90,33 @@  __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
   return __wcpcpy_alias (__dest, __src);
 }
 
-__fortify_function wchar_t *
-__NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wcsncpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+		const wchar_t *__restrict __src, size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __dest, sizeof (wchar_t),
+					       "wcsncpy called with length bigger "
+					       "than size of destination buffer")
 {
   return __glibc_fortify_n (wcsncpy, __n, sizeof (wchar_t),
 			    __glibc_objsize (__dest),
 			    __dest, __src, __n);
 }
 
-__fortify_function wchar_t *
-__NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wcpncpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+		const wchar_t *__restrict __src, size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __dest, sizeof (wchar_t),
+					       "wcpncpy called with length bigger "
+					       "than size of destination buffer")
 {
   return __glibc_fortify_n (wcpncpy, __n, sizeof (wchar_t),
 			    __glibc_objsize (__dest),
 			    __dest, __src, __n);
 }
 
-__fortify_function wchar_t *
-__NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wcscat (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+	       const wchar_t *__restrict __src))
 {
   size_t sz = __glibc_objsize (__dest);
   if (sz != (size_t) -1)
@@ -101,9 +124,9 @@  __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
   return __wcscat_alias (__dest, __src);
 }
 
-__fortify_function wchar_t *
-__NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wcsncat (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+	       const wchar_t *__restrict __src, size_t __n))
 {
   size_t sz = __glibc_objsize (__dest);
   if (sz != (size_t) -1)
@@ -112,9 +135,12 @@  __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
 }
 
 #ifdef __USE_MISC
-__fortify_function size_t
-__NTH (wcslcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_function __attribute_overloadable__ size_t
+__NTH (wcslcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+		const wchar_t *__restrict __src, size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __dest, sizeof (wchar_t),
+					       "wcslcpy called with length bigger "
+					       "than size of destination buffer")
 {
   if (__glibc_objsize (__dest) != (size_t) -1
       && (!__builtin_constant_p (__n
@@ -125,9 +151,9 @@  __NTH (wcslcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
   return __wcslcpy_alias (__dest, __src, __n);
 }
 
-__fortify_function size_t
-__NTH (wcslcat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_function __attribute_overloadable__ size_t
+__NTH (wcslcat (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+		const wchar_t *__restrict __src, size_t __n))
 {
   if (__glibc_objsize (__dest) != (size_t) -1
       && (!__builtin_constant_p (__n > __glibc_objsize (__dest)
@@ -150,6 +176,23 @@  __NTH (swprintf (wchar_t *__restrict __s, size_t __n,
 			   sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
   return __swprintf_alias (__s, __n, __fmt, __va_arg_pack ());
 }
+#elif __fortify_use_clang
+__fortify_function_error_function __attribute_overloadable__ int
+__NTH (swprintf (__fortify_clang_overload_arg (wchar_t *, __restrict, __s),
+		 size_t __n, const wchar_t *__restrict __fmt, ...))
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  int __r;
+  if (__glibc_objsize (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
+    __r = __vswprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
+			   __glibc_objsize (__s) / sizeof (wchar_t),
+			   __fmt, __fortify_ap);
+  else
+    __r = __vswprintf_alias (__s, __n, __fmt, __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+  return __r;
+}
 #elif !defined __cplusplus
 /* XXX We might want to have support in gcc for swprintf.  */
 # define swprintf(s, n, ...) \
@@ -207,34 +250,46 @@  vfwprintf (__FILE *__restrict __stream,
 }
 
 #endif
-__fortify_function __wur wchar_t *
-fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
+__fortify_function __attribute_overloadable__ __wur wchar_t *
+fgetws (__fortify_clang_overload_arg (wchar_t *, __restrict, __s), int __n,
+	__FILE *__restrict __stream)
+     __fortify_clang_warning_only_if_bos_lt2 (__n, __s, sizeof (wchar_t),
+					      "fgetws called with length bigger "
+					      "than size of destination buffer")
 {
   size_t sz = __glibc_objsize (__s);
   if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
     return __fgetws_alias (__s, __n, __stream);
+#if !__fortify_use_clang
   if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
     return __fgetws_chk_warn (__s, sz / sizeof (wchar_t), __n, __stream);
+#endif
   return __fgetws_chk (__s, sz / sizeof (wchar_t), __n, __stream);
 }
 
 #ifdef __USE_GNU
-__fortify_function __wur wchar_t *
-fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
+__fortify_function __attribute_overloadable__ __wur wchar_t *
+fgetws_unlocked (__fortify_clang_overload_arg (wchar_t *, __restrict, __s),
+		 int __n, __FILE *__restrict __stream)
+     __fortify_clang_warning_only_if_bos_lt2 (__n, __s, sizeof (wchar_t),
+					      "fgetws_unlocked called with length bigger "
+					      "than size of destination buffer")
 {
   size_t sz = __glibc_objsize (__s);
   if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
     return __fgetws_unlocked_alias (__s, __n, __stream);
+# if !__fortify_use_clang
   if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
     return __fgetws_unlocked_chk_warn (__s, sz / sizeof (wchar_t), __n,
 				       __stream);
+# endif
   return __fgetws_unlocked_chk (__s, sz / sizeof (wchar_t), __n, __stream);
 }
 #endif
 
-__fortify_function __wur size_t
-__NTH (wcrtomb (char *__restrict __s, wchar_t __wchar,
-		mbstate_t *__restrict __ps))
+__fortify_function __attribute_overloadable__ __wur size_t
+__NTH (wcrtomb (__fortify_clang_overload_arg (char *, __restrict, __s),
+		wchar_t __wchar, mbstate_t *__restrict __ps))
 {
   /* We would have to include <limits.h> to get a definition of MB_LEN_MAX.
      But this would only disturb the namespace.  So we define our own
@@ -249,18 +304,26 @@  __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar,
   return __wcrtomb_alias (__s, __wchar, __ps);
 }
 
-__fortify_function size_t
-__NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
+__fortify_function __attribute_overloadable__ size_t
+__NTH (mbsrtowcs (__fortify_clang_overload_arg (wchar_t *, __restrict, __dst),
+		  const char **__restrict __src,
 		  size_t __len, mbstate_t *__restrict __ps))
+     __fortify_clang_warning_only_if_bos_lt2 (__len, __dst, sizeof (wchar_t),
+					      "mbsrtowcs called with dst buffer "
+					      "smaller than len * sizeof (wchar_t)")
 {
   return __glibc_fortify_n (mbsrtowcs, __len, sizeof (wchar_t),
 			    __glibc_objsize (__dst),
 			    __dst, __src, __len, __ps);
 }
 
-__fortify_function size_t
-__NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
+__fortify_function __attribute_overloadable__ size_t
+__NTH (wcsrtombs (__fortify_clang_overload_arg (char *, __restrict, __dst),
+		  const wchar_t **__restrict __src,
 		  size_t __len, mbstate_t *__restrict __ps))
+     __fortify_clang_warning_only_if_bos_lt (__len, __dst,
+					     "wcsrtombs called with dst buffer "
+					     "smaller than len")
 {
   return __glibc_fortify (wcsrtombs, __len, sizeof (char),
 			  __glibc_objsize (__dst),
@@ -269,18 +332,26 @@  __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
 
 
 #ifdef	__USE_XOPEN2K8
-__fortify_function size_t
-__NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
-		   size_t __nmc, size_t __len, mbstate_t *__restrict __ps))
+__fortify_function __attribute_overloadable__ size_t
+__NTH (mbsnrtowcs (__fortify_clang_overload_arg (wchar_t *, __restrict, __dst),
+		   const char **__restrict __src, size_t __nmc, size_t __len,
+		   mbstate_t *__restrict __ps))
+     __fortify_clang_warning_only_if_bos_lt (sizeof (wchar_t) * __len, __dst,
+					     "mbsnrtowcs called with dst buffer "
+					     "smaller than len * sizeof (wchar_t)")
 {
   return __glibc_fortify_n (mbsnrtowcs, __len, sizeof (wchar_t),
 			    __glibc_objsize (__dst),
 			    __dst, __src, __nmc, __len, __ps);
 }
 
-__fortify_function size_t
-__NTH (wcsnrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
-		   size_t __nwc, size_t __len, mbstate_t *__restrict __ps))
+__fortify_function __attribute_overloadable__ size_t
+__NTH (wcsnrtombs (__fortify_clang_overload_arg (char *, __restrict, __dst),
+		   const wchar_t **__restrict __src, size_t __nwc,
+		   size_t __len, mbstate_t *__restrict __ps))
+     __fortify_clang_warning_only_if_bos_lt (__len, __dst,
+					     "wcsnrtombs called with dst buffer "
+					     "smaller than len")
 {
   return __glibc_fortify (wcsnrtombs, __len, sizeof (char),
 			  __glibc_objsize (__dst),