fortify: further improve Clang style fortify

Message ID 20250327143555.418565-1-adrian.ratiu@collabora.com (mailing list archive)
State Changes Requested
Headers
Series fortify: further improve Clang style fortify |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
redhat-pt-bot/TryBot-32bit success Build for i686
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 success Test passed

Commit Message

Adrian Ratiu March 27, 2025, 2:35 p.m. UTC
  glibc >= v2.41 significatly improved clang fortify support,
so I've rebased the ChromeOS toolchain test suite [1] on
top of the upstream implementation and semantics.

Doing this I noticed some missing upstream diagnostics, so
I've added them to get Clang builds on par with GCC.

In addition to the missing ones I also noticed some mismatch
bugs between __glibc_objsize0 vs __glibc_objsize calls done
via various macros like:
__fortify_clang_warning_only_if_bos0_lt2 versus
__fortify_clang_warning_only_if_bos_lt2

The general rule is that the function argument declaration
must match its uses to ensure check consistency between the
__glibc_objsize0 and __glibc_objsize calls.

For example if the arg is defined like
__fortify_clang_overload_arg (...)
then a form like the following must be used:
__fortify_clang_warning_only_if_bos_lt2(...)

If the arg is defined like
__fortify_clang_overload_arg0 (...)
then a form like the following must be used:
__fortify_clang_warning_only_if_bos0_lt2(...)

This rule ensures consistent use of __glibc_objsize0 vs
__glibc_objsize calls in checks.

While a diagnostic message might be correctly printed
with the above type of mismatch, LLVM/Clang will not be
able to signal and terminate a process despite for eg a
buffer overflow being detected (it will happily continue).

So the end result of this type of bug fix is that processes
will get terimated by proper signals when fortify diagnostics
get triggered.

Based on a patch by George Burges with contributions from
Andrej Shadura. [2]

Link: https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/main/cros-toolchain/fortify-tests/clang-fortify-tests.cpp [1]
Link: https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/refs/heads/staging-infra-release-R135-16209.B/sys-libs/glibc/files/local/glibc-2.39/0005-glibc-add-clang-style-FORTIFY.patch [2]
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
---
 libio/bits/stdio2.h             | 38 ++++++++++++++++++++++-----------
 misc/bits/syslog.h              |  6 ++++--
 posix/bits/unistd.h             |  5 ++++-
 stdlib/bits/stdlib.h            |  5 ++++-
 string/bits/string_fortified.h  | 26 +++++++++++++---------
 string/bits/strings_fortified.h | 11 ++++++----
 wcsmbs/bits/wchar2.h            | 12 +++++------
 7 files changed, 67 insertions(+), 36 deletions(-)
  

Comments

Andrej Shadura March 27, 2025, 2:48 p.m. UTC | #1
On 27/03/2025 15:35, Adrian Ratiu wrote:
> glibc >= v2.41 significatly improved clang fortify support,
> so I've rebased the ChromeOS toolchain test suite [1] on
> top of the upstream implementation and semantics.
> 
> Doing this I noticed some missing upstream diagnostics, so
> I've added them to get Clang builds on par with GCC.
> 
> In addition to the missing ones I also noticed some mismatch
> bugs between __glibc_objsize0 vs __glibc_objsize calls done
> via various macros like:
> __fortify_clang_warning_only_if_bos0_lt2 versus
> __fortify_clang_warning_only_if_bos_lt2
> 
> The general rule is that the function argument declaration
> must match its uses to ensure check consistency between the
> __glibc_objsize0 and __glibc_objsize calls.
> 
> For example if the arg is defined like
> __fortify_clang_overload_arg (...)
> then a form like the following must be used:
> __fortify_clang_warning_only_if_bos_lt2(...)
> 
> If the arg is defined like
> __fortify_clang_overload_arg0 (...)
> then a form like the following must be used:
> __fortify_clang_warning_only_if_bos0_lt2(...)
> 
> This rule ensures consistent use of __glibc_objsize0 vs
> __glibc_objsize calls in checks.
> 
> While a diagnostic message might be correctly printed
> with the above type of mismatch, LLVM/Clang will not be
> able to signal and terminate a process despite for eg a
> buffer overflow being detected (it will happily continue).

despite e.g. having detected a buffer overflow, and the process will 
happily continue.

> 
> So the end result of this type of bug fix is that processes
> will get terimated by proper signals when fortify diagnostics

terminated

> get triggered.
> 
> Based on a patch by George Burges with contributions from
> Andrej Shadura. [2]


> Link: https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/main/cros-toolchain/fortify-tests/clang-fortify-tests.cpp [1]
> Link: https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/refs/heads/staging-infra-release-R135-16209.B/sys-libs/glibc/files/local/glibc-2.39/0005-glibc-add-clang-style-FORTIFY.patch [2]
> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>

Thanks!

Acked-by: Andrej Shadura <andrew.shadura@collabora.co.uk>
  
Adhemerval Zanella Netto March 27, 2025, 4:32 p.m. UTC | #2
On 27/03/25 11:35, Adrian Ratiu wrote:
> glibc >= v2.41 significatly improved clang fortify support,
> so I've rebased the ChromeOS toolchain test suite [1] on
> top of the upstream implementation and semantics.
> 
> Doing this I noticed some missing upstream diagnostics, so
> I've added them to get Clang builds on par with GCC.
> 
> In addition to the missing ones I also noticed some mismatch
> bugs between __glibc_objsize0 vs __glibc_objsize calls done
> via various macros like:
> __fortify_clang_warning_only_if_bos0_lt2 versus
> __fortify_clang_warning_only_if_bos_lt2
> 
> The general rule is that the function argument declaration
> must match its uses to ensure check consistency between the
> __glibc_objsize0 and __glibc_objsize calls.
> 
> For example if the arg is defined like
> __fortify_clang_overload_arg (...)
> then a form like the following must be used:
> __fortify_clang_warning_only_if_bos_lt2(...)
> 
> If the arg is defined like
> __fortify_clang_overload_arg0 (...)
> then a form like the following must be used:
> __fortify_clang_warning_only_if_bos0_lt2(...)
> 
> This rule ensures consistent use of __glibc_objsize0 vs
> __glibc_objsize calls in checks.
> 
> While a diagnostic message might be correctly printed
> with the above type of mismatch, LLVM/Clang will not be
> able to signal and terminate a process despite for eg a
> buffer overflow being detected (it will happily continue).

These should be considered real bugs and have proper regression testcases.
Do you have any examples of which fortify wrappers are not being triggered
correctly?

Unfortunately we don't have tests for the compiler warning itself,
just for the runtime behavior.  And I recently updated my clang branch [1]
and I don't see any regression with debug fortify tests with clang 18/19/20/main.

I also don't see any issue withg clang 18/19/20/main when used just as test 
compiler (TEST_CC/TEST_CXX).

[1] https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/azanella/clang

> 
> So the end result of this type of bug fix is that processes
> will get terimated by proper signals when fortify diagnostics
> get triggered.
> 
> Based on a patch by George Burges with contributions from
> Andrej Shadura. [2]
> 
> Link: https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/main/cros-toolchain/fortify-tests/clang-fortify-tests.cpp [1]
> Link: https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/refs/heads/staging-infra-release-R135-16209.B/sys-libs/glibc/files/local/glibc-2.39/0005-glibc-add-clang-style-FORTIFY.patch [2]
> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
> ---
>  libio/bits/stdio2.h             | 38 ++++++++++++++++++++++-----------
>  misc/bits/syslog.h              |  6 ++++--
>  posix/bits/unistd.h             |  5 ++++-
>  stdlib/bits/stdlib.h            |  5 ++++-
>  string/bits/string_fortified.h  | 26 +++++++++++++---------
>  string/bits/strings_fortified.h | 11 ++++++----
>  wcsmbs/bits/wchar2.h            | 12 +++++------
>  7 files changed, 67 insertions(+), 36 deletions(-)
> 
> diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
> index d2ed65371f..0dca01ec83 100644
> --- a/libio/bits/stdio2.h
> +++ b/libio/bits/stdio2.h
> @@ -33,7 +33,8 @@ __NTH (sprintf (char *__restrict __s, const char *__restrict __fmt, ...))
>  }
>  #elif __fortify_use_clang
>  /* clang does not have __va_arg_pack, so defer to va_arg version.  */
> -__fortify_function_error_function __attribute_overloadable__ int
> +__fortify_function_error_function __attribute_overloadable__
> +__attribute__ ((__format__ (__printf__, 2, 3))) int

This seems not really related to the described issues in commit message and
not really clang-specific since gcc also supports __format__ attribute.
So I think we should be a different change.

>  __NTH (sprintf (__fortify_clang_overload_arg (char *, __restrict, __s),
>  		const char *__restrict __fmt, ...))
>  {
> @@ -71,9 +72,13 @@ __NTH (snprintf (char *__restrict __s, size_t __n,
>  }
>  # elif __fortify_use_clang
>  /* clang does not have __va_arg_pack, so defer to va_arg version.  */
> -__fortify_function_error_function __attribute_overloadable__ int
> +__fortify_function_error_function __attribute_overloadable__
> +__attribute__ ((__format__ (__printf__, 3, 4))) int
>  __NTH (snprintf (__fortify_clang_overload_arg (char *, __restrict, __s),
>  		 size_t __n, const char *__restrict __fmt, ...))
> +     __fortify_clang_warning_only_if_bos_lt(__n, __s,
> +					    "call to snprintf may overflow "
> +					    "the destination buffer")
>  {
>    __gnuc_va_list __fortify_ap;
>    __builtin_va_start (__fortify_ap, __fmt);
> @@ -89,13 +94,14 @@ __NTH (snprintf (__fortify_clang_overload_arg (char *, __restrict, __s),
>  			    __glibc_objsize (str), __VA_ARGS__)
>  # endif
>  
> -__fortify_function __attribute_overloadable__ int
> +__fortify_function __attribute_overloadable__
> +__attribute__ ((__format__ (__printf__, 3, 0))) int
>  __NTH (vsnprintf (__fortify_clang_overload_arg (char *, __restrict, __s),
>  		  size_t __n, const char *__restrict __fmt,
>  		  __gnuc_va_list __ap))
> -     __fortify_clang_warning (__fortify_clang_bos_static_lt (__n, __s),
> -			      "call to vsnprintf may overflow the destination "
> -			      "buffer")
> +     __fortify_clang_warning_only_if_bos_lt(__n, __s,
> +					    "call to vsnprintf may overflow "
> +					    "the destination buffer")
>  {
>    return __builtin___vsnprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
>  				    __glibc_objsize (__s), __fmt, __ap);
> @@ -119,7 +125,9 @@ printf (const char *__restrict __fmt, ...)
>  }
>  # elif __fortify_use_clang
>  /* clang does not have __va_arg_pack, so defer to va_arg version.  */
> -__fortify_function_error_function __attribute_overloadable__ __nonnull ((1)) int
> +__fortify_function_error_function __attribute_overloadable__ __nonnull ((1))
> +__attribute__ ((__format__ (__printf__, 2, 3)))
> +int
>  fprintf (__fortify_clang_overload_arg (FILE *, __restrict, __stream),
>  	 const char *__restrict __fmt, ...)
>  {
> @@ -131,7 +139,8 @@ fprintf (__fortify_clang_overload_arg (FILE *, __restrict, __stream),
>    return __r;
>  }
>  
> -__fortify_function_error_function __attribute_overloadable__ int
> +__fortify_function_error_function __attribute_overloadable__
> +__attribute__ ((__format__ (__printf__, 1, 2))) int
>  printf (__fortify_clang_overload_arg (const char *, __restrict, __fmt), ...)
>  {
>    __gnuc_va_list __fortify_ap;
> @@ -148,7 +157,8 @@ printf (__fortify_clang_overload_arg (const char *, __restrict, __fmt), ...)
>    __fprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
>  # endif
>  
> -__fortify_function __attribute_overloadable__ int
> +__fortify_function __attribute_overloadable__
> +__attribute__ ((__format__ (__printf__, 1, 0))) int
>  vprintf (__fortify_clang_overload_arg (const char *, __restrict, __fmt),
>  	 __gnuc_va_list __ap)
>  {
> @@ -175,7 +185,8 @@ dprintf (int __fd, const char *__restrict __fmt, ...)
>  			__va_arg_pack ());
>  }
>  #  elif __fortify_use_clang
> -__fortify_function_error_function __attribute_overloadable__ int
> +__fortify_function_error_function __attribute_overloadable__
> +__attribute__ ((__format__ (__printf__, 2, 3))) int
>  dprintf (int __fd, __fortify_clang_overload_arg (const char *, __restrict,
>  						 __fmt), ...)
>  {
> @@ -223,7 +234,9 @@ __NTH (obstack_printf (struct obstack *__restrict __obstack,
>  			       __va_arg_pack ());
>  }
>  #  elif __fortify_use_clang
> -__fortify_function_error_function __attribute_overloadable__ int
> +__fortify_function_error_function __attribute_overloadable__
> +__attribute__ ((__format__ (__printf__, 2, 3)))
> +__wur int
>  __NTH (asprintf (__fortify_clang_overload_arg (char **, __restrict, __ptr),
>  		 const char *__restrict __fmt, ...))
>  {
> @@ -247,7 +260,8 @@ __NTH (__asprintf (__fortify_clang_overload_arg (char **, __restrict, __ptr),
>    return __r;
>  }
>  
> -__fortify_function_error_function __attribute_overloadable__ int
> +__fortify_function_error_function __attribute_overloadable__
> +__attribute__ ((__format__ (__printf__, 2, 3))) int
>  __NTH (obstack_printf (__fortify_clang_overload_arg (struct obstack *,
>  						     __restrict, __obstack),
>  		       const char *__restrict __fmt, ...))
> diff --git a/misc/bits/syslog.h b/misc/bits/syslog.h
> index 9907a28cbe..ca3132e09c 100644
> --- a/misc/bits/syslog.h
> +++ b/misc/bits/syslog.h
> @@ -37,7 +37,8 @@ syslog (int __pri, const char *__fmt, ...)
>    __syslog_chk (__pri, __USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
>  }
>  #elif __fortify_use_clang && defined __USE_MISC
> -__fortify_function_error_function __attribute_overloadable__ void
> +__fortify_function_error_function __attribute_overloadable__
> +__attribute__ ((__format__ (__printf__, 2, 3))) void
>  syslog (int __pri, __fortify_clang_overload_arg (const char *, , __fmt), ...)
>  {
>    __gnuc_va_list __fortify_ap;
> @@ -52,7 +53,8 @@ syslog (int __pri, __fortify_clang_overload_arg (const char *, , __fmt), ...)
>  
>  
>  #ifdef __USE_MISC
> -__fortify_function __attribute_overloadable__ void
> +__fortify_function __attribute_overloadable__
> +__attribute__ ((__format__ (__printf__, 2, 0))) void
>  vsyslog (int __pri, __fortify_clang_overload_arg (const char *, ,__fmt),
>  	 __gnuc_va_list __ap)
>  {
> diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h
> index f3428135ec..0af7b5e53c 100644
> --- a/posix/bits/unistd.h
> +++ b/posix/bits/unistd.h
> @@ -79,7 +79,7 @@ pread64 (int __fd, __fortify_clang_overload_arg0 (void *, ,__buf),
>  #if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K
>  __fortify_function __attribute_overloadable__ __nonnull ((1, 2)) __wur ssize_t
>  __NTH (readlink (const char *__restrict __path,
> -		 __fortify_clang_overload_arg0 (char *, __restrict, __buf),
> +		 __fortify_clang_overload_arg (char *, __restrict, __buf),
>  		 size_t __len))
>       __fortify_clang_warning_only_if_bos_lt (__len, __buf,
>  					     "readlink called with bigger length "
> @@ -122,6 +122,9 @@ __NTH (getcwd (__fortify_clang_overload_arg (char *, , __buf), size_t __size))
>  __fortify_function __attribute_overloadable__ __nonnull ((1))
>  __attribute_deprecated__ __wur char *
>  __NTH (getwd (__fortify_clang_overload_arg (char *,, __buf)))
> +     __fortify_clang_warning (__glibc_objsize (__buf) == (size_t) -1,
> +			      "please use getcwd instead, as getwd "
> +			      "doesn't specify buffer size")
>  {
>    if (__glibc_objsize (__buf) != (size_t) -1)
>      return __getwd_chk (__buf, __glibc_objsize (__buf));

Ok.

> diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
> index 12f9cfd58f..58c51faaf8 100644
> --- a/stdlib/bits/stdlib.h
> +++ b/stdlib/bits/stdlib.h
> @@ -129,7 +129,7 @@ __fortify_function __attribute_overloadable__ size_t
>  __NTH (mbstowcs (__fortify_clang_overload_arg (wchar_t *, __restrict, __dst),
>  		 const char *__restrict __src,
>  		 size_t __len))
> -     __fortify_clang_warning_only_if_bos0_lt2 (__len, __dst, sizeof (wchar_t),
> +     __fortify_clang_warning_only_if_bos_lt2 (__len, __dst, sizeof (wchar_t),
>  					       "mbstowcs called with dst buffer "
>  					       "smaller than len * sizeof (wchar_t)")
>  {

Ok.

> @@ -159,6 +159,9 @@ __fortify_function __attribute_overloadable__ size_t
>  __NTH (wcstombs (__fortify_clang_overload_arg (char *, __restrict, __dst),
>  		 const wchar_t *__restrict __src,
>  		 size_t __len))
> +     __fortify_clang_warning_only_if_bos_lt (__len, __dst,
> +					      "wcstombs called with dst buffer "
> +					      "smaller than len")
>  {
>    return __glibc_fortify (wcstombs, __len, sizeof (char),
>  			  __glibc_objsize (__dst),

Ok.

> diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h
> index ae14cfbab0..2512bc0517 100644
> --- a/string/bits/string_fortified.h
> +++ b/string/bits/string_fortified.h
> @@ -22,25 +22,29 @@
>  # error "Never use <bits/string_fortified.h> directly; include <string.h> instead."
>  #endif
>  
> -__fortify_function void *
> -__NTH (memcpy (void *__restrict __dest, const void *__restrict __src,
> -	       size_t __len))
> +__fortify_function __attribute_overloadable__ void *
> +__NTH (memcpy (__fortify_clang_overload_arg0 (void *, __restrict, __dest),
> +	       const void *__restrict __src, size_t __len))
> +     __fortify_clang_warn_if_dest_too_small0 (__dest, __len)
>  {
>    return __builtin___memcpy_chk (__dest, __src, __len,
>  				 __glibc_objsize0 (__dest));
>  }
>  

Ok.

> -__fortify_function void *
> -__NTH (memmove (void *__dest, const void *__src, size_t __len))
> +__fortify_function __attribute_overloadable__ void *
> +__NTH (memmove (__fortify_clang_overload_arg0 (void *, __restrict, __dest),
> +		const void *__src, size_t __len))
> +     __fortify_clang_warn_if_dest_too_small0 (__dest, __len)
>  {
>    return __builtin___memmove_chk (__dest, __src, __len,
>  				  __glibc_objsize0 (__dest));
>  }
>  

Ok.

>  #ifdef __USE_GNU
> -__fortify_function void *
> -__NTH (mempcpy (void *__restrict __dest, const void *__restrict __src,
> -		size_t __len))
> +__fortify_function __attribute_overloadable__ void *
> +__NTH (mempcpy (__fortify_clang_overload_arg0 (void *, __restrict, __dest),
> +                const void *__restrict __src, size_t __len))
> +     __fortify_clang_warn_if_dest_too_small0 (__dest, __len)
>  {
>    return __builtin___mempcpy_chk (__dest, __src, __len,
>  				  __glibc_objsize0 (__dest));

Ok.

> @@ -53,8 +57,10 @@ __NTH (mempcpy (void *__restrict __dest, const void *__restrict __src,
>     especially problematic if the intended fill value is zero.  In this
>     case no work is done at all.  We detect these problems by referring
>     non-existing functions.  */
> -__fortify_function void *
> -__NTH (memset (void *__dest, int __ch, size_t __len))
> +__fortify_function __attribute_overloadable__ void *
> +__NTH (memset (__fortify_clang_overload_arg0 (void *, __restrict, __dest),
> +	       int __ch, size_t __len))
> +     __fortify_clang_warn_if_dest_too_small0 (__dest, __len)
>  {
>    return __builtin___memset_chk (__dest, __ch, __len,
>  				 __glibc_objsize0 (__dest));

Ok.

> diff --git a/string/bits/strings_fortified.h b/string/bits/strings_fortified.h
> index be65d5937d..327288f289 100644
> --- a/string/bits/strings_fortified.h
> +++ b/string/bits/strings_fortified.h
> @@ -19,15 +19,18 @@
>  #ifndef __STRINGS_FORTIFIED
>  # define __STRINGS_FORTIFIED 1
>  
> -__fortify_function void
> -__NTH (bcopy (const void *__src, void *__dest, size_t __len))
> +__fortify_function __attribute_overloadable__ void
> +__NTH (bcopy (const void *__src, __fortify_clang_overload_arg0 (void *, , __dest),
> +	      size_t __len))
> +     __fortify_clang_warn_if_dest_too_small0 (__dest, __len)
>  {
>    (void) __builtin___memmove_chk (__dest, __src, __len,
>  				  __glibc_objsize0 (__dest));
>  }
>  

Ok.

> -__fortify_function void
> -__NTH (bzero (void *__dest, size_t __len))
> +__fortify_function __attribute_overloadable__ void
> +__NTH (bzero (__fortify_clang_overload_arg0 (void *, , __dest), size_t __len))
> +     __fortify_clang_warn_if_dest_too_small0 (__dest, __len)
>  {
>    (void) __builtin___memset_chk (__dest, '\0', __len,
>  				 __glibc_objsize0 (__dest));

Ok.

> diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
> index c1a1da8166..609cc76986 100644
> --- a/wcsmbs/bits/wchar2.h
> +++ b/wcsmbs/bits/wchar2.h
> @@ -21,7 +21,7 @@
>  #endif
>  
>  __fortify_function __attribute_overloadable__ wchar_t *
> -__NTH (wmemcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
> +__NTH (wmemcpy (__fortify_clang_overload_arg0 (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 "
> @@ -33,7 +33,7 @@ __NTH (wmemcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
>  }

Ok.

>  
>  __fortify_function __attribute_overloadable__ wchar_t *
> -__NTH (wmemmove (__fortify_clang_overload_arg (wchar_t *, ,__s1),
> +__NTH (wmemmove (__fortify_clang_overload_arg0 (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 "
> @@ -46,7 +46,7 @@ __NTH (wmemmove (__fortify_clang_overload_arg (wchar_t *, ,__s1),
>  
>  #ifdef __USE_GNU
>  __fortify_function __attribute_overloadable__ wchar_t *
> -__NTH (wmempcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
> +__NTH (wmempcpy (__fortify_clang_overload_arg0 (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 "
> @@ -59,7 +59,7 @@ __NTH (wmempcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
>  #endif
>  
>  __fortify_function __attribute_overloadable__ wchar_t *
> -__NTH (wmemset (__fortify_clang_overload_arg (wchar_t *, ,__s), wchar_t __c,
> +__NTH (wmemset (__fortify_clang_overload_arg0 (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 "
> @@ -93,7 +93,7 @@ __NTH (wcpcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
>  __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),
> +     __fortify_clang_warning_only_if_bos_lt2 (__n, __dest, sizeof (wchar_t),
>  					       "wcsncpy called with length bigger "
>  					       "than size of destination buffer")
>  {
> @@ -105,7 +105,7 @@ __NTH (wcsncpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
>  __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),
> +     __fortify_clang_warning_only_if_bos_lt2 (__n, __dest, sizeof (wchar_t),
>  					       "wcpncpy called with length bigger "
>  					       "than size of destination buffer")
>  {

Ok.
  
Sam James March 27, 2025, 4:39 p.m. UTC | #3
Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> writes:

> [...]

> Unfortunately we don't have tests for the compiler warning itself,
> just for the runtime behavior.  And I recently updated my clang branch [1]
> and I don't see any regression with debug fortify tests with clang 18/19/20/main.

(FWIW, I don't have much capacity at the moment, but in a few months, if
you want to either send some of that out in batches, or otherwise
coordinate on getting some of that in, let me know, and I'll provide review.)

> [...]

thanks,
sam
  
Adrian Ratiu March 27, 2025, 5:43 p.m. UTC | #4
Hi Adhemerval and thank you for the prompt response!

On Thu, 27 Mar 2025, Adhemerval Zanella Netto 
<adhemerval.zanella@linaro.org> wrote:
> 
> These should be considered real bugs and have proper regression 
> testcases.  Do you have any examples of which fortify wrappers 
> are not being triggered correctly? 

Yes, all the ones affected by the objsize vs objsize0 mismatch 
which I'm touching here.

In version 2, which will be patch series for better clarity, I 
will provide an explicit list. From the top of my head the 
memset/memcpy/mempcpy/memmove & co, including their wcsmbs 
counterparts.

> 
> Unfortunately we don't have tests for the compiler warning 
> itself, just for the runtime behavior.  And I recently updated 
> my clang branch [1] and I don't see any regression with debug 
> fortify tests with clang 18/19/20/main. 
> 
> I also don't see any issue withg clang 18/19/20/main when used 
> just as test  compiler (TEST_CC/TEST_CXX). 
> 
> [1] 
> https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/azanella/clang 
> 

I'm testing this by building glibc with GCC (currently 10.2, in 
the process of upgrading to 14.2.1 from Gentoo), then building and 
running the tests linked in the patch description [1] with clang 
20 against those glibc headers on amd64.

I can create minimal reproducing C testcases, to avoid for 
e.g. the CPP GTest suite we use in CrOS.

Also these are not quite regressions due to compiler versions or 
glibc itself, they just never worked and are the last missing 
pieces. :) 

For some fun context, with glibc 2.41 the ChromiumOS downstream 
clang fortify patch went from:
 17 files changed, 1114 insertions(+), 621 deletions(-) 
to 
 7 files changed, 67 insertions(+), 36 deletions(-)

The remaining 67(+), 36(-) is exactly this patch, so sweet! :)
 
> 
> This seems not really related to the described issues in commit 
> message and not really clang-specific since gcc also supports 
> __format__ attribute.  So I think we should be a different 
> change. 
> 

Yes, I'll split this into separate smaller patches, each with 
their own separate reasoning, because indeed there are multiple 
separate issues here.

Thanks again for everything!
  
Adhemerval Zanella Netto March 27, 2025, 5:56 p.m. UTC | #5
On 27/03/25 14:43, Adrian Ratiu wrote:
> Hi Adhemerval and thank you for the prompt response!
> 
> On Thu, 27 Mar 2025, Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> wrote:
>>
>> These should be considered real bugs and have proper regression testcases.  Do you have any examples of which fortify wrappers are not being triggered correctly? 
> 
> Yes, all the ones affected by the objsize vs objsize0 mismatch which I'm touching here.
> 
> In version 2, which will be patch series for better clarity, I will provide an explicit list. From the top of my head the memset/memcpy/mempcpy/memmove & co, including their wcsmbs counterparts.

Thanks.

> 
>>
>> Unfortunately we don't have tests for the compiler warning itself, just for the runtime behavior.  And I recently updated my clang branch [1] and I don't see any regression with debug fortify tests with clang 18/19/20/main.
>> I also don't see any issue withg clang 18/19/20/main when used just as test  compiler (TEST_CC/TEST_CXX).
>> [1] https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/azanella/clang
> 
> I'm testing this by building glibc with GCC (currently 10.2, in the process of upgrading to 14.2.1 from Gentoo), then building and running the tests linked in the patch description [1] with clang 20 against those glibc headers on amd64.
> 
> I can create minimal reproducing C testcases, to avoid for e.g. the CPP GTest suite we use in CrOS.

If you could add then either on debug/tst-fortify.c or in an extra extra it would
be helpful.  The tst-fortify.c is the simplest because we test with a lot of
permutation (_FORTIFY_SOURCE equal 1,2,3, C/C++, etc.)

> 
> Also these are not quite regressions due to compiler versions or glibc itself, they just never worked and are the last missing pieces. :)

We do have tests that check for invalid mem* and wmem* on tst-fortify.c, so
they catch missing *_chk calls from compiler/fortify header and also missing
abort exceptions due invalid calls. We don't test invalid calls where the
fortify wrappers will thrown a compile warning.

> For some fun context, with glibc 2.41 the ChromiumOS downstream clang fortify patch went from:
> 17 files changed, 1114 insertions(+), 621 deletions(-) to 7 files changed, 67 insertions(+), 36 deletions(-)
> 
> The remaining 67(+), 36(-) is exactly this patch, so sweet! :)

Nice.

> 
>>
>> This seems not really related to the described issues in commit message and not really clang-specific since gcc also supports __format__ attribute.  So I think we should be a different change.
> 
> Yes, I'll split this into separate smaller patches, each with their own separate reasoning, because indeed there are multiple separate issues here.
> 
> Thanks again for everything!
  
Adhemerval Zanella Netto April 10, 2025, 6:40 p.m. UTC | #6
On 27/03/25 13:39, Sam James wrote:
> Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> writes:
> 
>> [...]
> 
>> Unfortunately we don't have tests for the compiler warning itself,
>> just for the runtime behavior.  And I recently updated my clang branch [1]
>> and I don't see any regression with debug fortify tests with clang 18/19/20/main.
> 
> (FWIW, I don't have much capacity at the moment, but in a few months, if
> you want to either send some of that out in batches, or otherwise
> coordinate on getting some of that in, let me know, and I'll provide review.)
> 
>> [...]

Hi Sam,

I finally update my clang branch [1] and cleanup some patches after the H.J
work to support TEST_CC.  It contains now 66 patches, 49 to enable build and
17 to fixes some test regressions.

I used clang versions 18, 19, 20, and master and focused on the main 64 bits
architectures.  In a short:

  * x86_64, aarch64, and riscv builds with expected default options [2] in
    all versions. x86_64 also support --enable-cet.

  * We need either -mno-gnu-attribute for powerpc64le, or adding some Makefile
    hackery to build some objects and strip the .gnu.attributes section.

  * We need -mlong-double-128 for s390x for some compat long double support.

  * --enable-memory-tagging is broken on aarch for clang 18, 19, and 20.  I think
    because __libc_mtag_address_get_tag lacks 'memory' constraint, the optimizer
    passes are not correctly generating the correct code and emitting the 'ldg'
    regardless.  I am checking if adding the constraint fixes it.

  * Both glibc and testsuite were checked using system glibc support libraries
    (libgcc*).  Using compiler-rt ones are possible, but last time I tried it
    triggered a lot of regressions (specially on math tests).

  * I used ld.ldd from each version as the linker, along llvm related tools
    (llvm-ar, llvm-readelf, etc).

The testsuite results are quite good:

# FAIL      x86_64   aarch64    RISCV
clang-18        21        20       66
clang-19        16        20
clang-20        17        20
clang-main      17        16

  * On all architectures I see tgmath conform issues due clang wrapper header.
    I need to check if there is an opened bug report, and/or check how to fix
    it.

  * clang-18 on x86_64 show ifuncmain failures which I almost sure it is code
    generation ones. I am not sure if it is worth to dig into, since clang-19
    does not show the regressions.

  * All the math tests failure are for float128 and/or long double.  I need to
    check exactly what is happening.

  * aarch64 gmon is broken due a ABI mismatch on how clang and gcc generated the
    _mcount funtion call.  I think I have a patch somewhere, I need to double
    check if I fixed on glibc or clang.

  * There are multiple tests that uses __builtin_*_overflow that disable by
    335ba9b6c1db7030264 because it tests for __GNUC_PREREQ instead of a proper
    configure tests if the compiler supports the builtin.  I need to add a
    patch to fix it.

  * I tests RISCV on qemu using NFS and cross-test-ssh.sh.  For some reason
    I am not sure the containers tests fails because it can not obtain the
    lock, so I expect the real result for RISCV on a more streamlined
    environment would be better.

So if you could help I can start to send the patched.  Most of them are just to
handle -Wall -Werror with clang, where some patches disable some compiler flags,
while other enable/disable the warnings.  There are some to fix the code for
clang where some gccsism are assumed.


[1] https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/azanella/clang
[2] --enable-stack-protector=all, --enable-bind-now=yes, --enable-profile=yes, and
    --enable-fortify-source=2
  

Patch

diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
index d2ed65371f..0dca01ec83 100644
--- a/libio/bits/stdio2.h
+++ b/libio/bits/stdio2.h
@@ -33,7 +33,8 @@  __NTH (sprintf (char *__restrict __s, const char *__restrict __fmt, ...))
 }
 #elif __fortify_use_clang
 /* clang does not have __va_arg_pack, so defer to va_arg version.  */
-__fortify_function_error_function __attribute_overloadable__ int
+__fortify_function_error_function __attribute_overloadable__
+__attribute__ ((__format__ (__printf__, 2, 3))) int
 __NTH (sprintf (__fortify_clang_overload_arg (char *, __restrict, __s),
 		const char *__restrict __fmt, ...))
 {
@@ -71,9 +72,13 @@  __NTH (snprintf (char *__restrict __s, size_t __n,
 }
 # elif __fortify_use_clang
 /* clang does not have __va_arg_pack, so defer to va_arg version.  */
-__fortify_function_error_function __attribute_overloadable__ int
+__fortify_function_error_function __attribute_overloadable__
+__attribute__ ((__format__ (__printf__, 3, 4))) int
 __NTH (snprintf (__fortify_clang_overload_arg (char *, __restrict, __s),
 		 size_t __n, const char *__restrict __fmt, ...))
+     __fortify_clang_warning_only_if_bos_lt(__n, __s,
+					    "call to snprintf may overflow "
+					    "the destination buffer")
 {
   __gnuc_va_list __fortify_ap;
   __builtin_va_start (__fortify_ap, __fmt);
@@ -89,13 +94,14 @@  __NTH (snprintf (__fortify_clang_overload_arg (char *, __restrict, __s),
 			    __glibc_objsize (str), __VA_ARGS__)
 # endif
 
-__fortify_function __attribute_overloadable__ int
+__fortify_function __attribute_overloadable__
+__attribute__ ((__format__ (__printf__, 3, 0))) int
 __NTH (vsnprintf (__fortify_clang_overload_arg (char *, __restrict, __s),
 		  size_t __n, const char *__restrict __fmt,
 		  __gnuc_va_list __ap))
-     __fortify_clang_warning (__fortify_clang_bos_static_lt (__n, __s),
-			      "call to vsnprintf may overflow the destination "
-			      "buffer")
+     __fortify_clang_warning_only_if_bos_lt(__n, __s,
+					    "call to vsnprintf may overflow "
+					    "the destination buffer")
 {
   return __builtin___vsnprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
 				    __glibc_objsize (__s), __fmt, __ap);
@@ -119,7 +125,9 @@  printf (const char *__restrict __fmt, ...)
 }
 # elif __fortify_use_clang
 /* clang does not have __va_arg_pack, so defer to va_arg version.  */
-__fortify_function_error_function __attribute_overloadable__ __nonnull ((1)) int
+__fortify_function_error_function __attribute_overloadable__ __nonnull ((1))
+__attribute__ ((__format__ (__printf__, 2, 3)))
+int
 fprintf (__fortify_clang_overload_arg (FILE *, __restrict, __stream),
 	 const char *__restrict __fmt, ...)
 {
@@ -131,7 +139,8 @@  fprintf (__fortify_clang_overload_arg (FILE *, __restrict, __stream),
   return __r;
 }
 
-__fortify_function_error_function __attribute_overloadable__ int
+__fortify_function_error_function __attribute_overloadable__
+__attribute__ ((__format__ (__printf__, 1, 2))) int
 printf (__fortify_clang_overload_arg (const char *, __restrict, __fmt), ...)
 {
   __gnuc_va_list __fortify_ap;
@@ -148,7 +157,8 @@  printf (__fortify_clang_overload_arg (const char *, __restrict, __fmt), ...)
   __fprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
 # endif
 
-__fortify_function __attribute_overloadable__ int
+__fortify_function __attribute_overloadable__
+__attribute__ ((__format__ (__printf__, 1, 0))) int
 vprintf (__fortify_clang_overload_arg (const char *, __restrict, __fmt),
 	 __gnuc_va_list __ap)
 {
@@ -175,7 +185,8 @@  dprintf (int __fd, const char *__restrict __fmt, ...)
 			__va_arg_pack ());
 }
 #  elif __fortify_use_clang
-__fortify_function_error_function __attribute_overloadable__ int
+__fortify_function_error_function __attribute_overloadable__
+__attribute__ ((__format__ (__printf__, 2, 3))) int
 dprintf (int __fd, __fortify_clang_overload_arg (const char *, __restrict,
 						 __fmt), ...)
 {
@@ -223,7 +234,9 @@  __NTH (obstack_printf (struct obstack *__restrict __obstack,
 			       __va_arg_pack ());
 }
 #  elif __fortify_use_clang
-__fortify_function_error_function __attribute_overloadable__ int
+__fortify_function_error_function __attribute_overloadable__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+__wur int
 __NTH (asprintf (__fortify_clang_overload_arg (char **, __restrict, __ptr),
 		 const char *__restrict __fmt, ...))
 {
@@ -247,7 +260,8 @@  __NTH (__asprintf (__fortify_clang_overload_arg (char **, __restrict, __ptr),
   return __r;
 }
 
-__fortify_function_error_function __attribute_overloadable__ int
+__fortify_function_error_function __attribute_overloadable__
+__attribute__ ((__format__ (__printf__, 2, 3))) int
 __NTH (obstack_printf (__fortify_clang_overload_arg (struct obstack *,
 						     __restrict, __obstack),
 		       const char *__restrict __fmt, ...))
diff --git a/misc/bits/syslog.h b/misc/bits/syslog.h
index 9907a28cbe..ca3132e09c 100644
--- a/misc/bits/syslog.h
+++ b/misc/bits/syslog.h
@@ -37,7 +37,8 @@  syslog (int __pri, const char *__fmt, ...)
   __syslog_chk (__pri, __USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
 }
 #elif __fortify_use_clang && defined __USE_MISC
-__fortify_function_error_function __attribute_overloadable__ void
+__fortify_function_error_function __attribute_overloadable__
+__attribute__ ((__format__ (__printf__, 2, 3))) void
 syslog (int __pri, __fortify_clang_overload_arg (const char *, , __fmt), ...)
 {
   __gnuc_va_list __fortify_ap;
@@ -52,7 +53,8 @@  syslog (int __pri, __fortify_clang_overload_arg (const char *, , __fmt), ...)
 
 
 #ifdef __USE_MISC
-__fortify_function __attribute_overloadable__ void
+__fortify_function __attribute_overloadable__
+__attribute__ ((__format__ (__printf__, 2, 0))) void
 vsyslog (int __pri, __fortify_clang_overload_arg (const char *, ,__fmt),
 	 __gnuc_va_list __ap)
 {
diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h
index f3428135ec..0af7b5e53c 100644
--- a/posix/bits/unistd.h
+++ b/posix/bits/unistd.h
@@ -79,7 +79,7 @@  pread64 (int __fd, __fortify_clang_overload_arg0 (void *, ,__buf),
 #if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K
 __fortify_function __attribute_overloadable__ __nonnull ((1, 2)) __wur ssize_t
 __NTH (readlink (const char *__restrict __path,
-		 __fortify_clang_overload_arg0 (char *, __restrict, __buf),
+		 __fortify_clang_overload_arg (char *, __restrict, __buf),
 		 size_t __len))
      __fortify_clang_warning_only_if_bos_lt (__len, __buf,
 					     "readlink called with bigger length "
@@ -122,6 +122,9 @@  __NTH (getcwd (__fortify_clang_overload_arg (char *, , __buf), size_t __size))
 __fortify_function __attribute_overloadable__ __nonnull ((1))
 __attribute_deprecated__ __wur char *
 __NTH (getwd (__fortify_clang_overload_arg (char *,, __buf)))
+     __fortify_clang_warning (__glibc_objsize (__buf) == (size_t) -1,
+			      "please use getcwd instead, as getwd "
+			      "doesn't specify buffer size")
 {
   if (__glibc_objsize (__buf) != (size_t) -1)
     return __getwd_chk (__buf, __glibc_objsize (__buf));
diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
index 12f9cfd58f..58c51faaf8 100644
--- a/stdlib/bits/stdlib.h
+++ b/stdlib/bits/stdlib.h
@@ -129,7 +129,7 @@  __fortify_function __attribute_overloadable__ size_t
 __NTH (mbstowcs (__fortify_clang_overload_arg (wchar_t *, __restrict, __dst),
 		 const char *__restrict __src,
 		 size_t __len))
-     __fortify_clang_warning_only_if_bos0_lt2 (__len, __dst, sizeof (wchar_t),
+     __fortify_clang_warning_only_if_bos_lt2 (__len, __dst, sizeof (wchar_t),
 					       "mbstowcs called with dst buffer "
 					       "smaller than len * sizeof (wchar_t)")
 {
@@ -159,6 +159,9 @@  __fortify_function __attribute_overloadable__ size_t
 __NTH (wcstombs (__fortify_clang_overload_arg (char *, __restrict, __dst),
 		 const wchar_t *__restrict __src,
 		 size_t __len))
+     __fortify_clang_warning_only_if_bos_lt (__len, __dst,
+					      "wcstombs called with dst buffer "
+					      "smaller than len")
 {
   return __glibc_fortify (wcstombs, __len, sizeof (char),
 			  __glibc_objsize (__dst),
diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h
index ae14cfbab0..2512bc0517 100644
--- a/string/bits/string_fortified.h
+++ b/string/bits/string_fortified.h
@@ -22,25 +22,29 @@ 
 # error "Never use <bits/string_fortified.h> directly; include <string.h> instead."
 #endif
 
-__fortify_function void *
-__NTH (memcpy (void *__restrict __dest, const void *__restrict __src,
-	       size_t __len))
+__fortify_function __attribute_overloadable__ void *
+__NTH (memcpy (__fortify_clang_overload_arg0 (void *, __restrict, __dest),
+	       const void *__restrict __src, size_t __len))
+     __fortify_clang_warn_if_dest_too_small0 (__dest, __len)
 {
   return __builtin___memcpy_chk (__dest, __src, __len,
 				 __glibc_objsize0 (__dest));
 }
 
-__fortify_function void *
-__NTH (memmove (void *__dest, const void *__src, size_t __len))
+__fortify_function __attribute_overloadable__ void *
+__NTH (memmove (__fortify_clang_overload_arg0 (void *, __restrict, __dest),
+		const void *__src, size_t __len))
+     __fortify_clang_warn_if_dest_too_small0 (__dest, __len)
 {
   return __builtin___memmove_chk (__dest, __src, __len,
 				  __glibc_objsize0 (__dest));
 }
 
 #ifdef __USE_GNU
-__fortify_function void *
-__NTH (mempcpy (void *__restrict __dest, const void *__restrict __src,
-		size_t __len))
+__fortify_function __attribute_overloadable__ void *
+__NTH (mempcpy (__fortify_clang_overload_arg0 (void *, __restrict, __dest),
+                const void *__restrict __src, size_t __len))
+     __fortify_clang_warn_if_dest_too_small0 (__dest, __len)
 {
   return __builtin___mempcpy_chk (__dest, __src, __len,
 				  __glibc_objsize0 (__dest));
@@ -53,8 +57,10 @@  __NTH (mempcpy (void *__restrict __dest, const void *__restrict __src,
    especially problematic if the intended fill value is zero.  In this
    case no work is done at all.  We detect these problems by referring
    non-existing functions.  */
-__fortify_function void *
-__NTH (memset (void *__dest, int __ch, size_t __len))
+__fortify_function __attribute_overloadable__ void *
+__NTH (memset (__fortify_clang_overload_arg0 (void *, __restrict, __dest),
+	       int __ch, size_t __len))
+     __fortify_clang_warn_if_dest_too_small0 (__dest, __len)
 {
   return __builtin___memset_chk (__dest, __ch, __len,
 				 __glibc_objsize0 (__dest));
diff --git a/string/bits/strings_fortified.h b/string/bits/strings_fortified.h
index be65d5937d..327288f289 100644
--- a/string/bits/strings_fortified.h
+++ b/string/bits/strings_fortified.h
@@ -19,15 +19,18 @@ 
 #ifndef __STRINGS_FORTIFIED
 # define __STRINGS_FORTIFIED 1
 
-__fortify_function void
-__NTH (bcopy (const void *__src, void *__dest, size_t __len))
+__fortify_function __attribute_overloadable__ void
+__NTH (bcopy (const void *__src, __fortify_clang_overload_arg0 (void *, , __dest),
+	      size_t __len))
+     __fortify_clang_warn_if_dest_too_small0 (__dest, __len)
 {
   (void) __builtin___memmove_chk (__dest, __src, __len,
 				  __glibc_objsize0 (__dest));
 }
 
-__fortify_function void
-__NTH (bzero (void *__dest, size_t __len))
+__fortify_function __attribute_overloadable__ void
+__NTH (bzero (__fortify_clang_overload_arg0 (void *, , __dest), size_t __len))
+     __fortify_clang_warn_if_dest_too_small0 (__dest, __len)
 {
   (void) __builtin___memset_chk (__dest, '\0', __len,
 				 __glibc_objsize0 (__dest));
diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
index c1a1da8166..609cc76986 100644
--- a/wcsmbs/bits/wchar2.h
+++ b/wcsmbs/bits/wchar2.h
@@ -21,7 +21,7 @@ 
 #endif
 
 __fortify_function __attribute_overloadable__ wchar_t *
-__NTH (wmemcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
+__NTH (wmemcpy (__fortify_clang_overload_arg0 (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 "
@@ -33,7 +33,7 @@  __NTH (wmemcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
 }
 
 __fortify_function __attribute_overloadable__ wchar_t *
-__NTH (wmemmove (__fortify_clang_overload_arg (wchar_t *, ,__s1),
+__NTH (wmemmove (__fortify_clang_overload_arg0 (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 "
@@ -46,7 +46,7 @@  __NTH (wmemmove (__fortify_clang_overload_arg (wchar_t *, ,__s1),
 
 #ifdef __USE_GNU
 __fortify_function __attribute_overloadable__ wchar_t *
-__NTH (wmempcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
+__NTH (wmempcpy (__fortify_clang_overload_arg0 (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 "
@@ -59,7 +59,7 @@  __NTH (wmempcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
 #endif
 
 __fortify_function __attribute_overloadable__ wchar_t *
-__NTH (wmemset (__fortify_clang_overload_arg (wchar_t *, ,__s), wchar_t __c,
+__NTH (wmemset (__fortify_clang_overload_arg0 (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 "
@@ -93,7 +93,7 @@  __NTH (wcpcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
 __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),
+     __fortify_clang_warning_only_if_bos_lt2 (__n, __dest, sizeof (wchar_t),
 					       "wcsncpy called with length bigger "
 					       "than size of destination buffer")
 {
@@ -105,7 +105,7 @@  __NTH (wcsncpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
 __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),
+     __fortify_clang_warning_only_if_bos_lt2 (__n, __dest, sizeof (wchar_t),
 					       "wcpncpy called with length bigger "
 					       "than size of destination buffer")
 {