commit 5dd7fa4810de0b5ae150af4d7eb1e6672fafb70d
Author: Nick Mathewson <nickm@torproject.org>
Date:   Mon Dec 15 09:14:48 2014 -0500

    Add new explicit_bzero() function

diff --git a/debug/tst-chk1.c b/debug/tst-chk1.c
index 3393153..9085e3e 100644
--- a/debug/tst-chk1.c
+++ b/debug/tst-chk1.c
@@ -283,6 +283,10 @@ do_test (void)
   CHK_FAIL_END
 
   CHK_FAIL_START
+  explicit_bzero (buf + 9, l0 + 2);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
   strcpy (buf + 5, str1 + 5);
   CHK_FAIL_END
 
diff --git a/include/string.h b/include/string.h
index 034e295..64340be 100644
--- a/include/string.h
+++ b/include/string.h
@@ -100,6 +100,7 @@ libc_hidden_builtin_proto (mempcpy)
 libc_hidden_builtin_proto (memcmp)
 libc_hidden_builtin_proto (memmove)
 libc_hidden_builtin_proto (memset)
+libc_hidden_builtin_proto (bzero)
 libc_hidden_builtin_proto (strcat)
 libc_hidden_builtin_proto (strchr)
 libc_hidden_builtin_proto (strcmp)
diff --git a/manual/string.texi b/manual/string.texi
index ba5a2c7..9fa60d8 100644
--- a/manual/string.texi
+++ b/manual/string.texi
@@ -1057,6 +1057,17 @@ BSD.  Note that it is not as general as @code{memset}, because the only
 value it can store is zero.
 @end deftypefun
 
+@comment string.h
+@comment BSD
+@deftypefun void explicit_bzero (void *@var{block}, size_t @var{size})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+This function behaves as @code{bzero} or as @code{memset(block, 0, size)},
+except that the compiler is not permitted to perform dead-assignment
+elimination on it.  It can be useful in cryptographic code that needs to
+clear sensitive data from the stack.
+@end deftypefun
+
+
 @node String/Array Comparison
 @section String/Array Comparison
 @cindex comparing strings and arrays
diff --git a/string/Makefile b/string/Makefile
index 98c2961..6fd9726 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -33,6 +33,7 @@ routines	:= strcat strchr strcmp strcoll strcpy strcspn		\
 		   strrchr strpbrk strsignal strspn strstr strtok	\
 		   strtok_r strxfrm memchr memcmp memmove memset	\
 		   mempcpy bcopy bzero ffs ffsll stpcpy stpncpy		\
+		   explicit_bzero					\
 		   strcasecmp strncase strcasecmp_l strncase_l		\
 		   memccpy memcpy wordcopy strsep strcasestr		\
 		   swab strfry memfrob memmem rawmemchr strchrnul	\
@@ -47,7 +48,8 @@ strop-tests	:= memchr memcmp memcpy memmove mempcpy memset memccpy	\
 		   stpcpy stpncpy strcat strchr strcmp strcpy strcspn	\
 		   strlen strncmp strncpy strpbrk strrchr strspn memmem	\
 		   strstr strcasestr strnlen strcasecmp strncasecmp	\
-		   strncat rawmemchr strchrnul bcopy bzero memrchr
+		   strncat rawmemchr strchrnul bcopy bzero memrchr	\
+		   explicit_bzero
 tests		:= tester inl-tester noinl-tester testcopy test-ffs	\
 		   tst-strlen stratcliff tst-svc tst-inlcall		\
 		   bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap	\
diff --git a/string/Versions b/string/Versions
index 59bf35a..f9aba06 100644
--- a/string/Versions
+++ b/string/Versions
@@ -80,4 +80,7 @@ libc {
   GLIBC_2.6 {
     strerror_l;
   }
+  GLIBC_2.21 {
+    explicit_bzero;
+  }
 }
diff --git a/string/bits/string3.h b/string/bits/string3.h
index 801e7ac..65d9067 100644
--- a/string/bits/string3.h
+++ b/string/bits/string3.h
@@ -102,6 +102,13 @@ __NTH (bzero (void *__dest, size_t __len))
 {
   (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest));
 }
+
+__fortify_function void
+__NTH (explicit_bzero (void *__dest, size_t __len))
+{
+  (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest));
+  __asm__ __volatile__ ( "" : : "r"(__dest) : "memory" );
+}
 #endif
 
 __fortify_function char *
diff --git a/string/bzero.c b/string/bzero.c
index 9c220b9..9525de8 100644
--- a/string/bzero.c
+++ b/string/bzero.c
@@ -20,6 +20,7 @@
 #include <memcopy.h>
 
 #undef __bzero
+#undef __explicit_bzero
 
 /* Set N bytes of S to 0.  */
 void
@@ -80,3 +81,17 @@ __bzero (s, len)
     }
 }
 weak_alias (__bzero, bzero)
+
+
+void
+__explicit_bzero(s, len)
+    void *s;
+    size_t len;
+{
+  __bzero (s, len);
+
+  /* Add a barrier to prevent the compiler from optimizing the above bzero
+   * away. */
+  __asm__ __volatile__ ( "" : : "r"(s) : "memory" );
+}
+weak_alias (__explicit_bzero, explicit_bzero)
diff --git a/string/explicit_bzero.c b/string/explicit_bzero.c
new file mode 100644
index 0000000..7ddd190
--- /dev/null
+++ b/string/explicit_bzero.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 1991-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <memcopy.h>
+
+void
+__explicit_bzero(s, len)
+    void *s;
+    size_t len;
+{
+  __bzero (s, len);
+
+  /* Add a barrier to prevent the compiler from optimizing the above bzero
+   * away. */
+  __asm__ __volatile__ ( "" : : "r"(s) : "memory" );
+}
+weak_alias (__explicit_bzero, explicit_bzero)
diff --git a/string/string.h b/string/string.h
index c79debc..c6888c0 100644
--- a/string/string.h
+++ b/string/string.h
@@ -445,9 +445,10 @@ extern char *strerror_l (int __errnum, __locale_t __l) __THROW;
 #endif
 
 
-/* We define this function always since `bzero' is sometimes needed when
+/* We define these functions always since `bzero' is sometimes needed when
    the namespace rules does not allow this.  */
 extern void __bzero (void *__s, size_t __n) __THROW __nonnull ((1));
+extern void __explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1));
 
 #ifdef __USE_MISC
 /* Copy N bytes of SRC to DEST (like memmove, but args reversed).  */
@@ -457,6 +458,9 @@ extern void bcopy (const void *__src, void *__dest, size_t __n)
 /* Set N bytes of S to 0.  */
 extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1));
 
+/* Set N bytes of S to 0, and don't let the compiler eliminate this. */
+extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1));
+
 /* Compare N bytes of S1 and S2 (same as memcmp).  */
 extern int bcmp (const void *__s1, const void *__s2, size_t __n)
      __THROW __attribute_pure__ __nonnull ((1, 2));
diff --git a/string/strings.h b/string/strings.h
index 872a0b2..12c4f51 100644
--- a/string/strings.h
+++ b/string/strings.h
@@ -49,6 +49,9 @@ extern void bcopy (const void *__src, void *__dest, size_t __n) __THROW;
 /* Set N bytes of S to 0.  */
 extern void bzero (void *__s, size_t __n) __THROW;
 
+/* Set N bytes of S to 0, and don't let the compiler eliminate this. */
+extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1));
+
 /* Find the first occurrence of C in S (same as strchr).  */
 #  ifdef __CORRECT_ISO_CPP_STRINGS_H_PROTO
 extern "C++"
diff --git a/string/test-explicit_bzero.c b/string/test-explicit_bzero.c
new file mode 100644
index 0000000..7ed52b3
--- /dev/null
+++ b/string/test-explicit_bzero.c
@@ -0,0 +1,20 @@
+/* Test and measure bzero functions.
+   Copyright (C) 2012-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+#define TEST_EXPLICIT_BZERO
+#define TEST_BZERO
+#include "test-memset.c"
diff --git a/string/test-memset.c b/string/test-memset.c
index 2171b0d..a4820dc 100644
--- a/string/test-memset.c
+++ b/string/test-memset.c
@@ -18,7 +18,9 @@
    <http://www.gnu.org/licenses/>.  */
 
 #define TEST_MAIN
-#ifdef TEST_BZERO
+#ifdef TEST_EXPLICIT_BZERO
+# define TEST_NAME "explicit_bzero"
+#elif defined (TEST_BZERO)
 # define TEST_NAME "bzero"
 #else
 # define TEST_NAME "memset"
@@ -35,7 +37,11 @@ void builtin_bzero (char *, size_t);
 
 IMPL (simple_bzero, 0)
 IMPL (builtin_bzero, 0)
+#ifdef TEST_EXPLICIT_BZERO
+IMPL (explicit_bzero, 1)
+#else
 IMPL (bzero, 1)
+#endif
 
 void
 simple_bzero (char *s, size_t n)
