diff mbox series

[RFC] Refactoring FORTIFY

Message ID CAKh6zBFAGomCFc+Y9=qpH-2N6AonKUja1R+cWy=p_=T=rs29cQ@mail.gmail.com
State New
Headers show
Series [RFC] Refactoring FORTIFY | expand

Commit Message

George Burgess IV Sept. 11, 2017, 6:26 a.m. UTC
Hello,

Attached is a patch that aims to substantially improve FORTIFY's
usefulness with clang, and make defining FORTIFY'ed functions require
less ceremony.

I'm not looking for a thorough review at this time, nor do I hope to
land this patch in one piece. The goal of this thread is to ensure
that everyone's more or less happy with where I'd like to take glibc's
FORTIFY implementation.

Please note that this change is intended to be a functional nop for
all compilers that aren't clang >= 5.0, which was just released last
Thursday.

Diving in: as said, this patch removes a lot of duplication from
FORTIFY in the common case, and makes FORTIFY far more useful for
those who use glibc with clang. Namely, with this patch, clang becomes
capable of emitting compile-time diagnostics on par (*) with GCC's,
and clang's ability to perform run-time checks is substantially
improved over what we have today.

It essentially does this by wrapping up the majority of the
compiler-specific incantations (declaring __foo_chk_warn,
conditionally calling it, ...) behind a macro, and uses that to stamp
out FORTIFY's compile-time diagnostic bits. While this approach is the
cleanest I've been able to come up with, it has potential downsides:

- Compile-time diagnostics with GCC are somewhat different than what
they are today. To show this, I've attached tst-chk2-output.diff,
which is a diff of the diagnostics produced by running GCC 7.1 on
debug/tst-chk2.c. I don't find the difference to be substantial, but
it does exist.
- In very rare cases, the code generated by GCC will be a bit worse
(e.g. slower+larger) with this patch. I know this may be a tough sell,
but please hear me out. :)

With this patch, we sometimes emit diagnostics by emitting code like:
if (should_emit_compile_time_warning) {
  volatile char c = 0;
  if (__glibc_unlikely (c))
    function_with_warnattr ();
}

Where `should_emit_compile_time_warning` always folds to a constant
during compilation. So, 0 diagnostics should mean 0 change in code
quality.

I don't believe this is a deal-breaker, since:
- if you're using FORTIFY, you presumably care enough to fix
FORTIFY-related warnings, which makes this regression nonexistent for
you,
- if you're using FORTIFY, you know there will be a (small, but
present) performance penalty,
- directly after each __glibc_unlikely(c) branch is call to a FORTIFY
function with known broken input, which should abort the program
anyway, and
- this doesn't apply to *all* diagnostics (e.g. bad calls to open()
don't have this penalty); just ones where we can unify clang's and
GCC's diagnostic emission bits.

In any case, please see binary-output.diff for an idea of the
difference this makes on code compiled with GCC 7.1. The function
being compiled was a call to wmemmove with an undersized buffer. With
a sufficiently large buffer, both today's FORTIFY implementation and
the proposed one produce identical bodies for the function in
question.

Other than that, I know of no regressions that this patch causes with GCC.

For clang, in very rare cases (read: I've seen ~10 instances of this
testing similar implementations across Android, ChromeOS, and another
very large code base), it can also break existing code. For specifics
on that, and an overview on how clang's FORTIFY implementation works,
please see
https://docs.google.com/document/d/1DFfZDICTbL7RqS74wJVIJ-YnjQOj1SaoqfhbgddFYSM/edit?usp=sharing
The "How does clang handle it?" section covers the primary attributes
this patch uses, and the "Incompatibilities between clang and GCC
FORTIFY" section covers places where this patch might break existing
clang users.

Though I expect clang breakages to be very rare and trivial to fix,
this patch introduces a _CLANG_FORTIFY_DISABLE macro, which can be
used to turn this entire patch into a nop for clang >= 5.0.

-----

I apologize if this is a lot to dump into one email. As said, if we
decide this is an acceptable direction to head in, I hope to land this
patch in many easily reviewable parts later on.

If you have any questions, comments, concerns, etc. please don't
hesitate to voice them.

Thank you very much for your time, :)
George

(*) - This means that clang can catch almost as many *types* of bugs
as GCC at compile-time. Due to architectural constraints, clang can
only perform these checks prior to optimizing code.
So, clang is still unable to statically diagnose bugs that require it
to do more than simple constant folding. __builtin_object_size,
however, isn't required to be folded until after we optimize code, so
many dynamic checks can still take advantage of optimizations.
commit 6259c783b44c876329bb174327b8956cd074e5cb
Author: George Burgess IV <gbiv@google.com>
Date:   Sun Sep 10 20:51:51 2017 -0700

    Refactor FORTIFY in glibc.
    
    This is intended to be a preview.  ChangeLog entry + sane commit
    messages will be added.
--- /tmp/glibc-master-binary.txt	2017-09-10 20:36:17.813220835 -0700
+++ /tmp/glibc-new-fortify-binary.txt	2017-09-10 20:35:57.859886341 -0700
@@ -6,10 +6,17 @@
 
 0000000000000000 <foo>:
    0:	48 83 ec 18          	sub    $0x18,%rsp
-   4:	b9 01 00 00 00       	mov    $0x1,%ecx
-   9:	ba 02 00 00 00       	mov    $0x2,%edx
-   e:	48 8d 74 24 08       	lea    0x8(%rsp),%rsi
-  13:	48 8d 7e 04          	lea    0x4(%rsi),%rdi
-  17:	e8 00 00 00 00       	callq  1c <foo+0x1c>
-  1c:	48 83 c4 18          	add    $0x18,%rsp
-  20:	c3                   	retq   
+   4:	c6 44 24 07 00       	movb   $0x0,0x7(%rsp)
+   9:	0f b6 44 24 07       	movzbl 0x7(%rsp),%eax
+   e:	84 c0                	test   %al,%al
+  10:	75 1e                	jne    30 <foo+0x30>
+  12:	48 8d 74 24 08       	lea    0x8(%rsp),%rsi
+  17:	b9 01 00 00 00       	mov    $0x1,%ecx
+  1c:	ba 02 00 00 00       	mov    $0x2,%edx
+  21:	48 8d 7e 04          	lea    0x4(%rsi),%rdi
+  25:	e8 00 00 00 00       	callq  2a <foo+0x2a>
+  2a:	48 83 c4 18          	add    $0x18,%rsp
+  2e:	c3                   	retq   
+  2f:	90                   	nop
+  30:	e8 00 00 00 00       	callq  35 <foo+0x35>
+  35:	eb db                	jmp    12 <foo+0x12>
--- /tmp/glibc-master-output.txt	2017-09-10 20:15:41.383148903 -0700
+++ /tmp/glibc-new-fortify-output.txt	2017-09-10 20:15:33.396481772 -0700
@@ -43,12 +43,12 @@
                  from tst-chk2.c:2:
 In function ‘memcpy’,
     inlined from ‘do_test’ at tst-chk1.c:318:3:
-../string/bits/string_fortified.h:34:10: warning: ‘__builtin___memcpy_chk’ writing 10 bytes into a region of size 9 overflows the destination [-Wstringop-overflow=]
+../string/bits/string_fortified.h:48:10: warning: ‘__builtin___memcpy_chk’ writing 10 bytes into a region of size 9 overflows the destination [-Wstringop-overflow=]
    return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In function ‘memmove’,
     inlined from ‘do_test’ at tst-chk1.c:326:3:
-../string/bits/string_fortified.h:40:10: warning: ‘__builtin___memmove_chk’ writing 9 bytes into a region of size 8 overflows the destination [-Wstringop-overflow=]
+../string/bits/string_fortified.h:56:10: warning: ‘__builtin___memmove_chk’ writing 9 bytes into a region of size 8 overflows the destination [-Wstringop-overflow=]
    return __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest));
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In file included from ../include/bits/strings_fortified.h:1:0,
@@ -62,7 +62,7 @@
                  from tst-chk2.c:2:
 In function ‘bcopy’,
     inlined from ‘do_test’ at tst-chk1.c:334:3:
-../string/bits/strings_fortified.h:25:3: warning: ‘__builtin___memmove_chk’ writing 9 bytes into a region of size 8 overflows the destination [-Wstringop-overflow=]
+../string/bits/strings_fortified.h:34:3: warning: ‘__builtin___memmove_chk’ writing 9 bytes into a region of size 8 overflows the destination [-Wstringop-overflow=]
    (void) __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest));
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In file included from ../include/bits/string_fortified.h:1:0,
@@ -74,12 +74,12 @@
                  from tst-chk2.c:2:
 In function ‘mempcpy’,
     inlined from ‘do_test’ at tst-chk1.c:342:16:
-../string/bits/string_fortified.h:48:10: warning: ‘__builtin___mempcpy_chk’ writing 5 bytes into a region of size 4 overflows the destination [-Wstringop-overflow=]
+../string/bits/string_fortified.h:65:10: warning: ‘__builtin___mempcpy_chk’ writing 5 bytes into a region of size 4 overflows the destination [-Wstringop-overflow=]
    return __builtin___mempcpy_chk (__dest, __src, __len, __bos0 (__dest));
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In function ‘memset’,
     inlined from ‘do_test’ at tst-chk1.c:350:3:
-../string/bits/string_fortified.h:71:10: warning: ‘__builtin___memset_chk’ writing 2 bytes into a region of size 1 overflows the destination [-Wstringop-overflow=]
+../string/bits/string_fortified.h:98:10: warning: ‘__builtin___memset_chk’ writing 2 bytes into a region of size 1 overflows the destination [-Wstringop-overflow=]
    return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest));
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In file included from ../include/bits/strings_fortified.h:1:0,
@@ -93,7 +93,7 @@
                  from tst-chk2.c:2:
 In function ‘bzero’,
     inlined from ‘do_test’ at tst-chk1.c:358:3:
-../string/bits/strings_fortified.h:31:3: warning: ‘__builtin___memset_chk’ writing 2 bytes into a region of size 1 overflows the destination [-Wstringop-overflow=]
+../string/bits/strings_fortified.h:42:3: warning: ‘__builtin___memset_chk’ writing 2 bytes into a region of size 1 overflows the destination [-Wstringop-overflow=]
    (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest));
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In file included from ../include/bits/string_fortified.h:1:0,
@@ -105,12 +105,12 @@
                  from tst-chk2.c:2:
 In function ‘strncpy’,
     inlined from ‘do_test’ at tst-chk1.c:382:3:
-../string/bits/string_fortified.h:106:10: warning: ‘__builtin___strncpy_chk’: specified bound 4 exceeds the size 3 of the destination [-Wstringop-overflow=]
+../string/bits/string_fortified.h:140:10: warning: ‘__builtin___strncpy_chk’: specified bound 4 exceeds the size 3 of the destination [-Wstringop-overflow=]
    return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In function ‘stpncpy’,
     inlined from ‘do_test’ at tst-chk1.c:390:3:
-../string/bits/string_fortified.h:120:12: warning: ‘__builtin___strncpy_chk’: specified bound 5 exceeds the size 4 of the destination [-Wstringop-overflow=]
+../string/bits/string_fortified.h:155:12: warning: ‘__builtin___strncpy_chk’: specified bound 5 exceeds the size 4 of the destination [-Wstringop-overflow=]
      return __stpncpy_chk (__dest, __src, __n, __bos (__dest));
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In file included from ../libio/stdio.h:862:0,
@@ -119,11 +119,9 @@
                  from tst-chk2.c:2:
 In function ‘snprintf’,
     inlined from ‘do_test’ at tst-chk1.c:403:3:
-../libio/bits/stdio2.h:64:10: warning: ‘__builtin___snprintf_chk’: specified bound 3 exceeds the size 2 of the destination [-Wstringop-overflow=]
-   return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
-          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos (__s), __fmt, __va_arg_pack ());
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../libio/bits/stdio2.h:79:7: warning: ‘__builtin___snprintf_chk’: specified bound 3 exceeds the size 2 of the destination [-Wstringop-overflow=]
+   int __result = __FORTIFY_CALL_VA_BUILTIN (snprintf, __s, __n,
+       ^~~~~~~~
 In file included from ../include/bits/string_fortified.h:1:0,
                  from ../string/string.h:494,
                  from ../include/string.h:56,
@@ -133,12 +131,12 @@
                  from tst-chk2.c:2:
 In function ‘memcpy’,
     inlined from ‘do_test’ at tst-chk1.c:435:3:
-../string/bits/string_fortified.h:34:10: warning: ‘__builtin___memcpy_chk’ writing 10 bytes into a region of size 9 overflows the destination [-Wstringop-overflow=]
+../string/bits/string_fortified.h:48:10: warning: ‘__builtin___memcpy_chk’ writing 10 bytes into a region of size 9 overflows the destination [-Wstringop-overflow=]
    return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In function ‘memmove’,
     inlined from ‘do_test’ at tst-chk1.c:443:3:
-../string/bits/string_fortified.h:40:10: warning: ‘__builtin___memmove_chk’ writing 9 bytes into a region of size 8 overflows the destination [-Wstringop-overflow=]
+../string/bits/string_fortified.h:56:10: warning: ‘__builtin___memmove_chk’ writing 9 bytes into a region of size 8 overflows the destination [-Wstringop-overflow=]
    return __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest));
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In file included from ../include/bits/strings_fortified.h:1:0,
@@ -152,7 +150,7 @@
                  from tst-chk2.c:2:
 In function ‘bcopy’,
     inlined from ‘do_test’ at tst-chk1.c:451:3:
-../string/bits/strings_fortified.h:25:3: warning: ‘__builtin___memmove_chk’ writing 9 bytes into a region of size 8 overflows the destination [-Wstringop-overflow=]
+../string/bits/strings_fortified.h:34:3: warning: ‘__builtin___memmove_chk’ writing 9 bytes into a region of size 8 overflows the destination [-Wstringop-overflow=]
    (void) __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest));
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In file included from ../include/bits/string_fortified.h:1:0,
@@ -164,12 +162,12 @@
                  from tst-chk2.c:2:
 In function ‘mempcpy’,
     inlined from ‘do_test’ at tst-chk1.c:459:16:
-../string/bits/string_fortified.h:48:10: warning: ‘__builtin___mempcpy_chk’ writing 5 bytes into a region of size 4 overflows the destination [-Wstringop-overflow=]
+../string/bits/string_fortified.h:65:10: warning: ‘__builtin___mempcpy_chk’ writing 5 bytes into a region of size 4 overflows the destination [-Wstringop-overflow=]
    return __builtin___mempcpy_chk (__dest, __src, __len, __bos0 (__dest));
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In function ‘memset’,
     inlined from ‘do_test’ at tst-chk1.c:467:3:
-../string/bits/string_fortified.h:71:10: warning: ‘__builtin___memset_chk’ writing 2 bytes into a region of size 1 overflows the destination [-Wstringop-overflow=]
+../string/bits/string_fortified.h:98:10: warning: ‘__builtin___memset_chk’ writing 2 bytes into a region of size 1 overflows the destination [-Wstringop-overflow=]
    return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest));
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In file included from ../include/bits/strings_fortified.h:1:0,
@@ -183,7 +181,7 @@
                  from tst-chk2.c:2:
 In function ‘bzero’,
     inlined from ‘do_test’ at tst-chk1.c:475:3:
-../string/bits/strings_fortified.h:31:3: warning: ‘__builtin___memset_chk’ writing 2 bytes into a region of size 1 overflows the destination [-Wstringop-overflow=]
+../string/bits/strings_fortified.h:42:3: warning: ‘__builtin___memset_chk’ writing 2 bytes into a region of size 1 overflows the destination [-Wstringop-overflow=]
    (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest));
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In file included from ../include/bits/string_fortified.h:1:0,
@@ -195,7 +193,7 @@
                  from tst-chk2.c:2:
 In function ‘strncpy’,
     inlined from ‘do_test’ at tst-chk1.c:505:3:
-../string/bits/string_fortified.h:106:10: warning: ‘__builtin___strncpy_chk’: specified bound 4 exceeds the size 3 of the destination [-Wstringop-overflow=]
+../string/bits/string_fortified.h:140:10: warning: ‘__builtin___strncpy_chk’: specified bound 4 exceeds the size 3 of the destination [-Wstringop-overflow=]
    return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In file included from ../libio/stdio.h:862:0,
@@ -204,311 +202,286 @@
                  from tst-chk2.c:2:
 In function ‘snprintf’,
     inlined from ‘do_test’ at tst-chk1.c:518:3:
-../libio/bits/stdio2.h:64:10: warning: ‘__builtin___snprintf_chk’: specified bound 3 exceeds the size 2 of the destination [-Wstringop-overflow=]
-   return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
-          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos (__s), __fmt, __va_arg_pack ());
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In file included from ../include/bits/wchar2.h:1:0,
-                 from ../wcsmbs/wchar.h:783,
-                 from ../include/wchar.h:2,
-                 from tst-chk1.c:34,
+../libio/bits/stdio2.h:79:7: warning: ‘__builtin___snprintf_chk’: specified bound 3 exceeds the size 2 of the destination [-Wstringop-overflow=]
+   int __result = __FORTIFY_CALL_VA_BUILTIN (snprintf, __s, __n,
+       ^~~~~~~~
+In file included from ../include/sys/cdefs.h:3:0,
+                 from ../include/features.h:423,
+                 from tst-chk1.c:20,
                  from tst-chk2.c:2:
 In function ‘wmemcpy’,
     inlined from ‘do_test’ at tst-chk1.c:665:3:
-../wcsmbs/bits/wchar2.h:49:9: warning: call to ‘__wmemcpy_chk_warn’ declared with attribute warning: wmemcpy called with length bigger than size of destination buffer
-  return __wmemcpy_chk_warn (__s1, __s2, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos0 (__s1) / sizeof (wchar_t));
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:35:42: warning: call to ‘__wmemcpy_warn’ declared with attribute warning: wmemcpy called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemcpy_warn, __n, __s1,
+../misc/sys/cdefs.h:234:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wmemcpy’,
     inlined from ‘do_test’ at tst-chk1.c:673:3:
-../wcsmbs/bits/wchar2.h:49:9: warning: call to ‘__wmemcpy_chk_warn’ declared with attribute warning: wmemcpy called with length bigger than size of destination buffer
-  return __wmemcpy_chk_warn (__s1, __s2, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos0 (__s1) / sizeof (wchar_t));
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:35:42: warning: call to ‘__wmemcpy_warn’ declared with attribute warning: wmemcpy called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemcpy_warn, __n, __s1,
+../misc/sys/cdefs.h:234:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wmemmove’,
     inlined from ‘do_test’ at tst-chk1.c:681:3:
-../wcsmbs/bits/wchar2.h:77:9: warning: call to ‘__wmemmove_chk_warn’ declared with attribute warning: wmemmove called with length bigger than size of destination buffer
-  return __wmemmove_chk_warn (__s1, __s2, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-         __bos0 (__s1) / sizeof (wchar_t));
-         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:56:42: warning: call to ‘__wmemmove_warn’ declared with attribute warning: wmemmove called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemmove_warn, __n, __s1,
+../misc/sys/cdefs.h:234:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wmempcpy’,
     inlined from ‘do_test’ at tst-chk1.c:689:8:
-../wcsmbs/bits/wchar2.h:110:9: warning: call to ‘__wmempcpy_chk_warn’ declared with attribute warning: wmempcpy called with length bigger than size of destination buffer
-  return __wmempcpy_chk_warn (__s1, __s2, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-         __bos0 (__s1) / sizeof (wchar_t));
-         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:81:42: warning: call to ‘__wmempcpy_warn’ declared with attribute warning: wmempcpy called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmempcpy_warn, __n, __s1,
+../misc/sys/cdefs.h:234:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wmemset’,
     inlined from ‘do_test’ at tst-chk1.c:697:3:
-../wcsmbs/bits/wchar2.h:137:9: warning: call to ‘__wmemset_chk_warn’ declared with attribute warning: wmemset called with length bigger than size of destination buffer
-  return __wmemset_chk_warn (__s, __c, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos0 (__s) / sizeof (wchar_t));
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:103:42: warning: call to ‘__wmemset_warn’ declared with attribute warning: wmemset called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemset_warn, __n, __s,
+../misc/sys/cdefs.h:234:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wcsncpy’,
     inlined from ‘do_test’ at tst-chk1.c:713:3:
-../wcsmbs/bits/wchar2.h:200:9: warning: call to ‘__wcsncpy_chk_warn’ declared with attribute warning: wcsncpy called with length bigger than size of destination buffer
-  return __wcsncpy_chk_warn (__dest, __src, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos (__dest) / sizeof (wchar_t));
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:161:41: warning: call to ‘__wcsncpy_warn’ declared with attribute warning: wcsncpy called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__wcsncpy_warn, __n, __dest,
+../misc/sys/cdefs.h:244:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wcsncpy’,
     inlined from ‘do_test’ at tst-chk1.c:721:3:
-../wcsmbs/bits/wchar2.h:200:9: warning: call to ‘__wcsncpy_chk_warn’ declared with attribute warning: wcsncpy called with length bigger than size of destination buffer
-  return __wcsncpy_chk_warn (__dest, __src, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos (__dest) / sizeof (wchar_t));
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:161:41: warning: call to ‘__wcsncpy_warn’ declared with attribute warning: wcsncpy called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__wcsncpy_warn, __n, __dest,
+../misc/sys/cdefs.h:244:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wcpncpy’,
     inlined from ‘do_test’ at tst-chk1.c:725:3:
-../wcsmbs/bits/wchar2.h:231:9: warning: call to ‘__wcpncpy_chk_warn’ declared with attribute warning: wcpncpy called with length bigger than size of destination buffer
-  return __wcpncpy_chk_warn (__dest, __src, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos (__dest) / sizeof (wchar_t));
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:186:41: warning: call to ‘__wcpncpy_warn’ declared with attribute warning: wcpncpy called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__wcpncpy_warn, __n, __dest,
+../misc/sys/cdefs.h:244:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wcpncpy’,
     inlined from ‘do_test’ at tst-chk1.c:729:3:
-../wcsmbs/bits/wchar2.h:231:9: warning: call to ‘__wcpncpy_chk_warn’ declared with attribute warning: wcpncpy called with length bigger than size of destination buffer
-  return __wcpncpy_chk_warn (__dest, __src, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos (__dest) / sizeof (wchar_t));
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:186:41: warning: call to ‘__wcpncpy_warn’ declared with attribute warning: wcpncpy called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__wcpncpy_warn, __n, __dest,
+../misc/sys/cdefs.h:244:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wmemcpy’,
     inlined from ‘do_test’ at tst-chk1.c:747:3:
-../wcsmbs/bits/wchar2.h:49:9: warning: call to ‘__wmemcpy_chk_warn’ declared with attribute warning: wmemcpy called with length bigger than size of destination buffer
-  return __wmemcpy_chk_warn (__s1, __s2, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos0 (__s1) / sizeof (wchar_t));
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:35:42: warning: call to ‘__wmemcpy_warn’ declared with attribute warning: wmemcpy called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemcpy_warn, __n, __s1,
+../misc/sys/cdefs.h:234:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wmemmove’,
     inlined from ‘do_test’ at tst-chk1.c:755:3:
-../wcsmbs/bits/wchar2.h:77:9: warning: call to ‘__wmemmove_chk_warn’ declared with attribute warning: wmemmove called with length bigger than size of destination buffer
-  return __wmemmove_chk_warn (__s1, __s2, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-         __bos0 (__s1) / sizeof (wchar_t));
-         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:56:42: warning: call to ‘__wmemmove_warn’ declared with attribute warning: wmemmove called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemmove_warn, __n, __s1,
+../misc/sys/cdefs.h:234:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wmempcpy’,
     inlined from ‘do_test’ at tst-chk1.c:763:8:
-../wcsmbs/bits/wchar2.h:110:9: warning: call to ‘__wmempcpy_chk_warn’ declared with attribute warning: wmempcpy called with length bigger than size of destination buffer
-  return __wmempcpy_chk_warn (__s1, __s2, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-         __bos0 (__s1) / sizeof (wchar_t));
-         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:81:42: warning: call to ‘__wmempcpy_warn’ declared with attribute warning: wmempcpy called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmempcpy_warn, __n, __s1,
+../misc/sys/cdefs.h:234:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wmemset’,
     inlined from ‘do_test’ at tst-chk1.c:771:3:
-../wcsmbs/bits/wchar2.h:137:9: warning: call to ‘__wmemset_chk_warn’ declared with attribute warning: wmemset called with length bigger than size of destination buffer
-  return __wmemset_chk_warn (__s, __c, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos0 (__s) / sizeof (wchar_t));
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:103:42: warning: call to ‘__wmemset_warn’ declared with attribute warning: wmemset called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemset_warn, __n, __s,
+../misc/sys/cdefs.h:234:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘wcsncpy’,
     inlined from ‘do_test’ at tst-chk1.c:793:3:
-../wcsmbs/bits/wchar2.h:200:9: warning: call to ‘__wcsncpy_chk_warn’ declared with attribute warning: wcsncpy called with length bigger than size of destination buffer
-  return __wcsncpy_chk_warn (__dest, __src, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos (__dest) / sizeof (wchar_t));
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In file included from ../libio/stdio.h:862:0,
-                 from ../include/stdio.h:2,
-                 from tst-chk1.c:30,
-                 from tst-chk2.c:2:
+../wcsmbs/bits/wchar2.h:161:41: warning: call to ‘__wcsncpy_warn’ declared with attribute warning: wcsncpy called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__wcsncpy_warn, __n, __dest,
+../misc/sys/cdefs.h:244:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘fgets’,
     inlined from ‘do_test’ at tst-chk1.c:964:7:
-../libio/bits/stdio2.h:260:9: warning: call to ‘__fgets_chk_warn’ declared with attribute warning: fgets called with bigger size than length of destination buffer
-  return __fgets_chk_warn (__s, __bos (__s), __n, __stream);
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../libio/bits/stdio2.h:311:28: warning: call to ‘__fgets_warn’ declared with attribute warning: fgets called with bigger size than length of destination buffer
+      __FORTIFY_WARNING_IF (__fgets_warn, __bos_static_lt (__n, __s) && __n > 0,
+../misc/sys/cdefs.h:218:5: note: in definition of macro ‘__FORTIFY_WARNING_IF’
+     err_fn (); \
+     ^~~~~~
 In function ‘fgets_unlocked’,
     inlined from ‘do_test’ at tst-chk1.c:991:7:
-../libio/bits/stdio2.h:318:9: warning: call to ‘__fgets_unlocked_chk_warn’ declared with attribute warning: fgets_unlocked called with bigger size than length of destination buffer
-  return __fgets_unlocked_chk_warn (__s, __bos (__s), __n, __stream);
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../libio/bits/stdio2.h:355:28: warning: call to ‘__fgets_unlocked_warn’ declared with attribute warning: fgets_unlocked called with bigger size than length of destination buffer
+      __FORTIFY_WARNING_IF (__fgets_unlocked_warn,
+../misc/sys/cdefs.h:218:5: note: in definition of macro ‘__FORTIFY_WARNING_IF’
+     err_fn (); \
+     ^~~~~~
 In function ‘fread’,
     inlined from ‘do_test’ at tst-chk1.c:1021:7:
-../libio/bits/stdio2.h:292:9: warning: call to ‘__fread_chk_warn’ declared with attribute warning: fread called with bigger size * nmemb than length of destination buffer
-  return __fread_chk_warn (__ptr, __bos0 (__ptr), __size, __n, __stream);
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../libio/bits/stdio2.h:333:28: warning: call to ‘__fread_warn’ declared with attribute warning: fread called with bigger size * nmemb than length of destination buffer
+      __FORTIFY_WARNING_IF (__fread_warn, __bos0_static_lt (__size * __n, __ptr)
+../misc/sys/cdefs.h:218:5: note: in definition of macro ‘__FORTIFY_WARNING_IF’
+     err_fn (); \
+     ^~~~~~
 In function ‘fread_unlocked’,
     inlined from ‘do_test’ at tst-chk1.c:1060:7:
-../libio/bits/stdio2.h:354:9: warning: call to ‘__fread_unlocked_chk_warn’ declared with attribute warning: fread_unlocked called with bigger size * nmemb than length of destination buffer
-  return __fread_unlocked_chk_warn (__ptr, __bos0 (__ptr), __size, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __stream);
-        ~~~~~~~~~
-In file included from ../include/bits/unistd.h:1:0,
-                 from ../posix/unistd.h:1167,
-                 from ../include/unistd.h:2,
-                 from tst-chk1.c:33,
-                 from tst-chk2.c:2:
+../libio/bits/stdio2.h:381:28: warning: call to ‘__fread_unlocked_warn’ declared with attribute warning: fread_unlocked called with bigger size * n than length of destination buffer
+      __FORTIFY_WARNING_IF (__fread_unlocked_warn,
+../misc/sys/cdefs.h:218:5: note: in definition of macro ‘__FORTIFY_WARNING_IF’
+     err_fn (); \
+     ^~~~~~
 In function ‘read’,
     inlined from ‘do_test’ at tst-chk1.c:1087:7:
-../posix/bits/unistd.h:42:9: warning: call to ‘__read_chk_warn’ declared with attribute warning: read called with bigger length than size of the destination buffer
-  return __read_chk_warn (__fd, __buf, __nbytes, __bos0 (__buf));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../posix/bits/unistd.h:31:41: warning: call to ‘__read_warn’ declared with attribute warning: read called with bigger length than size of the destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT (__read_warn, __nbytes, __buf,
+../misc/sys/cdefs.h:239:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘pread’,
     inlined from ‘do_test’ at tst-chk1.c:1111:7:
-../posix/bits/unistd.h:80:9: warning: call to ‘__pread_chk_warn’ declared with attribute warning: pread called with bigger length than size of the destination buffer
-  return __pread_chk_warn (__fd, __buf, __nbytes, __offset,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-      __bos0 (__buf));
-      ~~~~~~~~~~~~~~~
+../posix/bits/unistd.h:67:41: warning: call to ‘__pread_chk_warn’ declared with attribute warning: pread called with bigger length than size of the destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT (__pread_chk_warn, __nbytes, __buf,
+../misc/sys/cdefs.h:239:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘pread64’,
     inlined from ‘do_test’ at tst-chk1.c:1137:7:
-../posix/bits/unistd.h:113:9: warning: call to ‘__pread64_chk_warn’ declared with attribute warning: pread64 called with bigger length than size of the destination buffer
-  return __pread64_chk_warn (__fd, __buf, __nbytes, __offset,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos0 (__buf));
-        ~~~~~~~~~~~~~~~
-In file included from ../include/bits/socket2.h:1:0,
-                 from ../socket/sys/socket.h:269,
-                 from ../include/sys/socket.h:2,
-                 from tst-chk1.c:37,
-                 from tst-chk2.c:2:
+../posix/bits/unistd.h:86:41: warning: call to ‘__pread64_warn’ declared with attribute warning: pread64 called with bigger length than size of the destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT (__pread64_warn, __nbytes, __buf,
+../misc/sys/cdefs.h:239:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘recv’,
     inlined from ‘do_test’ at tst-chk1.c:1208:11:
-../socket/bits/socket2.h:42:9: warning: call to ‘__recv_chk_warn’ declared with attribute warning: recv called with bigger length than size of destination buffer
-  return __recv_chk_warn (__fd, __buf, __n, __bos0 (__buf), __flags);
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../socket/bits/socket2.h:32:41: warning: call to ‘__recv_warn’ declared with attribute warning: recv called with bigger length than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT (__recv_warn, __n, __buf,
+../misc/sys/cdefs.h:239:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘recvfrom’,
     inlined from ‘do_test’ at tst-chk1.c:1239:11:
-../socket/bits/socket2.h:73:9: warning: call to ‘__recvfrom_chk_warn’ declared with attribute warning: recvfrom called with bigger length than size of destination buffer
-  return __recvfrom_chk_warn (__fd, __buf, __n, __bos0 (__buf), __flags,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-         __addr, __addr_len);
-         ~~~~~~~~~~~~~~~~~~~
-In file included from ../include/bits/unistd.h:1:0,
-                 from ../posix/unistd.h:1167,
-                 from ../include/unistd.h:2,
-                 from tst-chk1.c:33,
-                 from tst-chk2.c:2:
+../socket/bits/socket2.h:56:41: warning: call to ‘__recvfrom_warn’ declared with attribute warning: recvfrom called with bigger length than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT (__recvfrom_warn, __n, __buf,
+../misc/sys/cdefs.h:239:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘readlink’,
     inlined from ‘do_test’ at tst-chk1.c:1282:7:
-../posix/bits/unistd.h:148:9: warning: call to ‘__readlink_chk_warn’ declared with attribute warning: readlink called with bigger length than size of destination buffer
-  return __readlink_chk_warn (__path, __buf, __len, __bos (__buf));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../posix/bits/unistd.h:113:40: warning: call to ‘__readlink_warn’ declared with attribute warning: readlink called with bigger length than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__readlink_warn, __len, __buf,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘readlinkat’,
     inlined from ‘do_test’ at tst-chk1.c:1307:7:
-../posix/bits/unistd.h:182:9: warning: call to ‘__readlinkat_chk_warn’ declared with attribute warning: readlinkat called with bigger length than size of destination buffer
-  return __readlinkat_chk_warn (__fd, __path, __buf, __len,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-           __bos (__buf));
-           ~~~~~~~~~~~~~~
+../posix/bits/unistd.h:141:40: warning: call to ‘__readlinkat_warn’ declared with attribute warning: readlinkat called with bigger length than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__readlinkat_warn, __len, __buf,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘getcwd’,
     inlined from ‘do_test’ at tst-chk1.c:1361:8:
-../posix/bits/unistd.h:208:9: warning: call to ‘__getcwd_chk_warn’ declared with attribute warning: getcwd caller with bigger length than size of destination buffer
-  return __getcwd_chk_warn (__buf, __size, __bos (__buf));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In file included from ../include/bits/wchar2.h:1:0,
-                 from ../wcsmbs/wchar.h:783,
-                 from ../include/wchar.h:2,
-                 from tst-chk1.c:34,
-                 from tst-chk2.c:2:
+../posix/bits/unistd.h:160:40: warning: call to ‘__getcwd_warn’ declared with attribute warning: getcwd called with bigger length than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__getcwd_warn, __size, __buf,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘mbsrtowcs’,
     inlined from ‘do_test’ at tst-chk1.c:1467:7:
-../wcsmbs/bits/wchar2.h:484:9: warning: call to ‘__mbsrtowcs_chk_warn’ declared with attribute warning: mbsrtowcs called with dst buffer smaller than len * sizeof (wchar_t)
-  return __mbsrtowcs_chk_warn (__dst, __src, __len, __ps,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-          __bos (__dst) / sizeof (wchar_t));
-          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In file included from ../include/bits/stdlib.h:1:0,
-                 from ../stdlib/stdlib.h:905,
-                 from ../include/stdlib.h:6,
-                 from tst-chk1.c:31,
-                 from tst-chk2.c:2:
+../wcsmbs/bits/wchar2.h:439:41: warning: call to ‘__mbsrtowcs_warn’ declared with attribute warning: mbsrtowcs called with dst buffer smaller than len * sizeof (wchar_t)
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__mbsrtowcs_warn, __len, __dst,
+../misc/sys/cdefs.h:244:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘mbstowcs’,
     inlined from ‘do_test’ at tst-chk1.c:1485:7:
-../stdlib/bits/stdlib.h:123:9: warning: call to ‘__mbstowcs_chk_warn’ declared with attribute warning: mbstowcs called with dst buffer smaller than len * sizeof (wchar_t)
-  return __mbstowcs_chk_warn (__dst, __src, __len,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-          __bos (__dst) / sizeof (wchar_t));
-          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In file included from ../include/bits/wchar2.h:1:0,
-                 from ../wcsmbs/wchar.h:783,
-                 from ../include/wchar.h:2,
-                 from tst-chk1.c:34,
-                 from tst-chk2.c:2:
+../stdlib/bits/stdlib.h:105:41: warning: call to ‘__mbstowcs_warn’ declared with attribute warning: mbstowcs called with dst buffer smaller than len * sizeof (wchar_t)
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__mbstowcs_warn, __len, __dst,
+../misc/sys/cdefs.h:244:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘mbsnrtowcs’,
     inlined from ‘do_test’ at tst-chk1.c:1505:7:
-../wcsmbs/bits/wchar2.h:552:9: warning: call to ‘__mbsnrtowcs_chk_warn’ declared with attribute warning: mbsnrtowcs called with dst buffer smaller than len * sizeof (wchar_t)
-  return __mbsnrtowcs_chk_warn (__dst, __src, __nmc, __len, __ps,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-           __bos (__dst) / sizeof (wchar_t));
-           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:494:40: warning: call to ‘__mbsnrtowcs_warn’ declared with attribute warning: mbsnrtowcs called with dst buffer smaller than len * sizeof (wchar_t)
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__mbsnrtowcs_warn,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘wcsrtombs’,
     inlined from ‘do_test’ at tst-chk1.c:1524:7:
-../wcsmbs/bits/wchar2.h:517:9: warning: call to ‘__wcsrtombs_chk_warn’ declared with attribute warning: wcsrtombs called with dst buffer smaller than len
-  return __wcsrtombs_chk_warn (__dst, __src, __len, __ps, __bos (__dst));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In file included from ../include/bits/stdlib.h:1:0,
-                 from ../stdlib/stdlib.h:905,
-                 from ../include/stdlib.h:6,
-                 from tst-chk1.c:31,
-                 from tst-chk2.c:2:
+../wcsmbs/bits/wchar2.h:467:40: warning: call to ‘__wcsrtombs_warn’ declared with attribute warning: wcsrtombs called with dst buffer smaller than len
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__wcsrtombs_warn, __len, __dst,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘wcstombs’,
     inlined from ‘do_test’ at tst-chk1.c:1543:7:
-../stdlib/bits/stdlib.h:152:9: warning: call to ‘__wcstombs_chk_warn’ declared with attribute warning: wcstombs called with dst buffer smaller than len
-  return __wcstombs_chk_warn (__dst, __src, __len, __bos (__dst));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In file included from ../include/bits/wchar2.h:1:0,
-                 from ../wcsmbs/wchar.h:783,
-                 from ../include/wchar.h:2,
-                 from tst-chk1.c:34,
-                 from tst-chk2.c:2:
+../stdlib/bits/stdlib.h:130:40: warning: call to ‘__wcstombs_warn’ declared with attribute warning: wcstombs called with dst buffer smaller than len
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__wcstombs_warn, __len, __dst,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘wcsnrtombs’,
     inlined from ‘do_test’ at tst-chk1.c:1562:7:
-../wcsmbs/bits/wchar2.h:588:9: warning: call to ‘__wcsnrtombs_chk_warn’ declared with attribute warning: wcsnrtombs called with dst buffer smaller than len
-  return __wcsnrtombs_chk_warn (__dst, __src, __nwc, __len, __ps,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-           __bos (__dst));
-           ~~~~~~~~~~~~~~
-In file included from ../include/bits/stdlib.h:1:0,
-                 from ../stdlib/stdlib.h:905,
-                 from ../include/stdlib.h:6,
-                 from tst-chk1.c:31,
-                 from tst-chk2.c:2:
+../wcsmbs/bits/wchar2.h:523:40: warning: call to ‘__wcsnrtombs_warn’ declared with attribute warning: wcsnrtombs called with dst buffer smaller than len
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__wcsnrtombs_warn, __len, __dst,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘ptsname_r’,
     inlined from ‘do_test’ at tst-chk1.c:1582:11:
-../stdlib/bits/stdlib.h:71:9: warning: call to ‘__ptsname_r_chk_warn’ declared with attribute warning: ptsname_r called with buflen bigger than size of buf
-  return __ptsname_r_chk_warn (__fd, __buf, __buflen, __bos (__buf));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In file included from ../include/bits/unistd.h:1:0,
-                 from ../posix/unistd.h:1167,
-                 from ../include/unistd.h:2,
-                 from tst-chk1.c:33,
-                 from tst-chk2.c:2:
+../stdlib/bits/stdlib.h:62:40: warning: call to ‘__ptsname_r_warn’ declared with attribute warning: ptsname_r called with buflen bigger than size of buf
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__ptsname_r_warn, __buflen, __buf,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘confstr’,
     inlined from ‘do_test’ at tst-chk1.c:1594:3:
-../posix/bits/unistd.h:248:9: warning: call to ‘__confstr_chk_warn’ declared with attribute warning: confstr called with bigger length than size of destination buffer
-  return __confstr_chk_warn (__name, __buf, __len, __bos (__buf));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../posix/bits/unistd.h:203:40: warning: call to ‘__confstr_warn’ declared with attribute warning: confstr called with bigger length than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__confstr_warn, __len, __buf,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘getgroups’,
     inlined from ‘do_test’ at tst-chk1.c:1605:7:
-../posix/bits/unistd.h:273:9: warning: call to ‘__getgroups_chk_warn’ declared with attribute warning: getgroups called with bigger group count than what can fit into destination buffer
-  return __getgroups_chk_warn (__size, __list, __bos (__list));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../posix/bits/unistd.h:221:40: warning: call to ‘__getgroups_warn’ declared with attribute warning: getgroups called with bigger group count than what can fit into destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__getgroups_warn,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘ttyname_r’,
     inlined from ‘do_test’ at tst-chk1.c:1620:11:
-../posix/bits/unistd.h:299:9: warning: call to ‘__ttyname_r_chk_warn’ declared with attribute warning: ttyname_r called with bigger buflen than size of destination buffer
-  return __ttyname_r_chk_warn (__fd, __buf, __buflen, __bos (__buf));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../posix/bits/unistd.h:249:40: warning: call to ‘__ttyname_r_warn’ declared with attribute warning: ttyname_r called with bigger buflen than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__ttyname_r_warn, __buflen, __buf,
+../posix/bits/unistd.h:249:6: note: in expansion of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__ttyname_r_warn, __buflen, __buf,
+      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 In function ‘gethostname’,
     inlined from ‘do_test’ at tst-chk1.c:1632:3:
-../posix/bits/unistd.h:352:9: warning: call to ‘__gethostname_chk_warn’ declared with attribute warning: gethostname called with bigger buflen than size of destination buffer
-  return __gethostname_chk_warn (__buf, __buflen, __bos (__buf));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../posix/bits/unistd.h:291:40: warning: call to ‘__gethostname_warn’ declared with attribute warning: gethostname called with bigger buflen than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__gethostname_warn, __buflen, __buf,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘getlogin_r’,
     inlined from ‘do_test’ at tst-chk1.c:1641:3:
-../posix/bits/unistd.h:325:9: warning: call to ‘__getlogin_r_chk_warn’ declared with attribute warning: getlogin_r called with bigger buflen than size of destination buffer
-  return __getlogin_r_chk_warn (__buf, __buflen, __bos (__buf));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../posix/bits/unistd.h:269:40: warning: call to ‘__getlogin_r_warn’ declared with attribute warning: getlogin_r called with bigger buflen than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__getlogin_r_warn, __buflen, __buf,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In function ‘getdomainname’,
     inlined from ‘do_test’ at tst-chk1.c:1651:7:
-../posix/bits/unistd.h:381:9: warning: call to ‘__getdomainname_chk_warn’ declared with attribute warning: getdomainname called with bigger buflen than size of destination buffer
-  return __getdomainname_chk_warn (__buf, __buflen, __bos (__buf));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../posix/bits/unistd.h:314:40: warning: call to ‘__getdomainname_warn’ declared with attribute warning: getdomainname called with bigger buflen than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT (__getdomainname_warn, __buflen, __buf,
+../misc/sys/cdefs.h:249:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT’
+     err_fn (); \
+     ^~~~~~
 In file included from ../include/bits/select2.h:1:0,
                  from ../misc/sys/select.h:123,
                  from ../include/sys/select.h:2,
@@ -567,20 +540,21 @@
 tst-chk1.c:1684:3: note: in expansion of macro ‘FD_ISSET’
    FD_ISSET (FD_SETSIZE, &s);
    ^~~~~~~~
-In file included from ../include/bits/poll2.h:1:0,
-                 from ../io/sys/poll.h:73,
-                 from ../include/sys/poll.h:2,
-                 from tst-chk1.c:35,
+In file included from ../include/sys/cdefs.h:3:0,
+                 from ../include/features.h:423,
+                 from tst-chk1.c:20,
                  from tst-chk2.c:2:
 In function ‘poll’,
     inlined from ‘do_test’ at tst-chk1.c:1698:3:
-../include/bits/../../io/bits/poll2.h:43:9: warning: call to ‘__poll_chk_warn’ declared with attribute warning: poll called with fds buffer too small file nfds entries
-  return __poll_chk_warn (__fds, __nfds, __timeout, __bos (__fds));
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../include/bits/../../io/bits/poll2.h:36:41: warning: call to ‘__poll_warn’ declared with attribute warning: poll called with fds buffer too small
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__poll_warn, __nfds, __fds,
+../misc/sys/cdefs.h:244:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT2’
+     err_fn (); \
+     ^~~~~~
 In function ‘ppoll’,
     inlined from ‘do_test’ at tst-chk1.c:1708:3:
-../include/bits/../../io/bits/poll2.h:73:9: warning: call to ‘__ppoll_chk_warn’ declared with attribute warning: ppoll called with fds buffer too small file nfds entries
-  return __ppoll_chk_warn (__fds, __nfds, __timeout, __ss,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-      __bos (__fds));
-      ~~~~~~~~~~~~~~
+../include/bits/../../io/bits/poll2.h:58:41: warning: call to ‘__ppoll_warn’ declared with attribute warning: ppoll called with fds buffer too small file nfds entries
+      __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__ppoll_warn, __nfds, __fds,
+../misc/sys/cdefs.h:244:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS_LT2’
+     err_fn (); \
+     ^~~~~~

Comments

George Burgess IV Oct. 2, 2017, 8:11 p.m. UTC | #1
Ping. :)

(If I don't get a response after a few more pings, I'll go ahead
and split this up/try to get it reviewed.)

On Sun, Sep 10, 2017 at 11:26 PM, George Burgess IV
<george.burgess.iv@gmail.com> wrote:
> Hello,
>
> Attached is a patch that aims to substantially improve FORTIFY's
> usefulness with clang, and make defining FORTIFY'ed functions require
> less ceremony.
>
> I'm not looking for a thorough review at this time, nor do I hope to
> land this patch in one piece. The goal of this thread is to ensure
> that everyone's more or less happy with where I'd like to take glibc's
> FORTIFY implementation.
>
> Please note that this change is intended to be a functional nop for
> all compilers that aren't clang >= 5.0, which was just released last
> Thursday.
>
> Diving in: as said, this patch removes a lot of duplication from
> FORTIFY in the common case, and makes FORTIFY far more useful for
> those who use glibc with clang. Namely, with this patch, clang becomes
> capable of emitting compile-time diagnostics on par (*) with GCC's,
> and clang's ability to perform run-time checks is substantially
> improved over what we have today.
>
> It essentially does this by wrapping up the majority of the
> compiler-specific incantations (declaring __foo_chk_warn,
> conditionally calling it, ...) behind a macro, and uses that to stamp
> out FORTIFY's compile-time diagnostic bits. While this approach is the
> cleanest I've been able to come up with, it has potential downsides:
>
> - Compile-time diagnostics with GCC are somewhat different than what
> they are today. To show this, I've attached tst-chk2-output.diff,
> which is a diff of the diagnostics produced by running GCC 7.1 on
> debug/tst-chk2.c. I don't find the difference to be substantial, but
> it does exist.
> - In very rare cases, the code generated by GCC will be a bit worse
> (e.g. slower+larger) with this patch. I know this may be a tough sell,
> but please hear me out. :)
>
> With this patch, we sometimes emit diagnostics by emitting code like:
> if (should_emit_compile_time_warning) {
>   volatile char c = 0;
>   if (__glibc_unlikely (c))
>     function_with_warnattr ();
> }
>
> Where `should_emit_compile_time_warning` always folds to a constant
> during compilation. So, 0 diagnostics should mean 0 change in code
> quality.
>
> I don't believe this is a deal-breaker, since:
> - if you're using FORTIFY, you presumably care enough to fix
> FORTIFY-related warnings, which makes this regression nonexistent for
> you,
> - if you're using FORTIFY, you know there will be a (small, but
> present) performance penalty,
> - directly after each __glibc_unlikely(c) branch is call to a FORTIFY
> function with known broken input, which should abort the program
> anyway, and
> - this doesn't apply to *all* diagnostics (e.g. bad calls to open()
> don't have this penalty); just ones where we can unify clang's and
> GCC's diagnostic emission bits.
>
> In any case, please see binary-output.diff for an idea of the
> difference this makes on code compiled with GCC 7.1. The function
> being compiled was a call to wmemmove with an undersized buffer. With
> a sufficiently large buffer, both today's FORTIFY implementation and
> the proposed one produce identical bodies for the function in
> question.
>
> Other than that, I know of no regressions that this patch causes with GCC.
>
> For clang, in very rare cases (read: I've seen ~10 instances of this
> testing similar implementations across Android, ChromeOS, and another
> very large code base), it can also break existing code. For specifics
> on that, and an overview on how clang's FORTIFY implementation works,
> please see
> https://docs.google.com/document/d/1DFfZDICTbL7RqS74wJVIJ-YnjQOj1SaoqfhbgddFYSM/edit?usp=sharing
> The "How does clang handle it?" section covers the primary attributes
> this patch uses, and the "Incompatibilities between clang and GCC
> FORTIFY" section covers places where this patch might break existing
> clang users.
>
> Though I expect clang breakages to be very rare and trivial to fix,
> this patch introduces a _CLANG_FORTIFY_DISABLE macro, which can be
> used to turn this entire patch into a nop for clang >= 5.0.
>
> -----
>
> I apologize if this is a lot to dump into one email. As said, if we
> decide this is an acceptable direction to head in, I hope to land this
> patch in many easily reviewable parts later on.
>
> If you have any questions, comments, concerns, etc. please don't
> hesitate to voice them.
>
> Thank you very much for your time, :)
> George
>
> (*) - This means that clang can catch almost as many *types* of bugs
> as GCC at compile-time. Due to architectural constraints, clang can
> only perform these checks prior to optimizing code.
> So, clang is still unable to statically diagnose bugs that require it
> to do more than simple constant folding. __builtin_object_size,
> however, isn't required to be folded until after we optimize code, so
> many dynamic checks can still take advantage of optimizations.
Adhemerval Zanella Oct. 3, 2017, 7:34 p.m. UTC | #2
On 11/09/2017 03:26, George Burgess IV wrote:
> Hello,
> 
> Attached is a patch that aims to substantially improve FORTIFY's
> usefulness with clang, and make defining FORTIFY'ed functions require
> less ceremony.

Due the patch size and complexity and no indication on the message, it
would be good to know if you already have a copyright assignment, and
if your work is covered by it.

You will need it to sort this out first so someone can actually look
into your patch (which I am interested in review btw).
George Burgess IV Oct. 3, 2017, 8:53 p.m. UTC | #3
I have not signed a copyright assignment yet, though I'm more than
happy to do so. Would
http://git.savannah.gnu.org/cgit/gnulib.git/plain/doc/Copyright/request-assign.future
be the appropriate form for me to fill out and send in?

If it changes things, I wrote this as a part of my work with Google,
who says they have a CLA on file with the FSF.

Thank you,
George

On Tue, Oct 3, 2017 at 12:34 PM, Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
> On 11/09/2017 03:26, George Burgess IV wrote:
>> Hello,
>>
>> Attached is a patch that aims to substantially improve FORTIFY's
>> usefulness with clang, and make defining FORTIFY'ed functions require
>> less ceremony.
>
> Due the patch size and complexity and no indication on the message, it
> would be good to know if you already have a copyright assignment, and
> if your work is covered by it.
>
> You will need it to sort this out first so someone can actually look
> into your patch (which I am interested in review btw).
Adhemerval Zanella Oct. 5, 2017, 1:43 p.m. UTC | #4
I am not sure if Google has an assignment that cover submission of all
its engineers.  Also, I am not well versed in the requirements for the
FSF copyright assignment, the only point I have is the GLIBC wiki entry [1].

Joseph, is the wiki updated with latest guidelines and and does Google
current CLA already cover George work?

[1] https://sourceware.org/glibc/wiki/Contribution%20checklist#FSF_copyright_Assignment

On 03/10/2017 17:53, George Burgess IV wrote:
> I have not signed a copyright assignment yet, though I'm more than
> happy to do so. Would
> http://git.savannah.gnu.org/cgit/gnulib.git/plain/doc/Copyright/request-assign.future
> be the appropriate form for me to fill out and send in?
> 
> If it changes things, I wrote this as a part of my work with Google,
> who says they have a CLA on file with the FSF.
> 
> Thank you,
> George
> 
> On Tue, Oct 3, 2017 at 12:34 PM, Adhemerval Zanella
> <adhemerval.zanella@linaro.org> wrote:
>> On 11/09/2017 03:26, George Burgess IV wrote:
>>> Hello,
>>>
>>> Attached is a patch that aims to substantially improve FORTIFY's
>>> usefulness with clang, and make defining FORTIFY'ed functions require
>>> less ceremony.
>>
>> Due the patch size and complexity and no indication on the message, it
>> would be good to know if you already have a copyright assignment, and
>> if your work is covered by it.
>>
>> You will need it to sort this out first so someone can actually look
>> into your patch (which I am interested in review btw).
Joseph Myers Oct. 5, 2017, 3:48 p.m. UTC | #5
On Thu, 5 Oct 2017, Adhemerval Zanella wrote:

> I am not sure if Google has an assignment that cover submission of all
> its engineers.  Also, I am not well versed in the requirements for the
> FSF copyright assignment, the only point I have is the GLIBC wiki entry [1].
> 
> Joseph, is the wiki updated with latest guidelines and and does Google
> current CLA already cover George work?

There is a Google assignment dated 2007-03-15 for all GNU projects.

I presume that the Google-internal version of 
https://opensource.google.com/docs/patching/ mentions the FSF assignment 
and deals with any Google-specific contribution requirements.
Adhemerval Zanella Oct. 5, 2017, 8:06 p.m. UTC | #6
Thanks for the follow up, I think we are good regarding it. 

> Il giorno 05 ott 2017, alle ore 12:48, Joseph Myers <joseph@codesourcery.com> ha scritto:
> 
>> On Thu, 5 Oct 2017, Adhemerval Zanella wrote:
>> 
>> I am not sure if Google has an assignment that cover submission of all
>> its engineers.  Also, I am not well versed in the requirements for the
>> FSF copyright assignment, the only point I have is the GLIBC wiki entry [1].
>> 
>> Joseph, is the wiki updated with latest guidelines and and does Google
>> current CLA already cover George work?
> 
> There is a Google assignment dated 2007-03-15 for all GNU projects.
> 
> I presume that the Google-internal version of 
> https://opensource.google.com/docs/patching/ mentions the FSF assignment 
> and deals with any Google-specific contribution requirements.
> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com
George Burgess IV Nov. 6, 2017, 7:11 p.m. UTC | #7
Ping :)

> I think we are good regarding it

Glad to hear it!

On Thu, Oct 5, 2017 at 1:06 PM, Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
> Thanks for the follow up, I think we are good regarding it.
>
>> Il giorno 05 ott 2017, alle ore 12:48, Joseph Myers <joseph@codesourcery.com> ha scritto:
>>
>>> On Thu, 5 Oct 2017, Adhemerval Zanella wrote:
>>>
>>> I am not sure if Google has an assignment that cover submission of all
>>> its engineers.  Also, I am not well versed in the requirements for the
>>> FSF copyright assignment, the only point I have is the GLIBC wiki entry [1].
>>>
>>> Joseph, is the wiki updated with latest guidelines and and does Google
>>> current CLA already cover George work?
>>
>> There is a Google assignment dated 2007-03-15 for all GNU projects.
>>
>> I presume that the Google-internal version of
>> https://opensource.google.com/docs/patching/ mentions the FSF assignment
>> and deals with any Google-specific contribution requirements.
>>
>> --
>> Joseph S. Myers
>> joseph@codesourcery.com
Adhemerval Zanella Nov. 20, 2017, 8:03 p.m. UTC | #8
On 11/09/2017 03:26, George Burgess IV wrote:
> Hello,
> 
> Attached is a patch that aims to substantially improve FORTIFY's
> usefulness with clang, and make defining FORTIFY'ed functions require
> less ceremony.
> 
> I'm not looking for a thorough review at this time, nor do I hope to
> land this patch in one piece. The goal of this thread is to ensure
> that everyone's more or less happy with where I'd like to take glibc's
> FORTIFY implementation.

Thanks for the patch and patience. The idea sound reasonable and it will
be indeed a good addition to extend fortify functionality to clang as well.

> 
> Please note that this change is intended to be a functional nop for
> all compilers that aren't clang >= 5.0, which was just released last
> Thursday.

As a potential side note it would be good to add some short explanation
of the internal required to adjust it for clang, for instance that
__use_clang_fortify is a compiler defined flag which is (?) define only
for clang 5.0 or higher. In any case the document referenced is a good
addition for explanation, but I usually prefer to have a more self
explanatory detail on the thread and or email itself.

> 
> Diving in: as said, this patch removes a lot of duplication from
> FORTIFY in the common case, and makes FORTIFY far more useful for
> those who use glibc with clang. Namely, with this patch, clang becomes
> capable of emitting compile-time diagnostics on par (*) with GCC's,
> and clang's ability to perform run-time checks is substantially
> improved over what we have today.
> 
> It essentially does this by wrapping up the majority of the
> compiler-specific incantations (declaring __foo_chk_warn,
> conditionally calling it, ...) behind a macro, and uses that to stamp
> out FORTIFY's compile-time diagnostic bits. While this approach is the
> cleanest I've been able to come up with, it has potential downsides:
> 
> - Compile-time diagnostics with GCC are somewhat different than what
> they are today. To show this, I've attached tst-chk2-output.diff,
> which is a diff of the diagnostics produced by running GCC 7.1 on
> debug/tst-chk2.c. I don't find the difference to be substantial, but
> it does exist.

Taking your provided file as an example I do not see it as blocker
for this approach.  Although the new warning prints the macros used
to parametrize the builtins invocation, I think it still shows enough
information for debugging.  For instance:

-../libio/bits/stdio2.h:64:10: warning: ‘__builtin___snprintf_chk’: specified bound 3 exceeds the size 2 of the destination [-Wstringop-overflow=]
-   return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
-          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        __bos (__s), __fmt, __va_arg_pack ());
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../libio/bits/stdio2.h:79:7: warning: ‘__builtin___snprintf_chk’: specified bound 3 exceeds the size 2 of the destination [-Wstringop-overflow=]
+   int __result = __FORTIFY_CALL_VA_BUILTIN (snprintf, __s, __n,

Also, some seems more convoluted as:

 In function ‘wmemmove’,
     inlined from ‘do_test’ at tst-chk1.c:681:3:
-../wcsmbs/bits/wchar2.h:77:9: warning: call to ‘__wmemmove_chk_warn’ declared with attribute warning: wmemmove called with length bigger than size of destination buffer
-  return __wmemmove_chk_warn (__s1, __s2, __n,
-         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-         __bos0 (__s1) / sizeof (wchar_t));
-         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+../wcsmbs/bits/wchar2.h:56:42: warning: call to ‘__wmemmove_warn’ declared with attribute warning: wmemmove called with length bigger than size of destination buffer
+      __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemmove_warn, __n, __s1,
+../misc/sys/cdefs.h:234:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT2’
+     err_fn (); \
+     ^~~~~~

Which might trigger an warning with different internal names being used
and also with a more convoluted warning which points to an internal name
instead direct to a builtin.  I still think this is non blocker since
the warning is still meaningful and correct to point the api usage issue.

> - In very rare cases, the code generated by GCC will be a bit worse
> (e.g. slower+larger) with this patch. I know this may be a tough sell,
> but please hear me out. :)
> 
> With this patch, we sometimes emit diagnostics by emitting code like:
> if (should_emit_compile_time_warning) {
>   volatile char c = 0;
>   if (__glibc_unlikely (c))
>     function_with_warnattr ();
> }
> 
> Where `should_emit_compile_time_warning` always folds to a constant
> during compilation. So, 0 diagnostics should mean 0 change in code
> quality.
> 
> I don't believe this is a deal-breaker, since:
> - if you're using FORTIFY, you presumably care enough to fix
> FORTIFY-related warnings, which makes this regression nonexistent for
> you,
> - if you're using FORTIFY, you know there will be a (small, but
> present) performance penalty,
> - directly after each __glibc_unlikely(c) branch is call to a FORTIFY
> function with known broken input, which should abort the program
> anyway, and
> - this doesn't apply to *all* diagnostics (e.g. bad calls to open()
> don't have this penalty); just ones where we can unify clang's and
> GCC's diagnostic emission bits.

I also agree potential pessimization on code that triggers the fortify
checks is not really a blocker.  The only issue I would consider for
it would be if hot path for fortified code also get slower/larger,
but it does not seem to be the case. 

> 
> In any case, please see binary-output.diff for an idea of the
> difference this makes on code compiled with GCC 7.1. The function
> being compiled was a call to wmemmove with an undersized buffer. With
> a sufficiently large buffer, both today's FORTIFY implementation and
> the proposed one produce identical bodies for the function in
> question.
> 
> Other than that, I know of no regressions that this patch causes with GCC.
> 
> For clang, in very rare cases (read: I've seen ~10 instances of this
> testing similar implementations across Android, ChromeOS, and another
> very large code base), it can also break existing code. For specifics
> on that, and an overview on how clang's FORTIFY implementation works,
> please see
> https://docs.google.com/document/d/1DFfZDICTbL7RqS74wJVIJ-YnjQOj1SaoqfhbgddFYSM/edit?usp=sharing

For 'Incompatibilities between clang and GCC FORTIFY' chapter in your
documentation, the first one I do not see really an issue because
relying on compiler constant fold strlen is quite fragile.  The second
one seem more a minor issue, but the a compiler details for a very
specialized usage.  I do not have a strong opinion if they should be
used as blockers.

> The "How does clang handle it?" section covers the primary attributes
> this patch uses, and the "Incompatibilities between clang and GCC
> FORTIFY" section covers places where this patch might break existing
> clang users.
> 
> Though I expect clang breakages to be very rare and trivial to fix,
> this patch introduces a _CLANG_FORTIFY_DISABLE macro, which can be
> used to turn this entire patch into a nop for clang >= 5.0.

I really want to avoid a compiler specific flag to deactivate fortify
where there is already in place better approach (either adjusting
the code or disabling fortify). Also it means it would need to to
continue export such macro to maintain compatibility, which also adds
a lot of complexity with no so straightforward gains.

> 
> -----
> 
> I apologize if this is a lot to dump into one email. As said, if we
> decide this is an acceptable direction to head in, I hope to land this
> patch in many easily reviewable parts later on.

Indeed to move forward on review we will need to split this patch by
family functions, maybe an initial patch to add the required macros
and gcc required refactoring and other for family of functions or
by headers with the adjustments for clang.

The only issue I see is lacking of testing I do not have an easier
solution.  One option would to try check for clang with support for
fortify on path and add extra rules for build the fortify tests
with clang as well, but I am not sure how complex would be to adjust
current testcase for such scenario.

> 
> If you have any questions, comments, concerns, etc. please don't
> hesitate to voice them.
> 
> Thank you very much for your time, :)
> George
> 
> (*) - This means that clang can catch almost as many *types* of bugs
> as GCC at compile-time. Due to architectural constraints, clang can
> only perform these checks prior to optimizing code.
> So, clang is still unable to statically diagnose bugs that require it
> to do more than simple constant folding. __builtin_object_size,
> however, isn't required to be folded until after we optimize code, so
> many dynamic checks can still take advantage of optimizations.
>
George Burgess IV Dec. 5, 2017, 4:52 a.m. UTC | #9
Apologies for the lag; catching up from a vacation.

> __use_clang_fortify is a compiler defined flag which is (?) define only
> for clang 5.0 or higher.

The compiler feature we key off of in clang for this is
`overloadable_unmarked`, which isn't overly interesting in itself, but
it does indicate whether clang has the last feature we need
in order to implement FORTIFY in the way this patch does.

> In any case the document referenced is a good
> addition for explanation, but I usually prefer to have a more self
> explanatory detail on the thread and or email itself.

Well, it's not exactly a *short* explanation, but I did include details
on how this all works at the end of this email. Please let me know
if you had something else in mind, or if there's anything I can
expand on. :)

> I really want to avoid a compiler specific flag to deactivate fortify
> where there is already in place better approach [...]

Yeah, the goal was to be as backwards compatible as possible
(so people could still have the FORTIFY protection they have
today if they didn't want to tweak their code), but FORTIFY on
clang today doesn't really provide a great experience, so I'm
happy to keep FORTIFY all-or-nothing.

> Indeed to move forward on review we will need to split this patch by
> family functions, maybe an initial patch to add the required macros
> and gcc required refactoring and other for family of functions or
> by headers with the adjustments for clang.

Sounds good. I'll start on that shortly. :)

> The only issue I see is lacking of testing I do not have an easier
> solution.  One option would to try check for clang with support for
> fortify on path and add extra rules for build the fortify tests
> with clang as well, but I am not sure how complex would be to adjust
> current testcase for such scenario.

Good call. I'll see if I can make this work.

-------

# Details of implementation

Clang's FORTIFY implementation boils down to a set of overloads of
standard library functions. We have special attributes we can
overload on (enable_if + pass_object_size) while keeping the
same language-level function type. In overload resolution, clang
prefers functions that have these attributes over overloads without,
all else being equal, which allows us to 'intercept' all calls to
FORTIFY'ed functions.

(These overloads do all have C++-like mangled names, but they're
also all static + always_inline'd, so the fact that we're using
overloads shouldn't be easily visible to the user.)

For compile-time diagnostics, clang uses diagnose_if, which is a
function-level attribute that tries to evaluate a condition at each
callsite of a function. If the condition is true, it'll emit a warning
or error.

Due to how clang's architected (no inlining before we run
optimizations; no AST/accurate type info is available during
optimizations), we also need to use the pass_object_size(N) attribute
on function parameters that we need to call __builtin_object_size on.
This adds a hidden size_t param to the parameter's function, and
causes all calls to said function to pass __builtin_object_size(p, N)
as that hidden parameter.

There are also a number of cases where FORTIFY uses
pass_object_size on functions that don't call __builtin_object_size.
This is generally for some combination of three reasons:
- there's nothing to overload on (e.g. see printf),
- as noted above, in a set with two overloads that have identical
  signatures (in C/C++), the one with pass_object_size wins, and
- functions with one or more parameters that have the
  pass_object_size attribute cannot have their address taken.

Without the last bullet, code like:

void foo(void *fn);
void bar() { foo(open); }

breaks, since we have open(const char *, int) and
open(const char *, int, int) overloads.

Putting this all into practice, improving run-time bounds
checking for clang FORTIFY is simply an issue of adding
pass_object_size to functions. Compile-time checks, OTOH,
are a bit more interesting, since GCC wants the check to live in
the function's body, whereas clang wants it to live in a function-level
attribute. My patch adds
__FORTIFY_PRECONDITIONS/__FORTIFY_FUNCTION_END
macros, which turn into balanced braces in GCC, and are nops in
clang.

The macros that emit diagnostics (e.g.
__FORTIFY_WARNING_ONLY_IF_BOS_LT2) either turn into
diagnose_if on clang, or unfold into a FORTIFY warning function
declaration + call on GCC. The call is logically unreachable, but
done in a way that GCC can't DCE it if we need to emit a
diagnostic. Because we're hiding all of this behind a macro,
many textual FORTIFY function bodies turn into:
{
  if (__FORTIFY_CALL_CHK && __bos (__ptr) != 1)
    return __foo_chk (__ptr, __bos (__ptr), ...);
  return __foo_real (__ptr, ...);
}

...Where __FORTIFY_CALL_CHK is always 1 on clang, but
on GCC, it's a variable (which should be trivially foldable to a
constant after a tiny bit of optimization). It contains whether
or not our static checks were able to verify that the call must
be safe (0 if guaranteed safe, 1 if not). It's a bit ugly, but
it matches how we act in the current FORTIFY implementation.

True variadic functions are a bit of a pain point, since clang can't
inline them and use __va_arg_pack () like GCC does. So, if
available, clang falls back on va_arg versions (vprintf instead of
printf, ...) instead.

Finally, C's variadic fauxverloads (like open()) are handled by
actual overloads. I've yet to find a clean way to stamp these out
with macros, so this patch just uses one function per reasonable
signature of a function.

...And I think that's about it for the nitty-gritty of the actual
implementation. As you noted, going through macros makes
both GCC and Clang emit "note:"s about each macro; the
implementation of some of these macros tries to keep that to
a bare minimum, at the cost of some repetition.

Hope this helped, :)
George

On Mon, Nov 20, 2017 at 3:03 PM, Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
> On 11/09/2017 03:26, George Burgess IV wrote:
>> Hello,
>>
>> Attached is a patch that aims to substantially improve FORTIFY's
>> usefulness with clang, and make defining FORTIFY'ed functions require
>> less ceremony.
>>
>> I'm not looking for a thorough review at this time, nor do I hope to
>> land this patch in one piece. The goal of this thread is to ensure
>> that everyone's more or less happy with where I'd like to take glibc's
>> FORTIFY implementation.
>
> Thanks for the patch and patience. The idea sound reasonable and it will
> be indeed a good addition to extend fortify functionality to clang as well.
>
>>
>> Please note that this change is intended to be a functional nop for
>> all compilers that aren't clang >= 5.0, which was just released last
>> Thursday.
>
> As a potential side note it would be good to add some short explanation
> of the internal required to adjust it for clang, for instance that
> __use_clang_fortify is a compiler defined flag which is (?) define only
> for clang 5.0 or higher. In any case the document referenced is a good
> addition for explanation, but I usually prefer to have a more self
> explanatory detail on the thread and or email itself.
>
>>
>> Diving in: as said, this patch removes a lot of duplication from
>> FORTIFY in the common case, and makes FORTIFY far more useful for
>> those who use glibc with clang. Namely, with this patch, clang becomes
>> capable of emitting compile-time diagnostics on par (*) with GCC's,
>> and clang's ability to perform run-time checks is substantially
>> improved over what we have today.
>>
>> It essentially does this by wrapping up the majority of the
>> compiler-specific incantations (declaring __foo_chk_warn,
>> conditionally calling it, ...) behind a macro, and uses that to stamp
>> out FORTIFY's compile-time diagnostic bits. While this approach is the
>> cleanest I've been able to come up with, it has potential downsides:
>>
>> - Compile-time diagnostics with GCC are somewhat different than what
>> they are today. To show this, I've attached tst-chk2-output.diff,
>> which is a diff of the diagnostics produced by running GCC 7.1 on
>> debug/tst-chk2.c. I don't find the difference to be substantial, but
>> it does exist.
>
> Taking your provided file as an example I do not see it as blocker
> for this approach.  Although the new warning prints the macros used
> to parametrize the builtins invocation, I think it still shows enough
> information for debugging.  For instance:
>
> -../libio/bits/stdio2.h:64:10: warning: ‘__builtin___snprintf_chk’: specified bound 3 exceeds the size 2 of the destination [-Wstringop-overflow=]
> -   return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
> -          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> -        __bos (__s), __fmt, __va_arg_pack ());
> -        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +../libio/bits/stdio2.h:79:7: warning: ‘__builtin___snprintf_chk’: specified bound 3 exceeds the size 2 of the destination [-Wstringop-overflow=]
> +   int __result = __FORTIFY_CALL_VA_BUILTIN (snprintf, __s, __n,
>
> Also, some seems more convoluted as:
>
>  In function ‘wmemmove’,
>      inlined from ‘do_test’ at tst-chk1.c:681:3:
> -../wcsmbs/bits/wchar2.h:77:9: warning: call to ‘__wmemmove_chk_warn’ declared with attribute warning: wmemmove called with length bigger than size of destination buffer
> -  return __wmemmove_chk_warn (__s1, __s2, __n,
> -         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> -         __bos0 (__s1) / sizeof (wchar_t));
> -         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +../wcsmbs/bits/wchar2.h:56:42: warning: call to ‘__wmemmove_warn’ declared with attribute warning: wmemmove called with length bigger than size of destination buffer
> +      __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemmove_warn, __n, __s1,
> +../misc/sys/cdefs.h:234:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT2’
> +     err_fn (); \
> +     ^~~~~~
>
> Which might trigger an warning with different internal names being used
> and also with a more convoluted warning which points to an internal name
> instead direct to a builtin.  I still think this is non blocker since
> the warning is still meaningful and correct to point the api usage issue.
>
>> - In very rare cases, the code generated by GCC will be a bit worse
>> (e.g. slower+larger) with this patch. I know this may be a tough sell,
>> but please hear me out. :)
>>
>> With this patch, we sometimes emit diagnostics by emitting code like:
>> if (should_emit_compile_time_warning) {
>>   volatile char c = 0;
>>   if (__glibc_unlikely (c))
>>     function_with_warnattr ();
>> }
>>
>> Where `should_emit_compile_time_warning` always folds to a constant
>> during compilation. So, 0 diagnostics should mean 0 change in code
>> quality.
>>
>> I don't believe this is a deal-breaker, since:
>> - if you're using FORTIFY, you presumably care enough to fix
>> FORTIFY-related warnings, which makes this regression nonexistent for
>> you,
>> - if you're using FORTIFY, you know there will be a (small, but
>> present) performance penalty,
>> - directly after each __glibc_unlikely(c) branch is call to a FORTIFY
>> function with known broken input, which should abort the program
>> anyway, and
>> - this doesn't apply to *all* diagnostics (e.g. bad calls to open()
>> don't have this penalty); just ones where we can unify clang's and
>> GCC's diagnostic emission bits.
>
> I also agree potential pessimization on code that triggers the fortify
> checks is not really a blocker.  The only issue I would consider for
> it would be if hot path for fortified code also get slower/larger,
> but it does not seem to be the case.
>
>>
>> In any case, please see binary-output.diff for an idea of the
>> difference this makes on code compiled with GCC 7.1. The function
>> being compiled was a call to wmemmove with an undersized buffer. With
>> a sufficiently large buffer, both today's FORTIFY implementation and
>> the proposed one produce identical bodies for the function in
>> question.
>>
>> Other than that, I know of no regressions that this patch causes with GCC.
>>
>> For clang, in very rare cases (read: I've seen ~10 instances of this
>> testing similar implementations across Android, ChromeOS, and another
>> very large code base), it can also break existing code. For specifics
>> on that, and an overview on how clang's FORTIFY implementation works,
>> please see
>> https://docs.google.com/document/d/1DFfZDICTbL7RqS74wJVIJ-YnjQOj1SaoqfhbgddFYSM/edit?usp=sharing
>
> For 'Incompatibilities between clang and GCC FORTIFY' chapter in your
> documentation, the first one I do not see really an issue because
> relying on compiler constant fold strlen is quite fragile.  The second
> one seem more a minor issue, but the a compiler details for a very
> specialized usage.  I do not have a strong opinion if they should be
> used as blockers.
>
>> The "How does clang handle it?" section covers the primary attributes
>> this patch uses, and the "Incompatibilities between clang and GCC
>> FORTIFY" section covers places where this patch might break existing
>> clang users.
>>
>> Though I expect clang breakages to be very rare and trivial to fix,
>> this patch introduces a _CLANG_FORTIFY_DISABLE macro, which can be
>> used to turn this entire patch into a nop for clang >= 5.0.
>
> I really want to avoid a compiler specific flag to deactivate fortify
> where there is already in place better approach (either adjusting
> the code or disabling fortify). Also it means it would need to to
> continue export such macro to maintain compatibility, which also adds
> a lot of complexity with no so straightforward gains.
>
>>
>> -----
>>
>> I apologize if this is a lot to dump into one email. As said, if we
>> decide this is an acceptable direction to head in, I hope to land this
>> patch in many easily reviewable parts later on.
>
> Indeed to move forward on review we will need to split this patch by
> family functions, maybe an initial patch to add the required macros
> and gcc required refactoring and other for family of functions or
> by headers with the adjustments for clang.
>
> The only issue I see is lacking of testing I do not have an easier
> solution.  One option would to try check for clang with support for
> fortify on path and add extra rules for build the fortify tests
> with clang as well, but I am not sure how complex would be to adjust
> current testcase for such scenario.
>
>>
>> If you have any questions, comments, concerns, etc. please don't
>> hesitate to voice them.
>>
>> Thank you very much for your time, :)
>> George
>>
>> (*) - This means that clang can catch almost as many *types* of bugs
>> as GCC at compile-time. Due to architectural constraints, clang can
>> only perform these checks prior to optimizing code.
>> So, clang is still unable to statically diagnose bugs that require it
>> to do more than simple constant folding. __builtin_object_size,
>> however, isn't required to be folded until after we optimize code, so
>> many dynamic checks can still take advantage of optimizations.
>>

On Mon, Nov 20, 2017 at 12:03 PM, Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
> On 11/09/2017 03:26, George Burgess IV wrote:
>> Hello,
>>
>> Attached is a patch that aims to substantially improve FORTIFY's
>> usefulness with clang, and make defining FORTIFY'ed functions require
>> less ceremony.
>>
>> I'm not looking for a thorough review at this time, nor do I hope to
>> land this patch in one piece. The goal of this thread is to ensure
>> that everyone's more or less happy with where I'd like to take glibc's
>> FORTIFY implementation.
>
> Thanks for the patch and patience. The idea sound reasonable and it will
> be indeed a good addition to extend fortify functionality to clang as well.
>
>>
>> Please note that this change is intended to be a functional nop for
>> all compilers that aren't clang >= 5.0, which was just released last
>> Thursday.
>
> As a potential side note it would be good to add some short explanation
> of the internal required to adjust it for clang, for instance that
> __use_clang_fortify is a compiler defined flag which is (?) define only
> for clang 5.0 or higher. In any case the document referenced is a good
> addition for explanation, but I usually prefer to have a more self
> explanatory detail on the thread and or email itself.
>
>>
>> Diving in: as said, this patch removes a lot of duplication from
>> FORTIFY in the common case, and makes FORTIFY far more useful for
>> those who use glibc with clang. Namely, with this patch, clang becomes
>> capable of emitting compile-time diagnostics on par (*) with GCC's,
>> and clang's ability to perform run-time checks is substantially
>> improved over what we have today.
>>
>> It essentially does this by wrapping up the majority of the
>> compiler-specific incantations (declaring __foo_chk_warn,
>> conditionally calling it, ...) behind a macro, and uses that to stamp
>> out FORTIFY's compile-time diagnostic bits. While this approach is the
>> cleanest I've been able to come up with, it has potential downsides:
>>
>> - Compile-time diagnostics with GCC are somewhat different than what
>> they are today. To show this, I've attached tst-chk2-output.diff,
>> which is a diff of the diagnostics produced by running GCC 7.1 on
>> debug/tst-chk2.c. I don't find the difference to be substantial, but
>> it does exist.
>
> Taking your provided file as an example I do not see it as blocker
> for this approach.  Although the new warning prints the macros used
> to parametrize the builtins invocation, I think it still shows enough
> information for debugging.  For instance:
>
> -../libio/bits/stdio2.h:64:10: warning: ‘__builtin___snprintf_chk’: specified bound 3 exceeds the size 2 of the destination [-Wstringop-overflow=]
> -   return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
> -          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> -        __bos (__s), __fmt, __va_arg_pack ());
> -        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +../libio/bits/stdio2.h:79:7: warning: ‘__builtin___snprintf_chk’: specified bound 3 exceeds the size 2 of the destination [-Wstringop-overflow=]
> +   int __result = __FORTIFY_CALL_VA_BUILTIN (snprintf, __s, __n,
>
> Also, some seems more convoluted as:
>
>  In function ‘wmemmove’,
>      inlined from ‘do_test’ at tst-chk1.c:681:3:
> -../wcsmbs/bits/wchar2.h:77:9: warning: call to ‘__wmemmove_chk_warn’ declared with attribute warning: wmemmove called with length bigger than size of destination buffer
> -  return __wmemmove_chk_warn (__s1, __s2, __n,
> -         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> -         __bos0 (__s1) / sizeof (wchar_t));
> -         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +../wcsmbs/bits/wchar2.h:56:42: warning: call to ‘__wmemmove_warn’ declared with attribute warning: wmemmove called with length bigger than size of destination buffer
> +      __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemmove_warn, __n, __s1,
> +../misc/sys/cdefs.h:234:5: note: in definition of macro ‘__FORTIFY_WARNING_ONLY_IF_BOS0_LT2’
> +     err_fn (); \
> +     ^~~~~~
>
> Which might trigger an warning with different internal names being used
> and also with a more convoluted warning which points to an internal name
> instead direct to a builtin.  I still think this is non blocker since
> the warning is still meaningful and correct to point the api usage issue.
>
>> - In very rare cases, the code generated by GCC will be a bit worse
>> (e.g. slower+larger) with this patch. I know this may be a tough sell,
>> but please hear me out. :)
>>
>> With this patch, we sometimes emit diagnostics by emitting code like:
>> if (should_emit_compile_time_warning) {
>>   volatile char c = 0;
>>   if (__glibc_unlikely (c))
>>     function_with_warnattr ();
>> }
>>
>> Where `should_emit_compile_time_warning` always folds to a constant
>> during compilation. So, 0 diagnostics should mean 0 change in code
>> quality.
>>
>> I don't believe this is a deal-breaker, since:
>> - if you're using FORTIFY, you presumably care enough to fix
>> FORTIFY-related warnings, which makes this regression nonexistent for
>> you,
>> - if you're using FORTIFY, you know there will be a (small, but
>> present) performance penalty,
>> - directly after each __glibc_unlikely(c) branch is call to a FORTIFY
>> function with known broken input, which should abort the program
>> anyway, and
>> - this doesn't apply to *all* diagnostics (e.g. bad calls to open()
>> don't have this penalty); just ones where we can unify clang's and
>> GCC's diagnostic emission bits.
>
> I also agree potential pessimization on code that triggers the fortify
> checks is not really a blocker.  The only issue I would consider for
> it would be if hot path for fortified code also get slower/larger,
> but it does not seem to be the case.
>
>>
>> In any case, please see binary-output.diff for an idea of the
>> difference this makes on code compiled with GCC 7.1. The function
>> being compiled was a call to wmemmove with an undersized buffer. With
>> a sufficiently large buffer, both today's FORTIFY implementation and
>> the proposed one produce identical bodies for the function in
>> question.
>>
>> Other than that, I know of no regressions that this patch causes with GCC.
>>
>> For clang, in very rare cases (read: I've seen ~10 instances of this
>> testing similar implementations across Android, ChromeOS, and another
>> very large code base), it can also break existing code. For specifics
>> on that, and an overview on how clang's FORTIFY implementation works,
>> please see
>> https://docs.google.com/document/d/1DFfZDICTbL7RqS74wJVIJ-YnjQOj1SaoqfhbgddFYSM/edit?usp=sharing
>
> For 'Incompatibilities between clang and GCC FORTIFY' chapter in your
> documentation, the first one I do not see really an issue because
> relying on compiler constant fold strlen is quite fragile.  The second
> one seem more a minor issue, but the a compiler details for a very
> specialized usage.  I do not have a strong opinion if they should be
> used as blockers.
>
>> The "How does clang handle it?" section covers the primary attributes
>> this patch uses, and the "Incompatibilities between clang and GCC
>> FORTIFY" section covers places where this patch might break existing
>> clang users.
>>
>> Though I expect clang breakages to be very rare and trivial to fix,
>> this patch introduces a _CLANG_FORTIFY_DISABLE macro, which can be
>> used to turn this entire patch into a nop for clang >= 5.0.
>
> I really want to avoid a compiler specific flag to deactivate fortify
> where there is already in place better approach (either adjusting
> the code or disabling fortify). Also it means it would need to to
> continue export such macro to maintain compatibility, which also adds
> a lot of complexity with no so straightforward gains.
>
>>
>> -----
>>
>> I apologize if this is a lot to dump into one email. As said, if we
>> decide this is an acceptable direction to head in, I hope to land this
>> patch in many easily reviewable parts later on.
>
> Indeed to move forward on review we will need to split this patch by
> family functions, maybe an initial patch to add the required macros
> and gcc required refactoring and other for family of functions or
> by headers with the adjustments for clang.
>
> The only issue I see is lacking of testing I do not have an easier
> solution.  One option would to try check for clang with support for
> fortify on path and add extra rules for build the fortify tests
> with clang as well, but I am not sure how complex would be to adjust
> current testcase for such scenario.
>
>>
>> If you have any questions, comments, concerns, etc. please don't
>> hesitate to voice them.
>>
>> Thank you very much for your time, :)
>> George
>>
>> (*) - This means that clang can catch almost as many *types* of bugs
>> as GCC at compile-time. Due to architectural constraints, clang can
>> only perform these checks prior to optimizing code.
>> So, clang is still unable to statically diagnose bugs that require it
>> to do more than simple constant folding. __builtin_object_size,
>> however, isn't required to be folded until after we optimize code, so
>> many dynamic checks can still take advantage of optimizations.
>>
diff mbox series

Patch

diff --git a/io/bits/fcntl2.h b/io/bits/fcntl2.h
index 4109ead9a8..0e08f51c2d 100644
--- a/io/bits/fcntl2.h
+++ b/io/bits/fcntl2.h
@@ -32,10 +32,28 @@  extern int __REDIRECT (__open_2, (const char *__path, int __oflag),
 extern int __REDIRECT (__open_alias, (const char *__path, int __oflag, ...),
 		       open64) __nonnull ((1));
 #endif
-__errordecl (__open_too_many_args,
-	     "open can be called either with 2 or 3 arguments, not more");
-__errordecl (__open_missing_mode,
-	     "open with O_CREAT or O_TMPFILE in second argument needs 3 arguments");
+
+#define __warn_open_too_many_args \
+  "open can be called either with 2 or 3 arguments, not more"
+#define __warn_open_missing_mode \
+  "open with O_CREAT in second argument needs 3 arguments"
+#ifdef __use_clang_fortify
+__fortify_overload __clang_prefer_this_overload int
+open (const char *const __clang_pass_object_size __path, int __oflag)
+     __clang_error_if (__OPEN_NEEDS_MODE (__oflag), __warn_open_missing_mode)
+{
+  return __open_2 (__path, __oflag);
+}
+
+__fortify_overload int
+open (const char *const __clang_pass_object_size __path, int __oflag,
+      mode_t __mode)
+{
+  return __open_alias (__path, __oflag, __mode);
+}
+#else
+__errordecl (__open_too_many_args, __warn_open_too_many_args);
+__errordecl (__open_missing_mode, __warn_open_missing_mode);
 
 __fortify_function int
 open (const char *__path, int __oflag, ...)
@@ -58,16 +76,37 @@  open (const char *__path, int __oflag, ...)
 
   return __open_alias (__path, __oflag, __va_arg_pack ());
 }
+#endif
+#undef __warn_open_too_many_args
+#undef __warn_open_missing_mode
 
 
 #ifdef __USE_LARGEFILE64
 extern int __open64_2 (const char *__path, int __oflag) __nonnull ((1));
 extern int __REDIRECT (__open64_alias, (const char *__path, int __oflag,
 					...), open64) __nonnull ((1));
-__errordecl (__open64_too_many_args,
-	     "open64 can be called either with 2 or 3 arguments, not more");
-__errordecl (__open64_missing_mode,
-	     "open64 with O_CREAT or O_TMPFILE in second argument needs 3 arguments");
+
+# define __warn_open64_too_many_args \
+  "open64 can be called either with 2 or 3 arguments, not more"
+# define __warn_open64_missing_mode \
+  "open64 with O_CREAT in second argument needs 3 arguments"
+# ifdef __use_clang_fortify
+__fortify_overload __clang_prefer_this_overload int
+open64 (const char *const __clang_pass_object_size __path, int __oflag)
+     __clang_error_if (__OPEN_NEEDS_MODE (__oflag), __warn_open64_missing_mode)
+{
+  return __open64_2 (__path, __oflag);
+}
+
+__fortify_overload __clang_prefer_this_overload int
+open64 (const char *const __clang_pass_object_size __path, int __oflag,
+	int __mode)
+{
+  return __open64_alias (__path, __oflag, __mode);
+}
+# else
+__errordecl (__open64_too_many_args, __warn_open64_too_many_args);
+__errordecl (__open64_missing_mode, __warn_open64_missing_mode);
 
 __fortify_function int
 open64 (const char *__path, int __oflag, ...)
@@ -90,6 +129,9 @@  open64 (const char *__path, int __oflag, ...)
 
   return __open64_alias (__path, __oflag, __va_arg_pack ());
 }
+# endif
+# undef __warn_open64_too_many_args
+# undef __warn_open64_missing_mode
 #endif
 
 
@@ -108,10 +150,32 @@  extern int __REDIRECT (__openat_alias, (int __fd, const char *__path,
 					int __oflag, ...), openat64)
      __nonnull ((2));
 # endif
-__errordecl (__openat_too_many_args,
-	     "openat can be called either with 3 or 4 arguments, not more");
-__errordecl (__openat_missing_mode,
-	     "openat with O_CREAT or O_TMPFILE in third argument needs 4 arguments");
+
+# define __warn_openat_too_many_args "openat can be called either with 3 or " \
+       "4 arguments, not more"
+# define __warn_openat_missing_mode "openat with O_CREAT in third argument " \
+       "needs 4 arguments"
+# ifdef __use_clang_fortify
+__fortify_error_function __clang_error (__warn_openat_too_many_args) int
+openat (int __fd, const char *__path, int __oflag, int __mode, ...);
+
+__fortify_overload __clang_prefer_this_overload int
+openat (int __fd, const char *const __clang_pass_object_size __path,
+	int __oflag)
+     __clang_error_if (__OPEN_NEEDS_MODE (__oflag), __warn_openat_missing_mode)
+{
+  return __openat_2 (__fd, __path, __oflag);
+}
+
+__fortify_overload __clang_prefer_this_overload int
+openat (int __fd, const char *const __clang_pass_object_size __path,
+	int __oflag, int __mode)
+{
+  return __openat_alias (__fd, __path, __oflag, __mode);
+}
+# else
+__errordecl (__openat_too_many_args, __warn_openat_too_many_args);
+__errordecl (__openat_missing_mode, __warn_openat_missing_mode);
 
 __fortify_function int
 openat (int __fd, const char *__path, int __oflag, ...)
@@ -134,6 +198,9 @@  openat (int __fd, const char *__path, int __oflag, ...)
 
   return __openat_alias (__fd, __path, __oflag, __va_arg_pack ());
 }
+# endif
+# undef __warn_openat_too_many_args
+# undef __warn_openat_missing_mode
 
 
 # ifdef __USE_LARGEFILE64
@@ -142,11 +209,34 @@  extern int __openat64_2 (int __fd, const char *__path, int __oflag)
 extern int __REDIRECT (__openat64_alias, (int __fd, const char *__path,
 					  int __oflag, ...), openat64)
      __nonnull ((2));
-__errordecl (__openat64_too_many_args,
-	     "openat64 can be called either with 3 or 4 arguments, not more");
-__errordecl (__openat64_missing_mode,
-	     "openat64 with O_CREAT or O_TMPFILE in third argument needs 4 arguments");
 
+#  define __warn_openat64_too_many_args "openat64 can be called either with " \
+       "3 or 4 arguments, not more"
+#  define __warn_openat64_missing_mode "openat64 with O_CREAT in third " \
+       "argument needs 4 arguments"
+
+#  ifdef __use_clang_fortify
+__fortify_error_function __clang_error (__warn_openat64_too_many_args) int
+openat64 (int __fd, const char *__path, int __oflag, int __mode, ...);
+
+__fortify_overload __clang_prefer_this_overload int
+openat64 (int __fd, const char *const __clang_pass_object_size __path,
+	  int __oflag)
+     __clang_error_if (__OPEN_NEEDS_MODE (__oflag),
+                       __warn_openat64_missing_mode)
+{
+  return __openat64_2 (__fd, __path, __oflag);
+}
+
+__fortify_overload __clang_prefer_this_overload int
+openat64 (int __fd, const char *const __clang_pass_object_size __path,
+	  int __oflag, int __mode)
+{
+  return __openat64_alias (__fd, __path, __oflag, __mode);
+}
+#  else
+__errordecl (__openat64_too_many_args, __warn_openat64_too_many_args);
+__errordecl (__openat64_missing_mode, __warn_openat64_missing_mode);
 __fortify_function int
 openat64 (int __fd, const char *__path, int __oflag, ...)
 {
@@ -168,5 +258,8 @@  openat64 (int __fd, const char *__path, int __oflag, ...)
 
   return __openat64_alias (__fd, __path, __oflag, __va_arg_pack ());
 }
+#  endif
+#  undef __warn_openat64_too_many_args
+#  undef __warn_openat64_missing_mode
 # endif
 #endif
diff --git a/io/bits/poll2.h b/io/bits/poll2.h
index 0fbba4f325..0f7ced5ff3 100644
--- a/io/bits/poll2.h
+++ b/io/bits/poll2.h
@@ -27,25 +27,20 @@  extern int __REDIRECT (__poll_alias, (struct pollfd *__fds, nfds_t __nfds,
 				      int __timeout), poll);
 extern int __poll_chk (struct pollfd *__fds, nfds_t __nfds, int __timeout,
 		       __SIZE_TYPE__ __fdslen);
-extern int __REDIRECT (__poll_chk_warn, (struct pollfd *__fds, nfds_t __nfds,
-					 int __timeout, __SIZE_TYPE__ __fdslen),
-		       __poll_chk)
-  __warnattr ("poll called with fds buffer too small file nfds entries");
 
-__fortify_function int
-poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+__fortify_potential_overload int
+poll (struct pollfd *const __clang_pass_object_size __fds, nfds_t __nfds,
+      int __timeout)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__poll_warn, __nfds, __fds,
+					sizeof (*__fds),
+					"poll called with fds buffer too small")
 {
-  if (__bos (__fds) != (__SIZE_TYPE__) -1)
-    {
-      if (! __builtin_constant_p (__nfds))
-	return __poll_chk (__fds, __nfds, __timeout, __bos (__fds));
-      else if (__bos (__fds) / sizeof (*__fds) < __nfds)
-	return __poll_chk_warn (__fds, __nfds, __timeout, __bos (__fds));
-    }
-
+  if (__FORTIFY_CALL_CHK && __bos (__fds) != (__SIZE_TYPE__) -1)
+    return __poll_chk (__fds, __nfds, __timeout, __bos (__fds));
   return __poll_alias (__fds, __nfds, __timeout);
 }
-
+__FORTIFY_FUNCTION_END
 
 #ifdef __USE_GNU
 extern int __REDIRECT (__ppoll_alias, (struct pollfd *__fds, nfds_t __nfds,
@@ -54,28 +49,21 @@  extern int __REDIRECT (__ppoll_alias, (struct pollfd *__fds, nfds_t __nfds,
 extern int __ppoll_chk (struct pollfd *__fds, nfds_t __nfds,
 			const struct timespec *__timeout,
 			const __sigset_t *__ss, __SIZE_TYPE__ __fdslen);
-extern int __REDIRECT (__ppoll_chk_warn, (struct pollfd *__fds, nfds_t __nfds,
-					  const struct timespec *__timeout,
-					  const __sigset_t *__ss,
-					  __SIZE_TYPE__ __fdslen),
-		       __ppoll_chk)
-  __warnattr ("ppoll called with fds buffer too small file nfds entries");
 
-__fortify_function int
-ppoll (struct pollfd *__fds, nfds_t __nfds, const struct timespec *__timeout,
-       const __sigset_t *__ss)
+__fortify_potential_overload int
+ppoll (struct pollfd *const __clang_pass_object_size __fds, nfds_t __nfds,
+       const struct timespec *__timeout, const __sigset_t *__ss)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__ppoll_warn, __nfds, __fds,
+					sizeof (*__fds),
+					"ppoll called with fds buffer too "
+					"small file nfds entries")
 {
-  if (__bos (__fds) != (__SIZE_TYPE__) -1)
-    {
-      if (! __builtin_constant_p (__nfds))
-	return __ppoll_chk (__fds, __nfds, __timeout, __ss, __bos (__fds));
-      else if (__bos (__fds) / sizeof (*__fds) < __nfds)
-	return __ppoll_chk_warn (__fds, __nfds, __timeout, __ss,
-				 __bos (__fds));
-    }
-
+  if (__FORTIFY_CALL_CHK && __bos (__fds) != (__SIZE_TYPE__) -1)
+    return __ppoll_chk (__fds, __nfds, __timeout, __ss, __bos (__fds));
   return __ppoll_alias (__fds, __nfds, __timeout, __ss);
 }
+__FORTIFY_FUNCTION_END
 #endif
 
 __END_DECLS
diff --git a/io/fcntl.h b/io/fcntl.h
index a6ccb90a15..ce712a5c4c 100644
--- a/io/fcntl.h
+++ b/io/fcntl.h
@@ -309,7 +309,7 @@  extern int posix_fallocate64 (int __fd, off64_t __offset, off64_t __len);
 
 /* Define some inlines helping to catch common problems.  */
 #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function \
-    && defined __va_arg_pack_len
+    && (defined __va_arg_pack_len || defined __use_clang_fortify)
 # include <bits/fcntl2.h>
 #endif
 
diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
index e9f9d6952b..05e2f0177c 100644
--- a/libio/bits/stdio2.h
+++ b/libio/bits/stdio2.h
@@ -26,12 +26,23 @@  extern int __vsprintf_chk (char *__restrict __s, int __flag, size_t __slen,
 			   const char *__restrict __format,
 			   _G_va_list __ap) __THROW;
 
-#ifdef __va_arg_pack
-__fortify_function int
-__NTH (sprintf (char *__restrict __s, const char *__restrict __fmt, ...))
+#define __mul_may_overflow(size, n) \
+  ((size | n) >= (((size_t)1) << (8 * sizeof (size_t) / 2)))
+
+#ifdef __FORTIFY_ARG_PACK_OK
+/* clang doesn't have __va_arg_pack, so we need to defer to the va_arg versions
+   of these functions.  */
+__fortify_potential_overload int
+__NTH (sprintf (char *__restrict const __clang_pass_object_size __s,
+		const char *__restrict __fmt, ...))
 {
-  return __builtin___sprintf_chk (__s, __USE_FORTIFY_LEVEL - 1,
-				  __bos (__s), __fmt, __va_arg_pack ());
+  __FORTIFY_INIT_ARG_PACK(__fmt);
+  int __result = __FORTIFY_CALL_VA_BUILTIN (sprintf, __s,
+					    __USE_FORTIFY_LEVEL - 1,
+					    __bos (__s), __fmt,
+					    __FORTIFY_ARG_PACK);
+  __FORTIFY_FREE_ARG_PACK();
+  return __result;
 }
 #elif !defined __cplusplus
 # define sprintf(str, ...) \
@@ -39,9 +50,9 @@  __NTH (sprintf (char *__restrict __s, const char *__restrict __fmt, ...))
 			   __VA_ARGS__)
 #endif
 
-__fortify_function int
-__NTH (vsprintf (char *__restrict __s, const char *__restrict __fmt,
-		 _G_va_list __ap))
+__fortify_potential_overload int
+__NTH (vsprintf (char *__restrict const __clang_pass_object_size __s,
+		 const char *__restrict __fmt, _G_va_list __ap))
 {
   return __builtin___vsprintf_chk (__s, __USE_FORTIFY_LEVEL - 1,
 				   __bos (__s), __fmt, __ap);
@@ -56,13 +67,21 @@  extern int __vsnprintf_chk (char *__restrict __s, size_t __n, int __flag,
 			    size_t __slen, const char *__restrict __format,
 			    _G_va_list __ap) __THROW;
 
-# ifdef __va_arg_pack
-__fortify_function int
-__NTH (snprintf (char *__restrict __s, size_t __n,
-		 const char *__restrict __fmt, ...))
+# ifdef __FORTIFY_ARG_PACK_OK
+__fortify_potential_overload int
+__NTH (snprintf (char *__restrict const __clang_pass_object_size __s,
+		 size_t __n, const char *__restrict __fmt, ...))
+     /* GCC's builtin will catch this, so we just need to cover clang here.  */
+     __clang_warning_if (__bos_static_lt (__n, __s),
+			 "call to snprintf may overflow the destination buffer")
 {
-  return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
-				   __bos (__s), __fmt, __va_arg_pack ());
+  __FORTIFY_INIT_ARG_PACK(__fmt);
+  int __result = __FORTIFY_CALL_VA_BUILTIN (snprintf, __s, __n,
+					    __USE_FORTIFY_LEVEL - 1,
+					    __bos (__s), __fmt,
+					    __FORTIFY_ARG_PACK);
+  __FORTIFY_FREE_ARG_PACK();
+  return __result;
 }
 # elif !defined __cplusplus
 #  define snprintf(str, len, ...) \
@@ -70,9 +89,12 @@  __NTH (snprintf (char *__restrict __s, size_t __n,
 			    __VA_ARGS__)
 # endif
 
-__fortify_function int
-__NTH (vsnprintf (char *__restrict __s, size_t __n,
-		  const char *__restrict __fmt, _G_va_list __ap))
+__fortify_potential_overload int
+__NTH (vsnprintf (char *__restrict const __clang_pass_object_size __s,
+		  size_t __n, const char *__restrict __fmt, _G_va_list __ap))
+     __clang_warning_if (__bos_static_lt (__n, __s),
+                         "call to vsnprintf may overflow the destination "
+                         "buffer")
 {
   return __builtin___vsnprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
 				    __bos (__s), __fmt, __ap);
@@ -90,18 +112,27 @@  extern int __vfprintf_chk (FILE *__restrict __stream, int __flag,
 extern int __vprintf_chk (int __flag, const char *__restrict __format,
 			  _G_va_list __ap);
 
-# ifdef __va_arg_pack
-__fortify_function int
-fprintf (FILE *__restrict __stream, const char *__restrict __fmt, ...)
+# ifdef __FORTIFY_ARG_PACK_OK
+__fortify_potential_overload int
+fprintf (FILE *__restrict const __clang_pass_object_size __stream,
+	 const char *__restrict __fmt, ...)
 {
-  return __fprintf_chk (__stream, __USE_FORTIFY_LEVEL - 1, __fmt,
-			__va_arg_pack ());
+  __FORTIFY_INIT_ARG_PACK(__fmt);
+  int __result = __FORTIFY_CALL_VA_CHK (fprintf, __stream,
+					__USE_FORTIFY_LEVEL - 1, __fmt,
+					__FORTIFY_ARG_PACK);
+  __FORTIFY_FREE_ARG_PACK();
+  return __result;
 }
 
-__fortify_function int
-printf (const char *__restrict __fmt, ...)
+__fortify_potential_overload int
+printf (const char *__restrict const __clang_pass_object_size __fmt, ...)
 {
-  return __printf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
+  __FORTIFY_INIT_ARG_PACK(__fmt);
+  int __result = __FORTIFY_CALL_VA_CHK (printf, __USE_FORTIFY_LEVEL - 1, __fmt,
+					__FORTIFY_ARG_PACK);
+  __FORTIFY_FREE_ARG_PACK();
+  return __result;
 }
 # elif !defined __cplusplus
 #  define printf(...) \
@@ -110,18 +141,19 @@  printf (const char *__restrict __fmt, ...)
   __fprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
 # endif
 
-__fortify_function int
-vprintf (const char *__restrict __fmt, _G_va_list __ap)
+__fortify_potential_overload int
+vprintf (const char *__restrict const __clang_pass_object_size __fmt,
+	 _G_va_list __ap)
 {
-#ifdef __USE_EXTERN_INLINES
+# ifdef __USE_EXTERN_INLINES
   return __vfprintf_chk (stdout, __USE_FORTIFY_LEVEL - 1, __fmt, __ap);
-#else
+# else
   return __vprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __ap);
-#endif
+# endif
 }
 
-__fortify_function int
-vfprintf (FILE *__restrict __stream,
+__fortify_potential_overload int
+vfprintf (FILE *__restrict const __clang_pass_object_size __stream,
 	  const char *__restrict __fmt, _G_va_list __ap)
 {
   return __vfprintf_chk (__stream, __USE_FORTIFY_LEVEL - 1, __fmt, __ap);
@@ -134,20 +166,26 @@  extern int __vdprintf_chk (int __fd, int __flag,
 			   const char *__restrict __fmt, _G_va_list __arg)
      __attribute__ ((__format__ (__printf__, 3, 0)));
 
-#  ifdef __va_arg_pack
-__fortify_function int
-dprintf (int __fd, const char *__restrict __fmt, ...)
+#  ifdef __FORTIFY_ARG_PACK_OK
+__fortify_potential_overload int
+dprintf (int __fd, const char *__restrict const __clang_pass_object_size __fmt,
+	 ...)
 {
-  return __dprintf_chk (__fd, __USE_FORTIFY_LEVEL - 1, __fmt,
-			__va_arg_pack ());
+  __FORTIFY_INIT_ARG_PACK(__fmt);
+  int __result = __FORTIFY_CALL_VA_CHK (dprintf, __fd, __USE_FORTIFY_LEVEL - 1,
+					__fmt, __FORTIFY_ARG_PACK);
+  __FORTIFY_FREE_ARG_PACK();
+  return __result;
 }
 #  elif !defined __cplusplus
 #   define dprintf(fd, ...) \
   __dprintf_chk (fd, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
 #  endif
 
-__fortify_function int
-vdprintf (int __fd, const char *__restrict __fmt, _G_va_list __ap)
+__fortify_potential_overload int
+vdprintf (int __fd,
+	  const char *__restrict const __clang_pass_object_size __fmt,
+	  _G_va_list __ap)
 {
   return __vdprintf_chk (__fd, __USE_FORTIFY_LEVEL - 1, __fmt, __ap);
 }
@@ -171,28 +209,47 @@  extern int __obstack_vprintf_chk (struct obstack *__restrict __obstack,
 				  _G_va_list __args)
      __THROW __attribute__ ((__format__ (__printf__, 3, 0)));
 
-#  ifdef __va_arg_pack
-__fortify_function int
-__NTH (asprintf (char **__restrict __ptr, const char *__restrict __fmt, ...))
+#  ifdef __FORTIFY_ARG_PACK_OK
+__fortify_potential_overload int
+__NTH (asprintf (char **__restrict const __clang_pass_object_size __ptr,
+		 const char *__restrict __fmt, ...))
 {
-  return __asprintf_chk (__ptr, __USE_FORTIFY_LEVEL - 1, __fmt,
-			 __va_arg_pack ());
+  __FORTIFY_INIT_ARG_PACK(__fmt);
+  int __result = __FORTIFY_CALL_VA_CHK (asprintf, __ptr,
+					__USE_FORTIFY_LEVEL - 1, __fmt,
+					__FORTIFY_ARG_PACK);
+  __FORTIFY_FREE_ARG_PACK();
+  return __result;
 }
 
-__fortify_function int
-__NTH (__asprintf (char **__restrict __ptr, const char *__restrict __fmt,
-		   ...))
+__fortify_potential_overload int
+__NTH (__asprintf (char **__restrict const __clang_pass_object_size __ptr,
+		   const char *__restrict __fmt, ...))
 {
-  return __asprintf_chk (__ptr, __USE_FORTIFY_LEVEL - 1, __fmt,
-			 __va_arg_pack ());
+  __FORTIFY_INIT_ARG_PACK(__fmt);
+  int __result = __FORTIFY_CALL_VA_CHK (asprintf, __ptr,
+					__USE_FORTIFY_LEVEL - 1, __fmt,
+					__FORTIFY_ARG_PACK);
+  __FORTIFY_FREE_ARG_PACK();
+  return __result;
 }
 
-__fortify_function int
-__NTH (obstack_printf (struct obstack *__restrict __obstack,
+__fortify_potential_overload int
+__NTH (obstack_printf (struct obstack *
+			 __restrict const __clang_pass_object_size __obstack,
 		       const char *__restrict __fmt, ...))
 {
-  return __obstack_printf_chk (__obstack, __USE_FORTIFY_LEVEL - 1, __fmt,
-			       __va_arg_pack ());
+  __FORTIFY_INIT_ARG_PACK(__fmt);
+  int __result =
+#   ifdef __use_clang_fortify
+    __obstack_vprintf_chk
+#   else
+    __obstack_printf_chk
+#   endif
+      (__obstack, __USE_FORTIFY_LEVEL - 1, __fmt,
+			     __FORTIFY_ARG_PACK);
+  __FORTIFY_FREE_ARG_PACK();
+  return __result;
 }
 #  elif !defined __cplusplus
 #   define asprintf(ptr, ...) \
@@ -203,15 +260,16 @@  __NTH (obstack_printf (struct obstack *__restrict __obstack,
   __obstack_printf_chk (obstack, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
 #  endif
 
-__fortify_function int
-__NTH (vasprintf (char **__restrict __ptr, const char *__restrict __fmt,
-		  _G_va_list __ap))
+__fortify_potential_overload int
+__NTH (vasprintf (char **__restrict const __clang_pass_object_size __ptr,
+		  const char *__restrict __fmt, _G_va_list __ap))
 {
   return __vasprintf_chk (__ptr, __USE_FORTIFY_LEVEL - 1, __fmt, __ap);
 }
 
-__fortify_function int
-__NTH (obstack_vprintf (struct obstack *__restrict __obstack,
+__fortify_potential_overload int
+__NTH (obstack_vprintf (struct obstack *
+			  __restrict const __clang_pass_object_size __obstack,
 			const char *__restrict __fmt, _G_va_list __ap))
 {
   return __obstack_vprintf_chk (__obstack, __USE_FORTIFY_LEVEL - 1, __fmt,
@@ -224,17 +282,20 @@  __NTH (obstack_vprintf (struct obstack *__restrict __obstack,
 
 #if __GLIBC_USE (DEPRECATED_GETS)
 extern char *__gets_chk (char *__str, size_t) __wur;
-extern char *__REDIRECT (__gets_warn, (char *__str), gets)
-     __wur __warnattr ("please use fgets or getline instead, gets can't "
-		       "specify buffer size");
-
-__fortify_function __wur char *
-gets (char *__str)
+extern char *__REDIRECT_NTH (__gets_alias, (char *__buf), gets) __wur;
+
+__fortify_potential_overload __wur char *
+gets (char *const __clang_pass_object_size __str)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_IF (__gets_warn, __bos (__str) == (size_t) -1,
+			   "please use fgets or getline instead, gets can't "
+			   "specify buffer size")
 {
   if (__bos (__str) != (size_t) -1)
     return __gets_chk (__str, __bos (__str));
-  return __gets_warn (__str);
+  return __gets_alias (__str);
 }
+__FORTIFY_FUNCTION_END
 #endif
 
 extern char *__fgets_chk (char *__restrict __s, size_t __size, int __n,
@@ -242,25 +303,20 @@  extern char *__fgets_chk (char *__restrict __s, size_t __size, int __n,
 extern char *__REDIRECT (__fgets_alias,
 			 (char *__restrict __s, int __n,
 			  FILE *__restrict __stream), fgets) __wur;
-extern char *__REDIRECT (__fgets_chk_warn,
-			 (char *__restrict __s, size_t __size, int __n,
-			  FILE *__restrict __stream), __fgets_chk)
-     __wur __warnattr ("fgets called with bigger size than length "
-		       "of destination buffer");
-
-__fortify_function __wur char *
-fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
+
+__fortify_potential_overload __wur char *
+fgets (char *__restrict const __clang_pass_object_size __s, int __n,
+       FILE *__restrict __stream)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_IF (__fgets_warn, __bos_static_lt (__n, __s) && __n > 0,
+			   "fgets called with bigger size than length of "
+			   "destination buffer")
 {
   if (__bos (__s) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__n) || __n <= 0)
-	return __fgets_chk (__s, __bos (__s), __n, __stream);
-
-      if ((size_t) __n > __bos (__s))
-	return __fgets_chk_warn (__s, __bos (__s), __n, __stream);
-    }
+    return __fgets_chk (__s, __bos (__s), __n, __stream);
   return __fgets_alias (__s, __n, __stream);
 }
+__FORTIFY_FUNCTION_END
 
 extern size_t __fread_chk (void *__restrict __ptr, size_t __ptrlen,
 			   size_t __size, size_t __n,
@@ -269,30 +325,21 @@  extern size_t __REDIRECT (__fread_alias,
 			  (void *__restrict __ptr, size_t __size,
 			   size_t __n, FILE *__restrict __stream),
 			  fread) __wur;
-extern size_t __REDIRECT (__fread_chk_warn,
-			  (void *__restrict __ptr, size_t __ptrlen,
-			   size_t __size, size_t __n,
-			   FILE *__restrict __stream),
-			  __fread_chk)
-     __wur __warnattr ("fread called with bigger size * nmemb than length "
-		       "of destination buffer");
 
-__fortify_function __wur size_t
-fread (void *__restrict __ptr, size_t __size, size_t __n,
-       FILE *__restrict __stream)
+__fortify_potential_overload __wur size_t
+fread (void *__restrict const __clang_pass_object_size0 __ptr, size_t __size,
+       size_t __n, FILE *__restrict __stream)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_IF (__fread_warn, __bos0_static_lt (__size * __n, __ptr)
+			    && !__mul_may_overflow (__size, __n),
+			   "fread called with bigger size * nmemb than length "
+			   "of destination buffer")
 {
   if (__bos0 (__ptr) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__size)
-	  || !__builtin_constant_p (__n)
-	  || (__size | __n) >= (((size_t) 1) << (8 * sizeof (size_t) / 2)))
-	return __fread_chk (__ptr, __bos0 (__ptr), __size, __n, __stream);
-
-      if (__size * __n > __bos0 (__ptr))
-	return __fread_chk_warn (__ptr, __bos0 (__ptr), __size, __n, __stream);
-    }
+    return __fread_chk (__ptr, __bos0 (__ptr), __size, __n, __stream);
   return __fread_alias (__ptr, __size, __n, __stream);
 }
+__FORTIFY_FUNCTION_END
 
 #ifdef __USE_GNU
 extern char *__fgets_unlocked_chk (char *__restrict __s, size_t __size,
@@ -300,25 +347,21 @@  extern char *__fgets_unlocked_chk (char *__restrict __s, size_t __size,
 extern char *__REDIRECT (__fgets_unlocked_alias,
 			 (char *__restrict __s, int __n,
 			  FILE *__restrict __stream), fgets_unlocked) __wur;
-extern char *__REDIRECT (__fgets_unlocked_chk_warn,
-			 (char *__restrict __s, size_t __size, int __n,
-			  FILE *__restrict __stream), __fgets_unlocked_chk)
-     __wur __warnattr ("fgets_unlocked called with bigger size than length "
-		       "of destination buffer");
-
-__fortify_function __wur char *
-fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream)
+
+__fortify_potential_overload __wur char *
+fgets_unlocked (char *__restrict const __clang_pass_object_size __s, int __n,
+		FILE *__restrict __stream)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_IF (__fgets_unlocked_warn,
+			   __bos_static_lt (__n, __s) && __n > 0,
+			   "fgets_unlocked called with bigger size than length "
+			   "of destination buffer")
 {
   if (__bos (__s) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__n) || __n <= 0)
-	return __fgets_unlocked_chk (__s, __bos (__s), __n, __stream);
-
-      if ((size_t) __n > __bos (__s))
-	return __fgets_unlocked_chk_warn (__s, __bos (__s), __n, __stream);
-    }
+    return __fgets_unlocked_chk (__s, __bos (__s), __n, __stream);
   return __fgets_unlocked_alias (__s, __n, __stream);
 }
+__FORTIFY_FUNCTION_END
 #endif
 
 #ifdef __USE_MISC
@@ -330,30 +373,19 @@  extern size_t __REDIRECT (__fread_unlocked_alias,
 			  (void *__restrict __ptr, size_t __size,
 			   size_t __n, FILE *__restrict __stream),
 			  fread_unlocked) __wur;
-extern size_t __REDIRECT (__fread_unlocked_chk_warn,
-			  (void *__restrict __ptr, size_t __ptrlen,
-			   size_t __size, size_t __n,
-			   FILE *__restrict __stream),
-			  __fread_unlocked_chk)
-     __wur __warnattr ("fread_unlocked called with bigger size * nmemb than "
-		       "length of destination buffer");
 
-__fortify_function __wur size_t
-fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
-		FILE *__restrict __stream)
+__fortify_potential_overload __wur size_t
+fread_unlocked (void *__restrict const __clang_pass_object_size0 __ptr,
+		size_t __size, size_t __n, FILE *__restrict __stream)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_IF (__fread_unlocked_warn,
+			   __bos0_static_lt (__size * __n, __ptr)
+			    && !__mul_may_overflow(__size, __n),
+			   "fread_unlocked called with bigger size * n than "
+			   "length of destination buffer")
 {
   if (__bos0 (__ptr) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__size)
-	  || !__builtin_constant_p (__n)
-	  || (__size | __n) >= (((size_t) 1) << (8 * sizeof (size_t) / 2)))
-	return __fread_unlocked_chk (__ptr, __bos0 (__ptr), __size, __n,
-				     __stream);
-
-      if (__size * __n > __bos0 (__ptr))
-	return __fread_unlocked_chk_warn (__ptr, __bos0 (__ptr), __size, __n,
-					  __stream);
-    }
+    return __fread_unlocked_chk (__ptr, __bos0 (__ptr), __size, __n, __stream);
 
 # ifdef __USE_EXTERN_INLINES
   if (__builtin_constant_p (__size)
@@ -378,4 +410,6 @@  fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
 # endif
   return __fread_unlocked_alias (__ptr, __size, __n, __stream);
 }
+__FORTIFY_FUNCTION_END
 #endif
+#undef __mul_may_overflow
diff --git a/misc/bits/syslog.h b/misc/bits/syslog.h
index 0b6c913516..8618bf1a56 100644
--- a/misc/bits/syslog.h
+++ b/misc/bits/syslog.h
@@ -20,11 +20,34 @@ 
 # error "Never include <bits/syslog.h> directly; use <sys/syslog.h> instead."
 #endif
 
+#ifdef __USE_MISC
+extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt,
+			   __gnuc_va_list __ap)
+     __attribute__ ((__format__ (__printf__, 3, 0)));
+
+__fortify_potential_overload void
+vsyslog (int __pri, const char *const __clang_pass_object_size __fmt,
+	 __gnuc_va_list __ap)
+{
+  __vsyslog_chk (__pri,  __USE_FORTIFY_LEVEL - 1, __fmt, __ap);
+}
+#endif
 
 extern void __syslog_chk (int __pri, int __flag, const char *__fmt, ...)
      __attribute__ ((__format__ (__printf__, 3, 4)));
 
-#ifdef __va_arg_pack
+#if defined __use_clang_fortify && __USE_MISC
+/* clang doesn't support __va_arg_pack, so this is only possible if we have
+   vsyslog.  */
+__fortify_overload void
+syslog (int __pri, const char *const __clang_pass_object_size __fmt, ...)
+{
+  __gnuc_va_list __ap;
+  va_start (__ap, __fmt);
+  __vsyslog_chk (__pri, __USE_FORTIFY_LEVEL - 1, __fmt, __ap);
+  va_end (__ap);
+}
+#elif defined __va_arg_pack
 __fortify_function void
 syslog (int __pri, const char *__fmt, ...)
 {
@@ -34,16 +57,3 @@  syslog (int __pri, const char *__fmt, ...)
 # define syslog(pri, ...) \
   __syslog_chk (pri, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
 #endif
-
-
-#ifdef __USE_MISC
-extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt,
-			   __gnuc_va_list __ap)
-     __attribute__ ((__format__ (__printf__, 3, 0)));
-
-__fortify_function void
-vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap)
-{
-  __vsyslog_chk (__pri,  __USE_FORTIFY_LEVEL - 1, __fmt, __ap);
-}
-#endif
diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index cfd39d5302..eb45839110 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -113,11 +113,150 @@ 
 # define __END_DECLS
 #endif
 
+#if defined __clang__ && defined __has_extension
+# define __clang_has_extension(x) __has_extension (x)
+#else
+# define __clang_has_extension(x) 0
+#endif
 
 /* Fortify support.  */
-#define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1)
+#define __fortify_function __extern_always_inline __attribute_artificial__
+#if defined __clang__ && __USE_FORTIFY_LEVEL > 0 \
+    && !defined _CLANG_FORTIFY_DISABLE \
+    && __clang_has_extension(overloadable_unmarked)
+# define __use_clang_fortify 1
+/* Clang-style FORTIFY creates a different symbol for each FORTIFY'ed function,
+   whereas GCC-style doesn't.  Thus, GCC can assume that the FORTIFY'ed
+   function is always available externally, but clang can't.  */
+# define __attribute_overloadable__ __attribute__ ((__overloadable__))
+# define __attribute_transparent_overload__ \
+  __attribute__ ((__overloadable__("transparent")))
+# define __fortify_overload static __always_inline __attribute_overloadable__
+/* For FORTIFY functions that exist only as decls.  */
+# define __fortify_error_function static __attribute_overloadable__
+# define __clang_pass_object_size_n(n) __attribute__ ((pass_object_size (n)))
+# define __clang_warning(what) __attribute__ ((deprecated(what)))
+# define __clang_prefer_this_overload __attribute__ ((enable_if (1, "")))
+# define __clang_warning_if(c, m) \
+  __attribute__ ((__diagnose_if__ ((c), (m), "warning")))
+# define __clang_error(what) __attribute__ ((unavailable(what)))
+# define __clang_error_if(c, m) \
+  __attribute__ ((__diagnose_if__ ((c), (m), "error")))
+# define __fortify_potential_overload __fortify_overload
+#else
+# define __fortify_potential_overload __fortify_function
+/* Some functions/decls can be shared between clang and non-clang FORTIFY.
+   Turning these into nops makes that possible.  */
+# define __clang_pass_object_size_n(n)
+# define __attribute_overloadable__
+# define __bos_n(ptr, n) __builtin_object_size (ptr, n)
+# define __clang_warning_if(c, m)
+# define __clang_error_if(c, m)
+#endif
+
+#define __bos_level (__USE_FORTIFY_LEVEL > 1)
+#define __bos(ptr) __builtin_object_size (ptr, __bos_level)
 #define __bos0(ptr) __builtin_object_size (ptr, 0)
 
+#define __clang_pass_object_size0 __clang_pass_object_size_n (0)
+#define __clang_pass_object_size __clang_pass_object_size_n (__bos_level)
+
+/* Some of these macros are awkwardly written, and more repetitive than they'd
+   ideally need to be.  This is because both clang and gcc will emit 'note's
+   about where these warnings originate from. For every macro that's expanded,
+   the user sees a note that ultimately doesn't matter to them...  */
+#ifdef __use_clang_fortify
+# define __FORTIFY_PRECONDITIONS
+# define __FORTIFY_FUNCTION_END
+# define __FORTIFY_WARNING_IF(_, c, msg) __clang_warning_if(c, msg)
+/* __builtin_constant_p isn't needed: this is only used in constructs that
+   must be fully evaluated at compile-time.  */
+# define __bos_static_lt_impl(bos_val, n, s) \
+  ((bos_val) != -1ULL && (n) > (bos_val) / (s))
+# define __FORTIFY_CALL_CHK 1
+
+# define __FORTIFY_BOSN_ARGS(bos_fn, n, buf, div, complaint) \
+  (__bos_static_lt_impl (bos_fn (buf), n, div)), (complaint), "warning"
+
+#define __FORTIFY_WARNING_ONLY_IF_BOS0_LT2(fn_name, n, buf, div, complaint) \
+  __attribute__ ((__diagnose_if__ \
+	(__FORTIFY_BOSN_ARGS (__bos0, n, buf, div, complaint))))
+#define __FORTIFY_WARNING_ONLY_IF_BOS0_LT(fn_name, n, buf, complaint) \
+  __attribute__ ((__diagnose_if__ \
+	(__FORTIFY_BOSN_ARGS (__bos0, n, buf, 1, complaint))))
+#define __FORTIFY_WARNING_ONLY_IF_BOS_LT2(fn_name, n, buf, div, complaint) \
+  __attribute__ ((__diagnose_if__ \
+	(__FORTIFY_BOSN_ARGS (__bos, n, buf, div, complaint))))
+#define __FORTIFY_WARNING_ONLY_IF_BOS_LT(fn_name, n, buf, complaint) \
+  __attribute__ ((__diagnose_if__ \
+	(__FORTIFY_BOSN_ARGS (__bos, n, buf, 1, complaint))))
+#else
+# define __FORTIFY_PRECONDITIONS {
+# define __FORTIFY_FUNCTION_END }
+/* __chk_fail was chosen arbitrarily. The function should never be called
+   anyway; it just exists to be reachable after optimizations.  */
+# define __FORTIFY_DECLARE_WARNING_FUNCTION(name, msg) \
+  __attribute ((__warning__(msg))) \
+  extern void __REDIRECT_NTH (name, (void), __chk_fail)
+
+# define __FORTIFY_WARNING_IF_BEGIN(fn_name, cond, complaint, if_cond_true) \
+  { \
+    if (cond) { \
+      if_cond_true; \
+      __FORTIFY_DECLARE_WARNING_FUNCTION (fn_name, complaint); \
+      volatile char __t = 0; \
+      if (__glibc_unlikely (__t)) \
+      {
+
+# define __FORTIFY_WARNING_IF_END \
+      } \
+    } \
+  }
+
+# define __FORTIFY_WARNING_IF(err_fn, cond, complaint) \
+  __FORTIFY_WARNING_IF_BEGIN (err_fn, cond, complaint, (void)0) \
+    err_fn (); \
+  __FORTIFY_WARNING_IF_END
+
+# define __bos_static_lt_impl(bos_val, n, s) \
+  (__builtin_constant_p (n) && (bos_val) != -1ULL && (n) > (bos_val) / (s))
+
+#define __FORTIFY_BOS_WARNING_BEGIN(fn_name, bos_fn, n, buf, div, complaint) \
+  char __need_dynamic_check = !__builtin_constant_p (n); \
+  __FORTIFY_WARNING_IF_BEGIN (fn_name, \
+			      __bos_static_lt_impl (bos_fn (buf), n, div), \
+			      complaint, (__need_dynamic_check = 1))
+
+/* Duplicate this so that the fn_name call happens with the smallest possible
+   macro "call stack". This minimizes diagnostics about expanding macros.  */
+#define __FORTIFY_WARNING_ONLY_IF_BOS0_LT2(err_fn, n, buf, div, complaint) \
+  __FORTIFY_BOS_WARNING_BEGIN (err_fn, __bos0, n, buf, div, complaint) \
+    err_fn (); \
+  __FORTIFY_WARNING_IF_END
+
+#define __FORTIFY_WARNING_ONLY_IF_BOS0_LT(err_fn, n, buf, complaint) \
+  __FORTIFY_BOS_WARNING_BEGIN (err_fn, __bos0, n, buf, 1, complaint) \
+    err_fn (); \
+  __FORTIFY_WARNING_IF_END
+
+#define __FORTIFY_WARNING_ONLY_IF_BOS_LT2(err_fn, n, buf, div, complaint) \
+  __FORTIFY_BOS_WARNING_BEGIN (err_fn, __bos, n, buf, div, complaint) \
+    err_fn (); \
+  __FORTIFY_WARNING_IF_END
+
+#define __FORTIFY_WARNING_ONLY_IF_BOS_LT(err_fn, n, buf, complaint) \
+  __FORTIFY_BOS_WARNING_BEGIN (err_fn, __bos, n, buf, 1, complaint) \
+    err_fn (); \
+  __FORTIFY_WARNING_IF_END
+
+# define __FORTIFY_CALL_CHK (__need_dynamic_check)
+#endif
+
+#define __bos_static_lt2(n, e, s) __bos_static_lt_impl (__bos (e), n, s)
+#define __bos_static_lt(n, e) __bos_static_lt2 (n, e, 1)
+#define __bos0_static_lt2(n, e, s) __bos_static_lt_impl (__bos0 (e), n, s)
+#define __bos0_static_lt(n, e) __bos0_static_lt2 (n, e, 1)
+
 #if __GNUC_PREREQ (4,3)
 # define __warndecl(name, msg) \
   extern void name (void) __attribute__((__warning__ (msg)))
@@ -358,6 +497,29 @@ 
 # define __va_arg_pack_len() __builtin_va_arg_pack_len ()
 #endif
 
+#if defined(__use_clang_fortify)
+/* clang doesn't support __va_arg_pack, so we need to call the v* version of
+   FORTIFY'ed functions.  */
+#define __FORTIFY_ARG_PACK __fortify_ap
+#define __FORTIFY_INIT_ARG_PACK(va_arg) \
+  __gnuc_va_list __FORTIFY_ARG_PACK; \
+  va_start (__FORTIFY_ARG_PACK, va_arg)
+#define __FORTIFY_CALL_VA_ALIAS(fn, ...) __v##fn##_alias (__VA_ARGS__)
+#define __FORTIFY_CALL_VA_CHK(fn, ...) __v##fn##_chk (__VA_ARGS__)
+#define __FORTIFY_CALL_VA_BUILTIN(fn, ...) \
+  __builtin___v##fn##_chk (__VA_ARGS__)
+#define __FORTIFY_FREE_ARG_PACK() va_end (__FORTIFY_ARG_PACK)
+#define __FORTIFY_ARG_PACK_OK 1
+#elif defined(__va_arg_pack)
+#define __FORTIFY_ARG_PACK __va_arg_pack ()
+#define __FORTIFY_INIT_ARG_PACK(va_arg)
+#define __FORTIFY_CALL_VA_ALIAS(fn, ...) __##fn##_alias (__VA_ARGS__)
+#define __FORTIFY_CALL_VA_CHK(fn, ...) __##fn##_chk (__VA_ARGS__)
+#define __FORTIFY_CALL_VA_BUILTIN(fn, ...) __builtin___##fn##_chk (__VA_ARGS__)
+#define __FORTIFY_FREE_ARG_PACK()
+#define __FORTIFY_ARG_PACK_OK 1
+#endif
+
 /* It is possible to compile containing GCC extensions even if GCC is
    run in pedantic mode if the uses are carefully marked using the
    `__extension__' keyword.  But this is not generally available before
diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h
index 4e4153c94f..3bd4c8de75 100644
--- a/posix/bits/unistd.h
+++ b/posix/bits/unistd.h
@@ -24,25 +24,19 @@  extern ssize_t __read_chk (int __fd, void *__buf, size_t __nbytes,
 			   size_t __buflen) __wur;
 extern ssize_t __REDIRECT (__read_alias, (int __fd, void *__buf,
 					  size_t __nbytes), read) __wur;
-extern ssize_t __REDIRECT (__read_chk_warn,
-			   (int __fd, void *__buf, size_t __nbytes,
-			    size_t __buflen), __read_chk)
-     __wur __warnattr ("read called with bigger length than size of "
-		       "the destination buffer");
 
-__fortify_function __wur ssize_t
-read (int __fd, void *__buf, size_t __nbytes)
+__fortify_potential_overload __wur ssize_t
+read (int __fd, void *const __clang_pass_object_size0 __buf, size_t __nbytes)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS0_LT (__read_warn, __nbytes, __buf,
+					"read called with bigger length than "
+					"size of the destination buffer")
 {
-  if (__bos0 (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__nbytes))
-	return __read_chk (__fd, __buf, __nbytes, __bos0 (__buf));
-
-      if (__nbytes > __bos0 (__buf))
-	return __read_chk_warn (__fd, __buf, __nbytes, __bos0 (__buf));
-    }
+  if (__FORTIFY_CALL_CHK && __bos0 (__buf) != (size_t) -1)
+    return __read_chk (__fd, __buf, __nbytes, __bos0 (__buf));
   return __read_alias (__fd, __buf, __nbytes);
 }
+__FORTIFY_FUNCTION_END
 
 #ifdef __USE_UNIX98
 extern ssize_t __pread_chk (int __fd, void *__buf, size_t __nbytes,
@@ -55,67 +49,49 @@  extern ssize_t __REDIRECT (__pread_alias,
 extern ssize_t __REDIRECT (__pread64_alias,
 			   (int __fd, void *__buf, size_t __nbytes,
 			    __off64_t __offset), pread64) __wur;
-extern ssize_t __REDIRECT (__pread_chk_warn,
-			   (int __fd, void *__buf, size_t __nbytes,
-			    __off_t __offset, size_t __bufsize), __pread_chk)
-     __wur __warnattr ("pread called with bigger length than size of "
-		       "the destination buffer");
-extern ssize_t __REDIRECT (__pread64_chk_warn,
-			   (int __fd, void *__buf, size_t __nbytes,
-			    __off64_t __offset, size_t __bufsize),
-			    __pread64_chk)
-     __wur __warnattr ("pread64 called with bigger length than size of "
-		       "the destination buffer");
 
 # ifndef __USE_FILE_OFFSET64
-__fortify_function __wur ssize_t
-pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset)
-{
-  if (__bos0 (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__nbytes))
-	return __pread_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf));
-
-      if ( __nbytes > __bos0 (__buf))
-	return __pread_chk_warn (__fd, __buf, __nbytes, __offset,
-				 __bos0 (__buf));
-    }
-  return __pread_alias (__fd, __buf, __nbytes, __offset);
-}
+#  define __fo_pread_chk __pread_chk
+#  define __fo_pread_alias __pread_alias
+#  define __fo_off_t __off_t
 # else
-__fortify_function __wur ssize_t
-pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
-{
-  if (__bos0 (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__nbytes))
-	return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf));
-
-      if ( __nbytes > __bos0 (__buf))
-	return __pread64_chk_warn (__fd, __buf, __nbytes, __offset,
-				   __bos0 (__buf));
-    }
-
-  return __pread64_alias (__fd, __buf, __nbytes, __offset);
-}
+#  define __fo_pread_chk __pread64_chk
+#  define __fo_pread_alias __pread64_alias
+#  define __fo_off_t __off64_t
 # endif
 
-# ifdef __USE_LARGEFILE64
-__fortify_function __wur ssize_t
-pread64 (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
+__fortify_potential_overload __wur ssize_t
+pread (int __fd, void *const __clang_pass_object_size0 __buf, size_t __nbytes,
+       __fo_off_t __offset)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS0_LT (__pread_chk_warn, __nbytes, __buf,
+					"pread called with bigger length than "
+					"size of the destination buffer")
 {
-  if (__bos0 (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__nbytes))
-	return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf));
+  if (__FORTIFY_CALL_CHK && __bos0 (__buf) != (size_t) -1)
+    return __fo_pread_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf));
+  return __fo_pread_alias (__fd, __buf, __nbytes, __offset);
+}
+__FORTIFY_FUNCTION_END
 
-      if ( __nbytes > __bos0 (__buf))
-	return __pread64_chk_warn (__fd, __buf, __nbytes, __offset,
-				   __bos0 (__buf));
-    }
+#undef __fo_pread_chk
+#undef __fo_pread_alias
+#undef __fo_off_t
 
+# ifdef __USE_LARGEFILE64
+__fortify_potential_overload __wur ssize_t
+pread64 (int __fd, void *const __clang_pass_object_size0 __buf,
+	  size_t __nbytes, __off64_t __offset)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS0_LT (__pread64_warn, __nbytes, __buf,
+					"pread64 called with bigger length "
+					"than size of the destination buffer")
+{
+  if (__FORTIFY_CALL_CHK && __bos0 (__buf) != (size_t) -1)
+    return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf));
   return __pread64_alias (__fd, __buf, __nbytes, __offset);
 }
+__FORTIFY_FUNCTION_END
 # endif
 #endif
 
@@ -128,27 +104,21 @@  extern ssize_t __REDIRECT_NTH (__readlink_alias,
 			       (const char *__restrict __path,
 				char *__restrict __buf, size_t __len), readlink)
      __nonnull ((1, 2)) __wur;
-extern ssize_t __REDIRECT_NTH (__readlink_chk_warn,
-			       (const char *__restrict __path,
-				char *__restrict __buf, size_t __len,
-				size_t __buflen), __readlink_chk)
-     __nonnull ((1, 2)) __wur __warnattr ("readlink called with bigger length "
-					  "than size of destination buffer");
 
-__fortify_function __nonnull ((1, 2)) __wur ssize_t
-__NTH (readlink (const char *__restrict __path, char *__restrict __buf,
+__fortify_potential_overload __nonnull ((1, 2)) __wur ssize_t
+__NTH (readlink (const char *__restrict __path,
+		 char *__restrict const __clang_pass_object_size __buf,
 		 size_t __len))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__readlink_warn, __len, __buf,
+				       "readlink called with bigger length "
+				       "than size of destination buffer")
 {
-  if (__bos (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__len))
-	return __readlink_chk (__path, __buf, __len, __bos (__buf));
-
-      if ( __len > __bos (__buf))
-	return __readlink_chk_warn (__path, __buf, __len, __bos (__buf));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__buf) != (size_t) -1)
+    return __readlink_chk (__path, __buf, __len, __bos (__buf));
   return __readlink_alias (__path, __buf, __len);
 }
+__FORTIFY_FUNCTION_END
 #endif
 
 #ifdef __USE_ATFILE
@@ -161,119 +131,104 @@  extern ssize_t __REDIRECT_NTH (__readlinkat_alias,
 				char *__restrict __buf, size_t __len),
 			       readlinkat)
      __nonnull ((2, 3)) __wur;
-extern ssize_t __REDIRECT_NTH (__readlinkat_chk_warn,
-			       (int __fd, const char *__restrict __path,
-				char *__restrict __buf, size_t __len,
-				size_t __buflen), __readlinkat_chk)
-     __nonnull ((2, 3)) __wur __warnattr ("readlinkat called with bigger "
-					  "length than size of destination "
-					  "buffer");
-
-__fortify_function __nonnull ((2, 3)) __wur ssize_t
-__NTH (readlinkat (int __fd, const char *__restrict __path,
-		   char *__restrict __buf, size_t __len))
+
+__fortify_potential_overload __nonnull ((2, 3)) __wur ssize_t
+__NTH (readlinkat (int __fd,
+		   const char *__restrict __path,
+		   char *__restrict const __clang_pass_object_size __buf,
+		   size_t __len))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__readlinkat_warn, __len, __buf,
+				       "readlinkat called with bigger length "
+				       "than size of destination buffer")
 {
-  if (__bos (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__len))
-	return __readlinkat_chk (__fd, __path, __buf, __len, __bos (__buf));
-
-      if (__len > __bos (__buf))
-	return __readlinkat_chk_warn (__fd, __path, __buf, __len,
-				      __bos (__buf));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__buf) != (size_t) -1)
+    return __readlinkat_chk (__fd, __path, __buf, __len, __bos (__buf));
   return __readlinkat_alias (__fd, __path, __buf, __len);
 }
+__FORTIFY_FUNCTION_END
 #endif
 
 extern char *__getcwd_chk (char *__buf, size_t __size, size_t __buflen)
      __THROW __wur;
 extern char *__REDIRECT_NTH (__getcwd_alias,
 			     (char *__buf, size_t __size), getcwd) __wur;
-extern char *__REDIRECT_NTH (__getcwd_chk_warn,
-			     (char *__buf, size_t __size, size_t __buflen),
-			     __getcwd_chk)
-     __wur __warnattr ("getcwd caller with bigger length than size of "
-		       "destination buffer");
-
-__fortify_function __wur char *
-__NTH (getcwd (char *__buf, size_t __size))
-{
-  if (__bos (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__size))
-	return __getcwd_chk (__buf, __size, __bos (__buf));
 
-      if (__size > __bos (__buf))
-	return __getcwd_chk_warn (__buf, __size, __bos (__buf));
-    }
+__fortify_potential_overload __wur char *
+__NTH (getcwd (char *const __clang_pass_object_size __buf, size_t __size))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__getcwd_warn, __size, __buf,
+				       "getcwd called with bigger length than "
+				       "size of destination buffer")
+{
+  if (__FORTIFY_CALL_CHK && __bos (__buf) != (size_t) -1)
+    return __getcwd_chk (__buf, __size, __bos (__buf));
   return __getcwd_alias (__buf, __size);
 }
+__FORTIFY_FUNCTION_END
 
 #if defined __USE_MISC || defined __USE_XOPEN_EXTENDED
+# define __warn_getwd_use_something_else \
+  "please use getcwd instead, as getwd doesn't specify buffer size"
+
 extern char *__getwd_chk (char *__buf, size_t buflen)
      __THROW __nonnull ((1)) __wur;
 extern char *__REDIRECT_NTH (__getwd_warn, (char *__buf), getwd)
-     __nonnull ((1)) __wur __warnattr ("please use getcwd instead, as getwd "
-				       "doesn't specify buffer size");
+     __nonnull ((1)) __wur __warnattr (__warn_getwd_use_something_else);
 
-__fortify_function __nonnull ((1)) __attribute_deprecated__ __wur char *
-__NTH (getwd (char *__buf))
+extern char *__REDIRECT (__getwd_alias, (char *__str), getwd) __wur;
+
+__fortify_potential_overload __nonnull ((1)) __attribute_deprecated__ __wur
+char *
+__NTH (getwd (char *const __clang_pass_object_size __buf))
+     __clang_warning_if (__bos (__buf) == (size_t) -1,
+			 __warn_getwd_use_something_else)
 {
   if (__bos (__buf) != (size_t) -1)
     return __getwd_chk (__buf, __bos (__buf));
   return __getwd_warn (__buf);
 }
+# undef __warn_getwd_use_something_else
 #endif
 
 extern size_t __confstr_chk (int __name, char *__buf, size_t __len,
 			     size_t __buflen) __THROW;
 extern size_t __REDIRECT_NTH (__confstr_alias, (int __name, char *__buf,
 						size_t __len), confstr);
-extern size_t __REDIRECT_NTH (__confstr_chk_warn,
-			      (int __name, char *__buf, size_t __len,
-			       size_t __buflen), __confstr_chk)
-     __warnattr ("confstr called with bigger length than size of destination "
-		 "buffer");
-
-__fortify_function size_t
-__NTH (confstr (int __name, char *__buf, size_t __len))
-{
-  if (__bos (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__len))
-	return __confstr_chk (__name, __buf, __len, __bos (__buf));
 
-      if (__bos (__buf) < __len)
-	return __confstr_chk_warn (__name, __buf, __len, __bos (__buf));
-    }
+__fortify_potential_overload size_t
+__NTH (confstr (int __name, char *const __clang_pass_object_size __buf,
+		size_t __len))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__confstr_warn, __len, __buf,
+				       "confstr called with bigger length than "
+				       "size of destination buffer")
+{
+  if (__FORTIFY_CALL_CHK && __bos (__buf) != (size_t) -1)
+    return __confstr_chk (__name, __buf, __len, __bos (__buf));
   return __confstr_alias (__name, __buf, __len);
 }
-
+__FORTIFY_FUNCTION_END
 
 extern int __getgroups_chk (int __size, __gid_t __list[], size_t __listlen)
      __THROW __wur;
 extern int __REDIRECT_NTH (__getgroups_alias, (int __size, __gid_t __list[]),
 			   getgroups) __wur;
-extern int __REDIRECT_NTH (__getgroups_chk_warn,
-			   (int __size, __gid_t __list[], size_t __listlen),
-			   __getgroups_chk)
-     __wur __warnattr ("getgroups called with bigger group count than what "
-		       "can fit into destination buffer");
-
-__fortify_function int
-__NTH (getgroups (int __size, __gid_t __list[]))
+
+__fortify_potential_overload int
+__NTH (getgroups (int __size, __gid_t *const __clang_pass_object_size __list))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__getgroups_warn,
+				       __size * sizeof (__gid_t), __list,
+				       "getgroups called with bigger group "
+				       "count than what can fit into "
+				       "destination buffer")
 {
-  if (__bos (__list) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__size) || __size < 0)
-	return __getgroups_chk (__size, __list, __bos (__list));
-
-      if (__size * sizeof (__gid_t) > __bos (__list))
-	return __getgroups_chk_warn (__size, __list, __bos (__list));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__list) != (size_t) -1)
+    return __getgroups_chk (__size, __list, __bos (__list));
   return __getgroups_alias (__size, __list);
 }
+__FORTIFY_FUNCTION_END
 
 
 extern int __ttyname_r_chk (int __fd, char *__buf, size_t __buflen,
@@ -287,19 +242,19 @@  extern int __REDIRECT_NTH (__ttyname_r_chk_warn,
      __nonnull ((2)) __warnattr ("ttyname_r called with bigger buflen than "
 				 "size of destination buffer");
 
-__fortify_function int
-__NTH (ttyname_r (int __fd, char *__buf, size_t __buflen))
+__fortify_potential_overload int
+__NTH (ttyname_r (int __fd, char *const __clang_pass_object_size __buf,
+		  size_t __buflen))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__ttyname_r_warn, __buflen, __buf,
+				       "ttyname_r called with bigger buflen "
+				       "than size of destination buffer")
 {
-  if (__bos (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__buflen))
-	return __ttyname_r_chk (__fd, __buf, __buflen, __bos (__buf));
-
-      if (__buflen > __bos (__buf))
-	return __ttyname_r_chk_warn (__fd, __buf, __buflen, __bos (__buf));
-    }
-  return __ttyname_r_alias (__fd, __buf, __buflen);
-}
+  if (__FORTIFY_CALL_CHK && __bos (__buf) != (size_t) -1)
+    return __ttyname_r_chk (__fd, __buf, __buflen, __bos (__buf));
+   return __ttyname_r_alias (__fd, __buf, __buflen);
+ }
+__FORTIFY_FUNCTION_END
 
 
 #ifdef __USE_POSIX199506
@@ -307,25 +262,19 @@  extern int __getlogin_r_chk (char *__buf, size_t __buflen, size_t __nreal)
      __nonnull ((1));
 extern int __REDIRECT (__getlogin_r_alias, (char *__buf, size_t __buflen),
 		       getlogin_r) __nonnull ((1));
-extern int __REDIRECT (__getlogin_r_chk_warn,
-		       (char *__buf, size_t __buflen, size_t __nreal),
-		       __getlogin_r_chk)
-     __nonnull ((1)) __warnattr ("getlogin_r called with bigger buflen than "
-				 "size of destination buffer");
 
-__fortify_function int
-getlogin_r (char *__buf, size_t __buflen)
+__fortify_potential_overload int
+getlogin_r (char *const __clang_pass_object_size __buf, size_t __buflen)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__getlogin_r_warn, __buflen, __buf,
+				       "getlogin_r called with bigger buflen "
+				       "than size of destination buffer")
 {
-  if (__bos (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__buflen))
-	return __getlogin_r_chk (__buf, __buflen, __bos (__buf));
-
-      if (__buflen > __bos (__buf))
-	return __getlogin_r_chk_warn (__buf, __buflen, __bos (__buf));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__buf) != (size_t) -1)
+    return __getlogin_r_chk (__buf, __buflen, __bos (__buf));
   return __getlogin_r_alias (__buf, __buflen);
 }
+__FORTIFY_FUNCTION_END
 #endif
 
 
@@ -334,25 +283,20 @@  extern int __gethostname_chk (char *__buf, size_t __buflen, size_t __nreal)
      __THROW __nonnull ((1));
 extern int __REDIRECT_NTH (__gethostname_alias, (char *__buf, size_t __buflen),
 			   gethostname) __nonnull ((1));
-extern int __REDIRECT_NTH (__gethostname_chk_warn,
-			   (char *__buf, size_t __buflen, size_t __nreal),
-			   __gethostname_chk)
-     __nonnull ((1)) __warnattr ("gethostname called with bigger buflen than "
-				 "size of destination buffer");
 
-__fortify_function int
-__NTH (gethostname (char *__buf, size_t __buflen))
+__fortify_potential_overload int
+__NTH (gethostname (char *const __clang_pass_object_size __buf,
+		    size_t __buflen))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__gethostname_warn, __buflen, __buf,
+				       "gethostname called with bigger buflen "
+				       "than size of destination buffer")
 {
-  if (__bos (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__buflen))
-	return __gethostname_chk (__buf, __buflen, __bos (__buf));
-
-      if (__buflen > __bos (__buf))
-	return __gethostname_chk_warn (__buf, __buflen, __bos (__buf));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__buf) != (size_t) -1)
+    return __gethostname_chk (__buf, __buflen, __bos (__buf));
   return __gethostname_alias (__buf, __buflen);
 }
+__FORTIFY_FUNCTION_END
 #endif
 
 
@@ -362,24 +306,18 @@  extern int __getdomainname_chk (char *__buf, size_t __buflen, size_t __nreal)
 extern int __REDIRECT_NTH (__getdomainname_alias, (char *__buf,
 						   size_t __buflen),
 			   getdomainname) __nonnull ((1)) __wur;
-extern int __REDIRECT_NTH (__getdomainname_chk_warn,
-			   (char *__buf, size_t __buflen, size_t __nreal),
-			   __getdomainname_chk)
-     __nonnull ((1)) __wur __warnattr ("getdomainname called with bigger "
-				       "buflen than size of destination "
-				       "buffer");
-
-__fortify_function int
-__NTH (getdomainname (char *__buf, size_t __buflen))
-{
-  if (__bos (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__buflen))
-	return __getdomainname_chk (__buf, __buflen, __bos (__buf));
 
-      if (__buflen > __bos (__buf))
-	return __getdomainname_chk_warn (__buf, __buflen, __bos (__buf));
-    }
+__fortify_potential_overload int
+__NTH (getdomainname (char *const __clang_pass_object_size __buf,
+		      size_t __buflen))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__getdomainname_warn, __buflen, __buf,
+				       "getdomainname called with bigger "
+				       "buflen than size of destination buffer")
+{
+  if (__FORTIFY_CALL_CHK && __bos (__buf) != (size_t) -1)
+    return __getdomainname_chk (__buf, __buflen, __bos (__buf));
   return __getdomainname_alias (__buf, __buflen);
 }
+__FORTIFY_FUNCTION_END
 #endif
diff --git a/rt/bits/mqueue2.h b/rt/bits/mqueue2.h
index 70ac65550e..886749cb9b 100644
--- a/rt/bits/mqueue2.h
+++ b/rt/bits/mqueue2.h
@@ -29,10 +29,47 @@  extern mqd_t __mq_open_2 (const char *__name, int __oflag)
 extern mqd_t __REDIRECT_NTH (__mq_open_alias, (const char *__name,
 					       int __oflag, ...), mq_open)
      __nonnull ((1));
+
+#define __warn_mq_open_wrong_number_of_args "mq_open can be called either " \
+  "with 2 or 4 arguments"
+#define __warn_mq_open_missing_mode_and_attr "mq_open with O_CREAT in " \
+  "second argument needs 4 arguments"
+#ifdef __use_clang_fortify
+__fortify_overload __clang_error (__warn_mq_open_wrong_number_of_args) mqd_t
+__NTH (mq_open (const char *const __clang_pass_object_size __name, int __oflag,
+		int __mode))
+{
+  return __mq_open_alias (__name, __oflag, __mode);
+}
+
+__fortify_overload __clang_error (__warn_mq_open_wrong_number_of_args)
+mqd_t
+__NTH (mq_open (const char *const __clang_pass_object_size __name, int __oflag,
+		int __mode, struct mq_attr *__attr, ...))
+{
+  return __mq_open_alias (__name, __oflag, __mode, __attr);
+}
+
+__fortify_overload __clang_prefer_this_overload mqd_t
+__NTH (mq_open (const char *const __clang_pass_object_size __name,
+		int __oflag))
+     __clang_error_if ((__oflag & O_CREAT),
+                       __warn_mq_open_missing_mode_and_attr)
+{
+  return __mq_open_alias (__name, __oflag);
+}
+
+__fortify_overload __clang_prefer_this_overload mqd_t
+__NTH (mq_open (const char *const __clang_pass_object_size __name, int __oflag,
+		int __mode, struct mq_attr *__attr))
+{
+  return __mq_open_alias (__name, __oflag, __mode, __attr);
+}
+#else
 __errordecl (__mq_open_wrong_number_of_args,
-	     "mq_open can be called either with 2 or 4 arguments");
+  __warn_mq_open_wrong_number_of_args);
 __errordecl (__mq_open_missing_mode_and_attr,
-	     "mq_open with O_CREAT in second argument needs 4 arguments");
+  __warn_mq_open_missing_mode_and_attr);
 
 __fortify_function mqd_t
 __NTH (mq_open (const char *__name, int __oflag, ...))
@@ -55,3 +92,6 @@  __NTH (mq_open (const char *__name, int __oflag, ...))
 
   return __mq_open_alias (__name, __oflag, __va_arg_pack ());
 }
+#endif
+#undef __warn_mq_open_wrong_number_of_args
+#undef __warn_mq_open_missing_mode_and_attr
diff --git a/rt/mqueue.h b/rt/mqueue.h
index c79aa53b94..4b77cda71f 100644
--- a/rt/mqueue.h
+++ b/rt/mqueue.h
@@ -89,7 +89,7 @@  extern int mq_timedsend (mqd_t __mqdes, const char *__msg_ptr,
 
 /* Define some inlines helping to catch common problems.  */
 #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function \
-    && defined __va_arg_pack_len
+    && (defined __va_arg_pack_len || defined __use_clang_fortify)
 # include <bits/mqueue2.h>
 #endif
 
diff --git a/socket/bits/socket2.h b/socket/bits/socket2.h
index 4f520d727f..5443ab08a5 100644
--- a/socket/bits/socket2.h
+++ b/socket/bits/socket2.h
@@ -24,25 +24,20 @@  extern ssize_t __recv_chk (int __fd, void *__buf, size_t __n, size_t __buflen,
 			   int __flags);
 extern ssize_t __REDIRECT (__recv_alias, (int __fd, void *__buf, size_t __n,
 					  int __flags), recv);
-extern ssize_t __REDIRECT (__recv_chk_warn,
-			   (int __fd, void *__buf, size_t __n, size_t __buflen,
-			    int __flags), __recv_chk)
-     __warnattr ("recv called with bigger length than size of destination "
-		 "buffer");
 
-__fortify_function ssize_t
-recv (int __fd, void *__buf, size_t __n, int __flags)
+__fortify_potential_overload ssize_t
+recv (int __fd, void *const __clang_pass_object_size0 __buf, size_t __n,
+      int __flags)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS0_LT (__recv_warn, __n, __buf,
+					"recv called with bigger length than "
+					"size of destination buffer")
 {
-  if (__bos0 (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__n))
-	return __recv_chk (__fd, __buf, __n, __bos0 (__buf), __flags);
-
-      if (__n > __bos0 (__buf))
-	return __recv_chk_warn (__fd, __buf, __n, __bos0 (__buf), __flags);
-    }
+  if (__FORTIFY_CALL_CHK && __bos0 (__buf) != (size_t) -1)
+    return __recv_chk (__fd, __buf, __n, __bos0 (__buf), __flags);
   return __recv_alias (__fd, __buf, __n, __flags);
 }
+__FORTIFY_FUNCTION_END
 
 extern ssize_t __recvfrom_chk (int __fd, void *__restrict __buf, size_t __n,
 			       size_t __buflen, int __flags,
@@ -52,26 +47,19 @@  extern ssize_t __REDIRECT (__recvfrom_alias,
 			   (int __fd, void *__restrict __buf, size_t __n,
 			    int __flags, __SOCKADDR_ARG __addr,
 			    socklen_t *__restrict __addr_len), recvfrom);
-extern ssize_t __REDIRECT (__recvfrom_chk_warn,
-			   (int __fd, void *__restrict __buf, size_t __n,
-			    size_t __buflen, int __flags,
-			    __SOCKADDR_ARG __addr,
-			    socklen_t *__restrict __addr_len), __recvfrom_chk)
-     __warnattr ("recvfrom called with bigger length than size of "
-		 "destination buffer");
 
-__fortify_function ssize_t
-recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags,
-	  __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)
+__fortify_potential_overload ssize_t
+recvfrom (int __fd, void *__restrict const __clang_pass_object_size0 __buf,
+	  size_t __n, int __flags, __SOCKADDR_ARG __addr,
+	  socklen_t *__restrict __addr_len)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS0_LT (__recvfrom_warn, __n, __buf,
+					"recvfrom called with bigger length "
+					"than size of destination buffer")
 {
-  if (__bos0 (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__n))
-	return __recvfrom_chk (__fd, __buf, __n, __bos0 (__buf), __flags,
-			       __addr, __addr_len);
-      if (__n > __bos0 (__buf))
-	return __recvfrom_chk_warn (__fd, __buf, __n, __bos0 (__buf), __flags,
-				    __addr, __addr_len);
-    }
+  if (__FORTIFY_CALL_CHK && __bos0 (__buf) != (size_t) -1)
+    return __recvfrom_chk (__fd, __buf, __n, __bos0 (__buf), __flags, __addr,
+			   __addr_len);
   return __recvfrom_alias (__fd, __buf, __n, __flags, __addr, __addr_len);
 }
+__FORTIFY_FUNCTION_END
diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
index 864284fc74..487fdc391b 100644
--- a/stdlib/bits/stdlib.h
+++ b/stdlib/bits/stdlib.h
@@ -26,27 +26,27 @@  extern char *__realpath_chk (const char *__restrict __name,
 extern char *__REDIRECT_NTH (__realpath_alias,
 			     (const char *__restrict __name,
 			      char *__restrict __resolved), realpath) __wur;
-extern char *__REDIRECT_NTH (__realpath_chk_warn,
-			     (const char *__restrict __name,
-			      char *__restrict __resolved,
-			      size_t __resolvedlen), __realpath_chk) __wur
-     __warnattr ("second argument of realpath must be either NULL or at "
-		 "least PATH_MAX bytes long buffer");
 
-__fortify_function __wur char *
-__NTH (realpath (const char *__restrict __name, char *__restrict __resolved))
+__fortify_potential_overload __wur char *
+__NTH (realpath (const char *__restrict __name,
+		 char *__restrict const __clang_pass_object_size __resolved))
+__FORTIFY_PRECONDITIONS
+#if defined _LIBC_LIMITS_H_ && defined PATH_MAX
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__realpath_warn, PATH_MAX, __resolved,
+				       "second argument of realpath must be "
+				       "either NULL or at least PATH_MAX "
+				       "bytes long buffer")
+#endif
 {
-  if (__bos (__resolved) != (size_t) -1)
-    {
+  if (
 #if defined _LIBC_LIMITS_H_ && defined PATH_MAX
-      if (__bos (__resolved) < PATH_MAX)
-	return __realpath_chk_warn (__name, __resolved, __bos (__resolved));
+      __FORTIFY_CALL_CHK &&
 #endif
-      return __realpath_chk (__name, __resolved, __bos (__resolved));
-    }
-
+      __bos (__resolved) != (size_t) -1)
+    return __realpath_chk (__name, __resolved, __bos (__resolved));
   return __realpath_alias (__name, __resolved);
 }
+__FORTIFY_FUNCTION_END
 
 
 extern int __ptsname_r_chk (int __fd, char *__buf, size_t __buflen,
@@ -54,33 +54,28 @@  extern int __ptsname_r_chk (int __fd, char *__buf, size_t __buflen,
 extern int __REDIRECT_NTH (__ptsname_r_alias, (int __fd, char *__buf,
 					       size_t __buflen), ptsname_r)
      __nonnull ((2));
-extern int __REDIRECT_NTH (__ptsname_r_chk_warn,
-			   (int __fd, char *__buf, size_t __buflen,
-			    size_t __nreal), __ptsname_r_chk)
-     __nonnull ((2)) __warnattr ("ptsname_r called with buflen bigger than "
-				 "size of buf");
-
-__fortify_function int
-__NTH (ptsname_r (int __fd, char *__buf, size_t __buflen))
+
+__fortify_potential_overload int
+__NTH (ptsname_r (int __fd, char *const __clang_pass_object_size __buf,
+		  size_t __buflen))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__ptsname_r_warn, __buflen, __buf,
+				       "ptsname_r called with buflen "
+				       "bigger than size of buf")
 {
-  if (__bos (__buf) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__buflen))
-	return __ptsname_r_chk (__fd, __buf, __buflen, __bos (__buf));
-      if (__buflen > __bos (__buf))
-	return __ptsname_r_chk_warn (__fd, __buf, __buflen, __bos (__buf));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__buf) != (size_t) -1)
+    return __ptsname_r_chk (__fd, __buf, __buflen, __bos (__buf));
   return __ptsname_r_alias (__fd, __buf, __buflen);
 }
-
+__FORTIFY_FUNCTION_END
 
 extern int __wctomb_chk (char *__s, wchar_t __wchar, size_t __buflen)
   __THROW __wur;
 extern int __REDIRECT_NTH (__wctomb_alias, (char *__s, wchar_t __wchar),
 			   wctomb) __wur;
 
-__fortify_function __wur int
-__NTH (wctomb (char *__s, wchar_t __wchar))
+__fortify_potential_overload __wur int
+__NTH (wctomb (char *const __clang_pass_object_size __s, wchar_t __wchar))
 {
   /* 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
@@ -102,29 +97,22 @@  extern size_t __REDIRECT_NTH (__mbstowcs_alias,
 			      (wchar_t *__restrict __dst,
 			       const char *__restrict __src,
 			       size_t __len), mbstowcs);
-extern size_t __REDIRECT_NTH (__mbstowcs_chk_warn,
-			      (wchar_t *__restrict __dst,
-			       const char *__restrict __src,
-			       size_t __len, size_t __dstlen), __mbstowcs_chk)
-     __warnattr ("mbstowcs called with dst buffer smaller than len "
-		 "* sizeof (wchar_t)");
 
-__fortify_function size_t
-__NTH (mbstowcs (wchar_t *__restrict __dst, const char *__restrict __src,
-		 size_t __len))
+__fortify_potential_overload size_t
+__NTH (mbstowcs (wchar_t *__restrict const __clang_pass_object_size __dst,
+		 const char *__restrict __src, size_t __len))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__mbstowcs_warn, __len, __dst,
+					sizeof (wchar_t),
+					"mbstowcs called with dst buffer "
+					"smaller than len * sizeof (wchar_t)")
 {
-  if (__bos (__dst) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__len))
-	return __mbstowcs_chk (__dst, __src, __len,
-			       __bos (__dst) / sizeof (wchar_t));
-
-      if (__len > __bos (__dst) / sizeof (wchar_t))
-	return __mbstowcs_chk_warn (__dst, __src, __len,
-				     __bos (__dst) / sizeof (wchar_t));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__dst) != (size_t) -1)
+    return __mbstowcs_chk (__dst, __src, __len,
+			   __bos (__dst) / sizeof (wchar_t));
   return __mbstowcs_alias (__dst, __src, __len);
 }
+__FORTIFY_FUNCTION_END
 
 
 extern size_t __wcstombs_chk (char *__restrict __dst,
@@ -134,22 +122,17 @@  extern size_t __REDIRECT_NTH (__wcstombs_alias,
 			      (char *__restrict __dst,
 			       const wchar_t *__restrict __src,
 			       size_t __len), wcstombs);
-extern size_t __REDIRECT_NTH (__wcstombs_chk_warn,
-			      (char *__restrict __dst,
-			       const wchar_t *__restrict __src,
-			       size_t __len, size_t __dstlen), __wcstombs_chk)
-     __warnattr ("wcstombs called with dst buffer smaller than len");
 
-__fortify_function size_t
-__NTH (wcstombs (char *__restrict __dst, const wchar_t *__restrict __src,
-		 size_t __len))
+__fortify_potential_overload size_t
+__NTH (wcstombs (char *__restrict const __clang_pass_object_size __dst,
+		 const wchar_t *__restrict __src, size_t __len))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__wcstombs_warn, __len, __dst,
+				       "wcstombs called with dst buffer "
+				       "smaller than len")
 {
-  if (__bos (__dst) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__len))
-	return __wcstombs_chk (__dst, __src, __len, __bos (__dst));
-      if (__len > __bos (__dst))
-	return __wcstombs_chk_warn (__dst, __src, __len, __bos (__dst));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__dst) != (size_t) -1)
+    return __wcstombs_chk (__dst, __src, __len, __bos (__dst));
   return __wcstombs_alias (__dst, __src, __len);
 }
+__FORTIFY_FUNCTION_END
diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h
index a89e757c9d..199cec7ad2 100644
--- a/string/bits/string_fortified.h
+++ b/string/bits/string_fortified.h
@@ -22,45 +22,70 @@ 
 # error "Never use <bits/string_fortified.h> directly; include <string.h> instead."
 #endif
 
-#if !__GNUC_PREREQ (5,0)
-__warndecl (__warn_memset_zero_len,
-	    "memset used with constant zero length parameter; this could be due to transposed parameters");
-#endif
-
-__fortify_function void *
-__NTH (memcpy (void *__restrict __dest, const void *__restrict __src,
-	       size_t __len))
+#define __warn_len_too_large \
+  "function called with bigger length than the destination buffer"
+/* Repeat bodies here to reduce 'note's if we detect a problem.  */
+#define __size_too_small(bos, dest, len) \
+  (bos (dest) != (size_t) -1 && bos (dest) < len)
+#define __warn_if_dest_too_small(dest, len) \
+  __clang_warning_if (__size_too_small (__bos, dest, len), \
+					__warn_len_too_large)
+#define __warn_if_dest_too_small0(dest, len) \
+  __clang_warning_if (__size_too_small (__bos0, dest, len), \
+					__warn_len_too_large)
+
+#define __warn_input_str_too_large \
+  "destination buffer will always be overflown by source"
+#define __warn_if_src_too_large(dest, src) \
+  __clang_warning_if (__size_too_small (__bos, dest, __builtin_strlen (src)), \
+		      __warn_input_str_too_large)
+
+__fortify_potential_overload void *
+__NTH (memcpy (void *__restrict const __clang_pass_object_size0 __dest,
+	       const void *__restrict __src, size_t __len))
+     __warn_if_dest_too_small0 (__dest, __len)
 {
   return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
 }
 
-__fortify_function void *
-__NTH (memmove (void *__dest, const void *__src, size_t __len))
+__fortify_potential_overload void *
+__NTH (memmove (void *const __clang_pass_object_size0 __dest,
+		const void *__src, size_t __len))
+     __warn_if_dest_too_small0 (__dest, __len)
 {
   return __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest));
 }
 
 #ifdef __USE_GNU
-__fortify_function void *
-__NTH (mempcpy (void *__restrict __dest, const void *__restrict __src,
-		size_t __len))
+__fortify_potential_overload void *
+__NTH (mempcpy (void *__restrict const __clang_pass_object_size0 __dest,
+		const void *__restrict __src, size_t __len))
+     __warn_if_dest_too_small0 (__dest, __len)
 {
   return __builtin___mempcpy_chk (__dest, __src, __len, __bos0 (__dest));
 }
 #endif
 
-
 /* The first two tests here help to catch a somewhat common problem
    where the second and third parameter are transposed.  This is
    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))
+#define __warn_memset_zero_len_msg \
+  "memset used with constant zero length parameter; this could be due to " \
+  "transposed parameters"
+#if !__GNUC_PREREQ (5,0)
+__warndecl (__warn_memset_zero_len, __warn_memset_zero_len_msg);
+#endif
+__fortify_potential_overload void *
+__NTH (memset (void *const __clang_pass_object_size0 __dest, int __ch,
+	       size_t __len))
+     __warn_if_dest_too_small0 (__dest, __len)
+     __clang_warning_if (__len == 0 && __ch != 0, __warn_memset_zero_len_msg)
 {
   /* GCC-5.0 and newer implements these checks in the compiler, so we don't
      need them here.  */
-#if !__GNUC_PREREQ (5,0)
+#if !__GNUC_PREREQ (5,0) && !defined __use_clang_fortify
   if (__builtin_constant_p (__len) && __len == 0
       && (!__builtin_constant_p (__ch) || __ch != 0))
     {
@@ -70,6 +95,7 @@  __NTH (memset (void *__dest, int __ch, size_t __len))
 #endif
   return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest));
 }
+#undef __warn_memset_zero_len_msg
 
 #ifdef __USE_MISC
 # include <bits/strings_fortified.h>
@@ -84,24 +110,30 @@  __NTH (explicit_bzero (void *__dest, size_t __len))
 }
 #endif
 
-__fortify_function char *
-__NTH (strcpy (char *__restrict __dest, const char *__restrict __src))
+__fortify_potential_overload char *
+__NTH (strcpy (char *__restrict const __clang_pass_object_size __dest,
+	       const char *__restrict __src))
+     __warn_if_src_too_large (__dest, __src)
 {
   return __builtin___strcpy_chk (__dest, __src, __bos (__dest));
 }
 
 #ifdef __USE_GNU
-__fortify_function char *
-__NTH (stpcpy (char *__restrict __dest, const char *__restrict __src))
+__fortify_potential_overload char *
+__NTH (stpcpy (char *__restrict const __clang_pass_object_size __dest,
+	       const char *__restrict __src))
+     __warn_if_src_too_large (__dest, __src)
 {
   return __builtin___stpcpy_chk (__dest, __src, __bos (__dest));
 }
 #endif
 
-
-__fortify_function char *
-__NTH (strncpy (char *__restrict __dest, const char *__restrict __src,
-		size_t __len))
+__fortify_potential_overload char *
+__NTH (strncpy (char *__restrict const __clang_pass_object_size __dest,
+		const char *__restrict __src, size_t __len))
+/* clang: Don't warn when __builtin_strlen (__src) < __bos (__dest),
+   but __len > __bos (__dest).  The user should fix their code instead.  */
+     __warn_if_dest_too_small (__dest, __len)
 {
   return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
 }
@@ -112,28 +144,36 @@  extern char *__stpncpy_chk (char *__dest, const char *__src, size_t __n,
 extern char *__REDIRECT_NTH (__stpncpy_alias, (char *__dest, const char *__src,
 					       size_t __n), stpncpy);
 
-__fortify_function char *
-__NTH (stpncpy (char *__dest, const char *__src, size_t __n))
+__fortify_potential_overload char *
+__NTH (stpncpy (char *const __clang_pass_object_size __dest, const char *__src,
+		size_t __n))
+     __warn_if_dest_too_small (__dest, __n)
 {
-  if (__bos (__dest) != (size_t) -1
-      && (!__builtin_constant_p (__n) || __n > __bos (__dest)))
+  if (__bos (__dest) != (size_t) -1)
     return __stpncpy_chk (__dest, __src, __n, __bos (__dest));
   return __stpncpy_alias (__dest, __src, __n);
 }
 
-
-__fortify_function char *
-__NTH (strcat (char *__restrict __dest, const char *__restrict __src))
+__fortify_potential_overload char *
+__NTH (strcat (char *__restrict const __clang_pass_object_size __dest,
+	       const char *__restrict __src))
+     __warn_if_src_too_large (__dest, __src)
 {
   return __builtin___strcat_chk (__dest, __src, __bos (__dest));
 }
 
-
-__fortify_function char *
-__NTH (strncat (char *__restrict __dest, const char *__restrict __src,
-		size_t __len))
+__fortify_potential_overload char *
+__NTH (strncat (char *__restrict const __clang_pass_object_size __dest,
+		const char *__restrict __src, size_t __len))
+     __warn_if_src_too_large (__dest, __src)
 {
   return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest));
 }
 
+#undef __warn_len_too_large
+#undef __size_too_small
+#undef __warn_if_dest_too_small
+#undef __warn_if_dest_too_small0
+#undef __warn_input_str_too_large
+#undef __warn_if_src_too_large
 #endif /* bits/string_fortified.h */
diff --git a/string/bits/strings_fortified.h b/string/bits/strings_fortified.h
index 411e7863d6..2098a36da4 100644
--- a/string/bits/strings_fortified.h
+++ b/string/bits/strings_fortified.h
@@ -19,16 +19,30 @@ 
 #ifndef __STRINGS_FORTIFIED
 # define __STRINGS_FORTIFIED 1
 
-__fortify_function void
-__NTH (bcopy (const void *__src, void *__dest, size_t __len))
+#define __warn_len_too_large \
+  "function called with bigger length than the destination buffer"
+
+#define __size_too_small(dest, len) \
+  (__bos0 (dest) != (size_t) -1 && __bos0 (dest) < len)
+
+__fortify_potential_overload void
+__NTH (bcopy (const void *__src, void *const __clang_pass_object_size0 __dest,
+	      size_t __len))
+     __clang_warning_if (__size_too_small (__dest, __len),
+			 __warn_len_too_large)
 {
   (void) __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest));
 }
 
-__fortify_function void
-__NTH (bzero (void *__dest, size_t __len))
+__fortify_potential_overload void
+__NTH (bzero (void *const __clang_pass_object_size0 __dest, size_t __len))
+     __clang_warning_if (__size_too_small (__dest, __len),
+			 __warn_len_too_large)
 {
   (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest));
 }
 
+
+#undef __size_too_small
+#undef __warn_len_too_large
 #endif
diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
index 4a461e6e29..7b9db7806e 100644
--- a/wcsmbs/bits/wchar2.h
+++ b/wcsmbs/bits/wchar2.h
@@ -20,7 +20,6 @@ 
 # error "Never include <bits/wchar2.h> directly; use <wchar.h> instead."
 #endif
 
-
 extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1,
 			       const wchar_t *__restrict __s2, size_t __n,
 			       size_t __ns1) __THROW;
@@ -28,57 +27,42 @@  extern wchar_t *__REDIRECT_NTH (__wmemcpy_alias,
 				(wchar_t *__restrict __s1,
 				 const wchar_t *__restrict __s2, size_t __n),
 				wmemcpy);
-extern wchar_t *__REDIRECT_NTH (__wmemcpy_chk_warn,
-				(wchar_t *__restrict __s1,
-				 const wchar_t *__restrict __s2, size_t __n,
-				 size_t __ns1), __wmemcpy_chk)
-     __warnattr ("wmemcpy called with length bigger than size of destination "
-		 "buffer");
 
-__fortify_function wchar_t *
-__NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
-		size_t __n))
+__fortify_potential_overload wchar_t *
+__NTH (wmemcpy (wchar_t *__restrict const __clang_pass_object_size0 __s1,
+	      const wchar_t *__restrict __s2, size_t __n))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemcpy_warn, __n, __s1,
+					 sizeof (wchar_t),
+					 "wmemcpy called with length bigger "
+					 "than size of destination buffer")
 {
-  if (__bos0 (__s1) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__n))
-	return __wmemcpy_chk (__s1, __s2, __n,
-			      __bos0 (__s1) / sizeof (wchar_t));
-
-      if (__n > __bos0 (__s1) / sizeof (wchar_t))
-	return __wmemcpy_chk_warn (__s1, __s2, __n,
-				   __bos0 (__s1) / sizeof (wchar_t));
-    }
-  return __wmemcpy_alias (__s1, __s2, __n);
+  if (__FORTIFY_CALL_CHK && __bos0 (__s1) != (size_t)-1)
+    return __wmemcpy_chk(__s1, __s2, __n, __bos0(__s1) / sizeof (wchar_t));
+  return __wmemcpy_alias(__s1, __s2, __n);
 }
-
+__FORTIFY_FUNCTION_END
 
 extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2,
 				size_t __n, size_t __ns1) __THROW;
 extern wchar_t *__REDIRECT_NTH (__wmemmove_alias, (wchar_t *__s1,
 						   const wchar_t *__s2,
 						   size_t __n), wmemmove);
-extern wchar_t *__REDIRECT_NTH (__wmemmove_chk_warn,
-				(wchar_t *__s1, const wchar_t *__s2,
-				 size_t __n, size_t __ns1), __wmemmove_chk)
-     __warnattr ("wmemmove called with length bigger than size of destination "
-		 "buffer");
-
-__fortify_function wchar_t *
-__NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
+
+__fortify_potential_overload wchar_t *
+__NTH (wmemmove (wchar_t *const __clang_pass_object_size0 __s1,
+		 const wchar_t *__s2, size_t __n))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemmove_warn, __n, __s1,
+					 sizeof (wchar_t),
+					 "wmemmove called with length bigger "
+					 "than size of destination buffer")
 {
-  if (__bos0 (__s1) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__n))
-	return __wmemmove_chk (__s1, __s2, __n,
-			       __bos0 (__s1) / sizeof (wchar_t));
-
-      if (__n > __bos0 (__s1) / sizeof (wchar_t))
-	return __wmemmove_chk_warn (__s1, __s2, __n,
-				    __bos0 (__s1) / sizeof (wchar_t));
-    }
+  if (__FORTIFY_CALL_CHK && __bos0 (__s1) != (size_t) -1)
+    return __wmemmove_chk (__s1, __s2, __n, __bos0 (__s1) / sizeof (wchar_t));
   return __wmemmove_alias (__s1, __s2, __n);
 }
+__FORTIFY_FUNCTION_END
 
 
 #ifdef __USE_GNU
@@ -89,29 +73,21 @@  extern wchar_t *__REDIRECT_NTH (__wmempcpy_alias,
 				(wchar_t *__restrict __s1,
 				 const wchar_t *__restrict __s2,
 				 size_t __n), wmempcpy);
-extern wchar_t *__REDIRECT_NTH (__wmempcpy_chk_warn,
-				(wchar_t *__restrict __s1,
-				 const wchar_t *__restrict __s2, size_t __n,
-				 size_t __ns1), __wmempcpy_chk)
-     __warnattr ("wmempcpy called with length bigger than size of destination "
-		 "buffer");
-
-__fortify_function wchar_t *
-__NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
-		 size_t __n))
+
+__fortify_potential_overload wchar_t *
+__NTH(wmempcpy(wchar_t *__restrict const __clang_pass_object_size0 __s1,
+               const wchar_t *__restrict __s2, size_t __n))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmempcpy_warn, __n, __s1,
+					 sizeof (wchar_t),
+					 "wmempcpy called with length bigger "
+					 "than size of destination buffer")
 {
-  if (__bos0 (__s1) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__n))
-	return __wmempcpy_chk (__s1, __s2, __n,
-			       __bos0 (__s1) / sizeof (wchar_t));
-
-      if (__n > __bos0 (__s1) / sizeof (wchar_t))
-	return __wmempcpy_chk_warn (__s1, __s2, __n,
-				    __bos0 (__s1) / sizeof (wchar_t));
-    }
-  return __wmempcpy_alias (__s1, __s2, __n);
+  if (__FORTIFY_CALL_CHK && __bos0 (__s1) != (size_t)-1)
+    return __wmempcpy_chk(__s1, __s2, __n, __bos0(__s1) / sizeof (wchar_t));
+  return __wmempcpy_alias(__s1, __s2, __n);
 }
+__FORTIFY_FUNCTION_END
 #endif
 
 
@@ -119,26 +95,21 @@  extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n,
 			       size_t __ns) __THROW;
 extern wchar_t *__REDIRECT_NTH (__wmemset_alias, (wchar_t *__s, wchar_t __c,
 						  size_t __n), wmemset);
-extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn,
-				(wchar_t *__s, wchar_t __c, size_t __n,
-				 size_t __ns), __wmemset_chk)
-     __warnattr ("wmemset called with length bigger than size of destination "
-		 "buffer");
-
-__fortify_function wchar_t *
-__NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n))
+
+__fortify_potential_overload wchar_t *
+__NTH (wmemset (wchar_t *const __clang_pass_object_size0 __s, wchar_t __c,
+		size_t __n))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS0_LT2 (__wmemset_warn, __n, __s,
+					 sizeof (wchar_t),
+					 "wmemset called with length bigger "
+					 "than size of destination buffer")
 {
-  if (__bos0 (__s) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__n))
-	return __wmemset_chk (__s, __c, __n, __bos0 (__s) / sizeof (wchar_t));
-
-      if (__n > __bos0 (__s) / sizeof (wchar_t))
-	return __wmemset_chk_warn (__s, __c, __n,
-				   __bos0 (__s) / sizeof (wchar_t));
-    }
+  if (__FORTIFY_CALL_CHK && __bos0 (__s) != (size_t) -1)
+    return __wmemset_chk (__s, __c, __n, __bos0 (__s) / sizeof (wchar_t));
   return __wmemset_alias (__s, __c, __n);
 }
+__FORTIFY_FUNCTION_END
 
 
 extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest,
@@ -148,8 +119,9 @@  extern wchar_t *__REDIRECT_NTH (__wcscpy_alias,
 				(wchar_t *__restrict __dest,
 				 const wchar_t *__restrict __src), wcscpy);
 
-__fortify_function wchar_t *
-__NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+__fortify_potential_overload wchar_t *
+__NTH (wcscpy (wchar_t *__restrict const __clang_pass_object_size __dest,
+	       const wchar_t *__restrict __src))
 {
   if (__bos (__dest) != (size_t) -1)
     return __wcscpy_chk (__dest, __src, __bos (__dest) / sizeof (wchar_t));
@@ -164,8 +136,9 @@  extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias,
 				(wchar_t *__restrict __dest,
 				 const wchar_t *__restrict __src), wcpcpy);
 
-__fortify_function wchar_t *
-__NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+__fortify_potential_overload wchar_t *
+__NTH (wcpcpy (wchar_t *__restrict const __clang_pass_object_size __dest,
+	       const wchar_t *__restrict __src))
 {
   if (__bos (__dest) != (size_t) -1)
     return __wcpcpy_chk (__dest, __src, __bos (__dest) / sizeof (wchar_t));
@@ -180,28 +153,22 @@  extern wchar_t *__REDIRECT_NTH (__wcsncpy_alias,
 				(wchar_t *__restrict __dest,
 				 const wchar_t *__restrict __src,
 				 size_t __n), wcsncpy);
-extern wchar_t *__REDIRECT_NTH (__wcsncpy_chk_warn,
-				(wchar_t *__restrict __dest,
-				 const wchar_t *__restrict __src,
-				 size_t __n, size_t __destlen), __wcsncpy_chk)
-     __warnattr ("wcsncpy called with length bigger than size of destination "
-		 "buffer");
 
-__fortify_function wchar_t *
-__NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_potential_overload wchar_t *
+__NTH (wcsncpy (wchar_t *__restrict const __clang_pass_object_size __dest,
+		const wchar_t *__restrict __src, size_t __n))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__wcsncpy_warn, __n, __dest,
+					sizeof (wchar_t),
+					"wcsncpy called with length bigger "
+					"than size of destination buffer")
 {
-  if (__bos (__dest) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__n))
-	return __wcsncpy_chk (__dest, __src, __n,
-			      __bos (__dest) / sizeof (wchar_t));
-      if (__n > __bos (__dest) / sizeof (wchar_t))
-	return __wcsncpy_chk_warn (__dest, __src, __n,
-				   __bos (__dest) / sizeof (wchar_t));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__dest) != (size_t) -1)
+    return __wcsncpy_chk (__dest, __src, __n,
+			  __bos (__dest) / sizeof (wchar_t));
   return __wcsncpy_alias (__dest, __src, __n);
 }
+__FORTIFY_FUNCTION_END
 
 
 extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest,
@@ -211,29 +178,22 @@  extern wchar_t *__REDIRECT_NTH (__wcpncpy_alias,
 				(wchar_t *__restrict __dest,
 				 const wchar_t *__restrict __src,
 				 size_t __n), wcpncpy);
-extern wchar_t *__REDIRECT_NTH (__wcpncpy_chk_warn,
-				(wchar_t *__restrict __dest,
-				 const wchar_t *__restrict __src,
-				 size_t __n, size_t __destlen), __wcpncpy_chk)
-     __warnattr ("wcpncpy called with length bigger than size of destination "
-		 "buffer");
 
-__fortify_function wchar_t *
-__NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_potential_overload wchar_t *
+__NTH (wcpncpy (wchar_t *__restrict const __clang_pass_object_size __dest,
+		const wchar_t *__restrict __src, size_t __n))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__wcpncpy_warn, __n, __dest,
+					sizeof (wchar_t),
+					"wcpncpy called with length bigger "
+					"than size of destination buffer")
 {
-  if (__bos (__dest) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__n))
-	return __wcpncpy_chk (__dest, __src, __n,
-			      __bos (__dest) / sizeof (wchar_t));
-      if (__n > __bos (__dest) / sizeof (wchar_t))
-	return __wcpncpy_chk_warn (__dest, __src, __n,
-				   __bos (__dest) / sizeof (wchar_t));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__dest) != (size_t) -1)
+    return __wcpncpy_chk (__dest, __src, __n,
+			  __bos (__dest) / sizeof (wchar_t));
   return __wcpncpy_alias (__dest, __src, __n);
 }
-
+__FORTIFY_FUNCTION_END
 
 extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest,
 			      const wchar_t *__restrict __src,
@@ -242,8 +202,9 @@  extern wchar_t *__REDIRECT_NTH (__wcscat_alias,
 				(wchar_t *__restrict __dest,
 				 const wchar_t *__restrict __src), wcscat);
 
-__fortify_function wchar_t *
-__NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+__fortify_potential_overload wchar_t *
+__NTH (wcscat (wchar_t *__restrict const __clang_pass_object_size __dest,
+	       const wchar_t *__restrict __src))
 {
   if (__bos (__dest) != (size_t) -1)
     return __wcscat_chk (__dest, __src, __bos (__dest) / sizeof (wchar_t));
@@ -259,9 +220,9 @@  extern wchar_t *__REDIRECT_NTH (__wcsncat_alias,
 				 const wchar_t *__restrict __src,
 				 size_t __n), wcsncat);
 
-__fortify_function wchar_t *
-__NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_potential_overload wchar_t *
+__NTH (wcsncat (wchar_t *__restrict const __clang_pass_object_size __dest,
+		const wchar_t *__restrict __src, size_t __n))
 {
   if (__bos (__dest) != (size_t) -1)
     return __wcsncat_chk (__dest, __src, __n,
@@ -280,16 +241,34 @@  extern int __REDIRECT_NTH_LDBL (__swprintf_alias,
 				 const wchar_t *__restrict __fmt, ...),
 				swprintf);
 
-#ifdef __va_arg_pack
-__fortify_function int
-__NTH (swprintf (wchar_t *__restrict __s, size_t __n,
-		 const wchar_t *__restrict __fmt, ...))
+extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
+			    int __flag, size_t __s_len,
+			    const wchar_t *__restrict __format,
+			    __gnuc_va_list __arg)
+     __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
+
+extern int __REDIRECT_NTH_LDBL (__vswprintf_alias,
+				(wchar_t *__restrict __s, size_t __n,
+				 const wchar_t *__restrict __fmt,
+				 __gnuc_va_list __ap), vswprintf);
+
+#ifdef __FORTIFY_ARG_PACK_OK
+__fortify_potential_overload int
+__NTH (swprintf (wchar_t *__restrict const __clang_pass_object_size __s,
+		 size_t __n, const wchar_t *__restrict __fmt, ...))
 {
+  __FORTIFY_INIT_ARG_PACK(__fmt);
+  int __result;
   if (__bos (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
-    return __swprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
-			   __bos (__s) / sizeof (wchar_t),
-			   __fmt, __va_arg_pack ());
-  return __swprintf_alias (__s, __n, __fmt, __va_arg_pack ());
+    __result = __FORTIFY_CALL_VA_CHK(swprintf, __s, __n,
+				     __USE_FORTIFY_LEVEL - 1,
+				     __bos (__s) / sizeof (wchar_t), __fmt,
+				     __FORTIFY_ARG_PACK);
+  else
+    __result = __FORTIFY_CALL_VA_ALIAS(swprintf, __s, __n, __fmt,
+				       __FORTIFY_ARG_PACK);
+  __FORTIFY_FREE_ARG_PACK();
+  return __result;
 }
 #elif !defined __cplusplus
 /* XXX We might want to have support in gcc for swprintf.  */
@@ -300,20 +279,10 @@  __NTH (swprintf (wchar_t *__restrict __s, size_t __n,
    : swprintf (s, n, __VA_ARGS__))
 #endif
 
-extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n,
-			    int __flag, size_t __s_len,
-			    const wchar_t *__restrict __format,
-			    __gnuc_va_list __arg)
-     __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */;
-
-extern int __REDIRECT_NTH_LDBL (__vswprintf_alias,
-				(wchar_t *__restrict __s, size_t __n,
-				 const wchar_t *__restrict __fmt,
-				 __gnuc_va_list __ap), vswprintf);
-
-__fortify_function int
-__NTH (vswprintf (wchar_t *__restrict __s, size_t __n,
-		  const wchar_t *__restrict __fmt, __gnuc_va_list __ap))
+__fortify_potential_overload int
+__NTH (vswprintf (wchar_t *__restrict const __clang_pass_object_size __s,
+		  size_t __n, const wchar_t *__restrict __fmt,
+		  __gnuc_va_list __ap))
 {
   if (__bos (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
     return __vswprintf_chk (__s, __n,  __USE_FORTIFY_LEVEL - 1,
@@ -334,18 +303,27 @@  extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag,
 extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format,
 			   __gnuc_va_list __ap);
 
-# ifdef __va_arg_pack
-__fortify_function int
-wprintf (const wchar_t *__restrict __fmt, ...)
+
+#ifdef __FORTIFY_ARG_PACK_OK
+__fortify_potential_overload int
+wprintf (const wchar_t *__restrict const __clang_pass_object_size __fmt, ...)
 {
-  return __wprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
+  __FORTIFY_INIT_ARG_PACK(__fmt);
+  int __r = __FORTIFY_CALL_VA_CHK (wprintf, __USE_FORTIFY_LEVEL - 1, __fmt,
+				   __FORTIFY_ARG_PACK);
+  __FORTIFY_FREE_ARG_PACK();
+  return __r;
 }
 
-__fortify_function int
-fwprintf (__FILE *__restrict __stream, const wchar_t *__restrict __fmt, ...)
+__fortify_potential_overload int
+fwprintf (__FILE *__restrict const __clang_pass_object_size __stream,
+	  const wchar_t *__restrict __fmt, ...)
 {
-  return __fwprintf_chk (__stream, __USE_FORTIFY_LEVEL - 1, __fmt,
-			 __va_arg_pack ());
+  __FORTIFY_INIT_ARG_PACK(__fmt);
+  int __r = __FORTIFY_CALL_VA_CHK (fwprintf, __stream, __USE_FORTIFY_LEVEL - 1,
+				   __fmt, __FORTIFY_ARG_PACK);
+  __FORTIFY_FREE_ARG_PACK();
+  return __r;
 }
 # elif !defined __cplusplus
 #  define wprintf(...) \
@@ -354,14 +332,15 @@  fwprintf (__FILE *__restrict __stream, const wchar_t *__restrict __fmt, ...)
   __fwprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
 # endif
 
-__fortify_function int
-vwprintf (const wchar_t *__restrict __fmt, __gnuc_va_list __ap)
+__fortify_potential_overload int
+vwprintf (const wchar_t *__restrict const __clang_pass_object_size __fmt,
+	  __gnuc_va_list __ap)
 {
   return __vwprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __ap);
 }
 
-__fortify_function int
-vfwprintf (__FILE *__restrict __stream,
+__fortify_potential_overload int
+vfwprintf (__FILE *__restrict const __clang_pass_object_size __stream,
 	   const wchar_t *__restrict __fmt, __gnuc_va_list __ap)
 {
   return __vfwprintf_chk (__stream, __USE_FORTIFY_LEVEL - 1, __fmt, __ap);
@@ -374,27 +353,21 @@  extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n,
 extern wchar_t *__REDIRECT (__fgetws_alias,
 			    (wchar_t *__restrict __s, int __n,
 			     __FILE *__restrict __stream), fgetws) __wur;
-extern wchar_t *__REDIRECT (__fgetws_chk_warn,
-			    (wchar_t *__restrict __s, size_t __size, int __n,
-			     __FILE *__restrict __stream), __fgetws_chk)
-     __wur __warnattr ("fgetws called with bigger size than length "
-		       "of destination buffer");
-
-__fortify_function __wur wchar_t *
-fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
-{
-  if (__bos (__s) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__n) || __n <= 0)
-	return __fgetws_chk (__s, __bos (__s) / sizeof (wchar_t),
-			     __n, __stream);
 
-      if ((size_t) __n > __bos (__s) / sizeof (wchar_t))
-	return __fgetws_chk_warn (__s, __bos (__s) / sizeof (wchar_t),
-				  __n, __stream);
-    }
+__fortify_potential_overload __wur wchar_t *
+fgetws (wchar_t *__restrict const __clang_pass_object_size __s, int __n,
+	__FILE *__restrict __stream)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__fgetws_warn, __n, __s,
+					sizeof (wchar_t),
+					"fgetws called with length bigger "
+					"than size of destination buffer")
+{
+  if (__FORTIFY_CALL_CHK && __bos (__s) != (size_t) -1)
+    return __fgetws_chk (__s, __bos (__s) / sizeof (wchar_t), __n, __stream);
   return __fgetws_alias (__s, __n, __stream);
 }
+__FORTIFY_FUNCTION_END
 
 #ifdef __USE_GNU
 extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size,
@@ -404,28 +377,23 @@  extern wchar_t *__REDIRECT (__fgetws_unlocked_alias,
 			    (wchar_t *__restrict __s, int __n,
 			     __FILE *__restrict __stream), fgetws_unlocked)
   __wur;
-extern wchar_t *__REDIRECT (__fgetws_unlocked_chk_warn,
-			    (wchar_t *__restrict __s, size_t __size, int __n,
-			     __FILE *__restrict __stream),
-			    __fgetws_unlocked_chk)
-     __wur __warnattr ("fgetws_unlocked called with bigger size than length "
-		       "of destination buffer");
-
-__fortify_function __wur wchar_t *
-fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
+
+__fortify_potential_overload __wur wchar_t *
+fgetws_unlocked (wchar_t *__restrict const __clang_pass_object_size __s,
+		 int __n, __FILE *__restrict __stream)
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_IF (__fgetws_unlocked_warn,
+			   __n > 0
+			    && __bos_static_lt2 (__n, __s, sizeof (wchar_t)),
+			   "fgetws_unlocked called with bigger size than "
+			   "length of destination buffer")
 {
   if (__bos (__s) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__n) || __n <= 0)
-	return __fgetws_unlocked_chk (__s, __bos (__s) / sizeof (wchar_t),
-				      __n, __stream);
-
-      if ((size_t) __n > __bos (__s) / sizeof (wchar_t))
-	return __fgetws_unlocked_chk_warn (__s, __bos (__s) / sizeof (wchar_t),
-					   __n, __stream);
-    }
+    return __fgetws_unlocked_chk (__s, __bos (__s) / sizeof (wchar_t),
+				  __n, __stream);
   return __fgetws_unlocked_alias (__s, __n, __stream);
 }
+__FORTIFY_FUNCTION_END
 #endif
 
 
@@ -436,9 +404,9 @@  extern size_t __REDIRECT_NTH (__wcrtomb_alias,
 			      (char *__restrict __s, wchar_t __wchar,
 			       mbstate_t *__restrict __ps), wcrtomb) __wur;
 
-__fortify_function __wur size_t
-__NTH (wcrtomb (char *__restrict __s, wchar_t __wchar,
-		mbstate_t *__restrict __ps))
+__fortify_potential_overload __wur size_t
+__NTH (wcrtomb (char *__restrict const __clang_pass_object_size __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
@@ -462,30 +430,23 @@  extern size_t __REDIRECT_NTH (__mbsrtowcs_alias,
 			       const char **__restrict __src,
 			       size_t __len, mbstate_t *__restrict __ps),
 			      mbsrtowcs);
-extern size_t __REDIRECT_NTH (__mbsrtowcs_chk_warn,
-			      (wchar_t *__restrict __dst,
-			       const char **__restrict __src,
-			       size_t __len, mbstate_t *__restrict __ps,
-			       size_t __dstlen), __mbsrtowcs_chk)
-     __warnattr ("mbsrtowcs called with dst buffer smaller than len "
-		 "* sizeof (wchar_t)");
 
-__fortify_function size_t
-__NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
-		  size_t __len, mbstate_t *__restrict __ps))
+__fortify_potential_overload size_t
+__NTH (mbsrtowcs (wchar_t *__restrict const __clang_pass_object_size __dst,
+		  const char **__restrict __src, size_t __len,
+		  mbstate_t *__restrict __ps))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT2 (__mbsrtowcs_warn, __len, __dst,
+					sizeof (wchar_t),
+					"mbsrtowcs called with dst buffer "
+					"smaller than len * sizeof (wchar_t)")
 {
-  if (__bos (__dst) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__len))
-	return __mbsrtowcs_chk (__dst, __src, __len, __ps,
-				__bos (__dst) / sizeof (wchar_t));
-
-      if (__len > __bos (__dst) / sizeof (wchar_t))
-	return __mbsrtowcs_chk_warn (__dst, __src, __len, __ps,
-				     __bos (__dst) / sizeof (wchar_t));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__dst) != (size_t) -1)
+    return __mbsrtowcs_chk (__dst, __src, __len, __ps,
+			    __bos (__dst) / sizeof (wchar_t));
   return __mbsrtowcs_alias (__dst, __src, __len, __ps);
 }
+__FORTIFY_FUNCTION_END
 
 
 extern size_t __wcsrtombs_chk (char *__restrict __dst,
@@ -497,27 +458,21 @@  extern size_t __REDIRECT_NTH (__wcsrtombs_alias,
 			       const wchar_t **__restrict __src,
 			       size_t __len, mbstate_t *__restrict __ps),
 			      wcsrtombs);
-extern size_t __REDIRECT_NTH (__wcsrtombs_chk_warn,
-			      (char *__restrict __dst,
-			       const wchar_t **__restrict __src,
-			       size_t __len, mbstate_t *__restrict __ps,
-			       size_t __dstlen), __wcsrtombs_chk)
-    __warnattr ("wcsrtombs called with dst buffer smaller than len");
 
-__fortify_function size_t
-__NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
-		  size_t __len, mbstate_t *__restrict __ps))
+__fortify_potential_overload size_t
+__NTH (wcsrtombs (char *__restrict const __clang_pass_object_size __dst,
+		  const wchar_t **__restrict __src, size_t __len,
+		  mbstate_t *__restrict __ps))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__wcsrtombs_warn, __len, __dst,
+				       "wcsrtombs called with dst buffer "
+				       "smaller than len")
 {
-  if (__bos (__dst) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__len))
-	return __wcsrtombs_chk (__dst, __src, __len, __ps, __bos (__dst));
-
-      if (__len > __bos (__dst))
-	return __wcsrtombs_chk_warn (__dst, __src, __len, __ps, __bos (__dst));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__dst) != (size_t) -1)
+    return __wcsrtombs_chk (__dst, __src, __len, __ps, __bos (__dst));
   return __wcsrtombs_alias (__dst, __src, __len, __ps);
 }
+__FORTIFY_FUNCTION_END
 
 
 #ifdef __USE_GNU
@@ -530,30 +485,23 @@  extern size_t __REDIRECT_NTH (__mbsnrtowcs_alias,
 			       const char **__restrict __src, size_t __nmc,
 			       size_t __len, mbstate_t *__restrict __ps),
 			      mbsnrtowcs);
-extern size_t __REDIRECT_NTH (__mbsnrtowcs_chk_warn,
-			      (wchar_t *__restrict __dst,
-			       const char **__restrict __src, size_t __nmc,
-			       size_t __len, mbstate_t *__restrict __ps,
-			       size_t __dstlen), __mbsnrtowcs_chk)
-     __warnattr ("mbsnrtowcs called with dst buffer smaller than len "
-		 "* sizeof (wchar_t)");
 
-__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_potential_overload size_t
+__NTH (mbsnrtowcs (wchar_t *__restrict const __clang_pass_object_size __dst,
+		   const char **__restrict __src, size_t __nmc, size_t __len,
+		   mbstate_t *__restrict __ps))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__mbsnrtowcs_warn,
+				       sizeof (wchar_t) * __len, __dst,
+				       "mbsnrtowcs called with dst buffer "
+				       "smaller than len * sizeof (wchar_t)")
 {
-  if (__bos (__dst) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__len))
-	return __mbsnrtowcs_chk (__dst, __src, __nmc, __len, __ps,
-				 __bos (__dst) / sizeof (wchar_t));
-
-      if (__len > __bos (__dst) / sizeof (wchar_t))
-	return __mbsnrtowcs_chk_warn (__dst, __src, __nmc, __len, __ps,
-				      __bos (__dst) / sizeof (wchar_t));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__dst) != (size_t) -1)
+    return __mbsnrtowcs_chk (__dst, __src, __nmc, __len, __ps,
+			     __bos (__dst) / sizeof (wchar_t));
   return __mbsnrtowcs_alias (__dst, __src, __nmc, __len, __ps);
 }
+__FORTIFY_FUNCTION_END
 
 
 extern size_t __wcsnrtombs_chk (char *__restrict __dst,
@@ -566,28 +514,19 @@  extern size_t __REDIRECT_NTH (__wcsnrtombs_alias,
 			       const wchar_t **__restrict __src,
 			       size_t __nwc, size_t __len,
 			       mbstate_t *__restrict __ps), wcsnrtombs);
-extern size_t __REDIRECT_NTH (__wcsnrtombs_chk_warn,
-			      (char *__restrict __dst,
-			       const wchar_t **__restrict __src,
-			       size_t __nwc, size_t __len,
-			       mbstate_t *__restrict __ps,
-			       size_t __dstlen), __wcsnrtombs_chk)
-     __warnattr ("wcsnrtombs called with dst buffer smaller than len");
 
-__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_potential_overload size_t
+__NTH (wcsnrtombs (char *__restrict const __clang_pass_object_size __dst,
+		   const wchar_t **__restrict __src, size_t __nwc, size_t __len,
+		   mbstate_t *__restrict __ps))
+__FORTIFY_PRECONDITIONS
+     __FORTIFY_WARNING_ONLY_IF_BOS_LT (__wcsnrtombs_warn, __len, __dst,
+				       "wcsnrtombs called with dst buffer "
+				       "smaller than len")
 {
-  if (__bos (__dst) != (size_t) -1)
-    {
-      if (!__builtin_constant_p (__len))
-	return __wcsnrtombs_chk (__dst, __src, __nwc, __len, __ps,
-				 __bos (__dst));
-
-      if (__len > __bos (__dst))
-	return __wcsnrtombs_chk_warn (__dst, __src, __nwc, __len, __ps,
-				      __bos (__dst));
-    }
+  if (__FORTIFY_CALL_CHK && __bos (__dst) != (size_t) -1)
+    return __wcsnrtombs_chk (__dst, __src, __nwc, __len, __ps, __bos (__dst));
   return __wcsnrtombs_alias (__dst, __src, __nwc, __len, __ps);
 }
+__FORTIFY_FUNCTION_END
 #endif