2004-10-15 Jakub Jelinek <jakub@redhat.com>
authordrepper <drepper>
Mon, 18 Oct 2004 04:17:08 +0000 (04:17 +0000)
committerdrepper <drepper>
Mon, 18 Oct 2004 04:17:08 +0000 (04:17 +0000)
* elf/dl-minimal.c (__chk_fail): New.  Add rtld_hidden_def.
* sysdeps/unix/sysv/linux/readonly-area.c: New file.
* sysdeps/i386/i686/memmove.S (__memmove_chk): Add checking
routine.
* sysdeps/i386/i686/memcpy.S (__memcpy_chk): Likewise.
* sysdeps/i386/i686/mempcpy.S (__mempcpy_chk): Likewise.
* sysdeps/i386/i686/memset.S (__memset_chk): Likewise.
* sysdeps/i386/i686/memmove-chk.S: New file.
* sysdeps/i386/i686/memcpy-chk.S: Likewise.
* sysdeps/i386/i686/mempcpy-chk.S: Likewise.
* sysdeps/i386/i686/memset-chk.S: Likewise.
* sysdeps/generic/strcat-chk.c (__strcat_chk): Don't __chk_fail
if exactly fitting into buffer.
* sysdeps/generic/strncat-chk.c (__strncat_chk): Likewise.
* sysdeps/generic/readonly-area.c: New file.
* sysdeps/generic/strncpy-chk.c (__strncpy_chk): Only test
destlen once.
* sysdeps/x86_64/memset.S (__memset_chk): Add checking routine.
* sysdeps/x86_64/memcpy.S (__memcpy_chk): Likewise.
* sysdeps/x86_64/mempcpy.S (__memcpy_chk): Define to __mempcpy_chk.
* sysdeps/x86_64/memcpy-chk.S: New file.
* sysdeps/x86_64/mempcpy-chk.S: Likewise.
* sysdeps/x86_64/memset-chk.S: Likewise.
* sysdeps/x86_64/strcpy-chk.S: Likewise.
* sysdeps/x86_64/stpcpy-chk.S: Likewise.
* argp/argp-xinl.c (__OPTIMIZE__): Define to 1 instead of nothing.
* argp/argp-fs-xinl.c (__OPTIMIZE__): Likewise.
* debug/tst-chk1.c: New test.
* debug/tst-chk2.c: Likewise.
* debug/tst-chk3.c: Likewise.
* debug/test-strcpy_chk.c: Likewise.
* debug/test-stpcpy_chk.c: Likewise.
* debug/vsprintf_chk.c (__vsprintf_chk): If flags > 0, request
_IO_FLAGS2_CHECK_PERCENT_N.  Add libc_hidden_def.
* debug/Makefile (routines): Add printf_chk, fprintf_chk, vprintf_chk,
vfprintf_chk, gets_chk and readonly-area.
(CFLAGS-*_chk.c): Set.
(tests): Add tst-chk1, tst-chk2, tst-chk3, test-strcpy_chk and
test-stpcpy_chk.
* debug/vprintf_chk.c: New file.
* debug/printf_chk.c: Likewise.
* debug/vfprintf_chk.c: Likewise.
* debug/fprintf_chk.c: Likewise.
* debug/gets_chk.c: Likewise.
* debug/chk_fail.c (__chk_fail): Add libc_hidden_def.
* debug/snprintf_chk.c (__snprintf_chk): Fix order of arguments
passed to __vsnprintf_chk.
* debug/Versions (libc): Export __printf_chk, __fprintf_chk,
__vprintf_chk, __vfprintf_chk and __gets_chk @GLIBC_2.3.4.
* debug/vsnprintf_chk.c (__vsnprintf_chk): Don't call
__vsnprintf, instead create a temporary file with
_IO_strn_jumps jumptable.  If flags > 0, request
_IO_FLAGS2_CHECK_PERCENT_N.  Add libc_hidden_def.
* libio/Makefile (headers): Add bits/stdio2.h.
* libio/stdio.h: Include <bits/stdio2.h> if __USE_FORTIFY_LEVEL.
(sprintf, snprintf, vsprintf, vsnprintf): Remove defines.
* libio/strfile.h (_IO_strnfile): New type.
(_IO_strn_jumps): New extern.
* libio/vsnprintf.c (_IO_strnfile): Remove.
(_IO_strn_jumps): Remove static.
* libio/bits/stdio2.h: New file.
* libio/vswprintf.c (_IO_strnfile): Rename type to...
(_IO_wstrnfile): ...this.  Adjust all uses.
* libio/libio.h (_IO_FLAGS2_CHECK_PERCENT_N): Define.
* stdio-common/vfprintf.c (STR_LEN): Define.
(vfprintf): Add readonly_format variable.
Handle _IO_FLAGS2_CHECK_PERCENT_N.
(buffered_vfprintf): Copy _flags2.
* include/stdio.h (__sprintf_chk, __snprintf_chk, __vsprintf_chk,
__vsnprintf_chk, __printf_chk, __fprintf_chk, __vprintf_chk,
__vfprintf_chk): New prototypes.
(__vsprintf_chk, __vsnprintf_chk): Add libc_hidden_proto.
* include/string.h (__memcpy_chk, __memmove_chk, __mempcpy_chk,
__memset_chk, __strcpy_chk, __stpcpy_chk, __strncpy_chk, __strcat_chk,
__strncat_chk): New prototypes.
* include/bits/string3.h: New file.
* include/sys/cdefs.h (__chk_fail): Add libc_hidden_proto
and rtld_hidden_proto.
* string/Makefile (headers): Add bits/string3.h.
* string/bits/string3.h (bcopy, bzero): New defines.
(memset, memcpy, memmove, strcpy, strncpy, strcat, strncat): Change
macros so that inlines are used only if unknown destination size
or side-effects in destination argument.
(mempcpy, stpcpy): Likewise.  Protect with #ifdef __USE_GNU.

2004-09-16  Ulrich Drepper  <drepper@redhat.com>

* debug/Makefile (routines): Add *_chk.
* debug/Versions (libc): Export __chk_fail, __memcpy_chk,
__memmove_chk, __mempcpy_chk, __memset_chk, __stpcpy_chk,
__strcat_chk, __strcpy_chk, __strncat_chk, __strncpy_chk,
__sprintf_chk, __vsprintf_chk, __snprintf_chk, __vsnprintf_chk
@GLIBC_2.3.4.
* debug/chk_fail.c: New file.
* debug/snprintf_chk.c: Likewise.
* debug/sprintf_chk.c: Likewise.
* debug/vsnprintf_chk.c: Likewise.
* debug/vsprintf_chk.c: Likewise.
* include/features.h (_FORTIFY_SOURCE): Document, handle.
(__USE_FORTIFY_LEVEL): Define.
(__GNUC_PREREQ): Move to earlier location.
* include/sys/cdefs.h (__chk_fail): New prototype.
* libio/bits/stdio.h (sprintf, vsprintf, snprintf, vsnprintf):
Define if __USE_FORTIFY_LEVEL.
* misc/sys/cdefs.h (__bos, __bos0): Define.
* string/string.h: Include <bits/string3.h> if __USE_FORTIFY_LEVEL.
* bits/string/string3.h: New header.
* sysdeps/generic/memcpy_chk.c: New file.
* sysdeps/generic/memmove_chk.c: Likewise.
* sysdeps/generic/mempcpy_chk.c: Likewise.
* sysdeps/generic/memset_chk.c: Likewise.
* sysdeps/generic/stpcpy_chk.c: Likewise.
* sysdeps/generic/strcat_chk.c: Likewise.
* sysdeps/generic/strcpy_chk.c: Likewise.
* sysdeps/generic/strncat_chk.c: Likewise.
* sysdeps/generic/strncpy_chk.c: Likewise.

65 files changed:
ChangeLog
argp/argp-fs-xinl.c
argp/argp-xinl.c
debug/Makefile
debug/Versions
debug/chk_fail.c [new file with mode: 0644]
debug/fprintf_chk.c [new file with mode: 0644]
debug/gets_chk.c [new file with mode: 0644]
debug/printf_chk.c [new file with mode: 0644]
debug/snprintf_chk.c [new file with mode: 0644]
debug/sprintf_chk.c [new file with mode: 0644]
debug/test-stpcpy_chk.c [new file with mode: 0644]
debug/test-strcpy_chk.c [new file with mode: 0644]
debug/tst-chk1.c [new file with mode: 0644]
debug/tst-chk2.c [new file with mode: 0644]
debug/tst-chk3.c [new file with mode: 0644]
debug/vfprintf_chk.c [new file with mode: 0644]
debug/vprintf_chk.c [new file with mode: 0644]
debug/vsnprintf_chk.c [new file with mode: 0644]
debug/vsprintf_chk.c [new file with mode: 0644]
elf/dl-minimal.c
include/bits/string3.h [new file with mode: 0644]
include/features.h
include/stdio.h
include/string.h
include/sys/cdefs.h
libio/Makefile
libio/bits/stdio2.h [new file with mode: 0644]
libio/libio.h
libio/stdio.h
libio/strfile.h
libio/vsnprintf.c
libio/vswprintf.c
misc/sys/cdefs.h
stdio-common/vfprintf.c
string/Makefile
string/bits/string3.h [new file with mode: 0644]
string/string.h
sysdeps/generic/memcpy_chk.c [new file with mode: 0644]
sysdeps/generic/memmove_chk.c [new file with mode: 0644]
sysdeps/generic/mempcpy_chk.c [new file with mode: 0644]
sysdeps/generic/memset_chk.c [new file with mode: 0644]
sysdeps/generic/readonly-area.c [new file with mode: 0644]
sysdeps/generic/stpcpy_chk.c [new file with mode: 0644]
sysdeps/generic/strcat_chk.c [new file with mode: 0644]
sysdeps/generic/strcpy_chk.c [new file with mode: 0644]
sysdeps/generic/strncat_chk.c [new file with mode: 0644]
sysdeps/generic/strncpy_chk.c [new file with mode: 0644]
sysdeps/i386/i686/memcpy.S
sysdeps/i386/i686/memcpy_chk.S [new file with mode: 0644]
sysdeps/i386/i686/memmove.S
sysdeps/i386/i686/memmove_chk.S [new file with mode: 0644]
sysdeps/i386/i686/mempcpy.S
sysdeps/i386/i686/mempcpy_chk.S [new file with mode: 0644]
sysdeps/i386/i686/memset.S
sysdeps/i386/i686/memset_chk.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/readonly-area.c [new file with mode: 0644]
sysdeps/x86_64/memcpy.S
sysdeps/x86_64/memcpy_chk.S [new file with mode: 0644]
sysdeps/x86_64/mempcpy.S
sysdeps/x86_64/mempcpy_chk.S [new file with mode: 0644]
sysdeps/x86_64/memset.S
sysdeps/x86_64/memset_chk.S [new file with mode: 0644]
sysdeps/x86_64/stpcpy_chk.S [new file with mode: 0644]
sysdeps/x86_64/strcpy_chk.S [new file with mode: 0644]

index d610e69..4b52d54 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,122 @@
+2004-10-15  Jakub Jelinek  <jakub@redhat.com>
+
+       * elf/dl-minimal.c (__chk_fail): New.  Add rtld_hidden_def.
+       * sysdeps/unix/sysv/linux/readonly-area.c: New file.
+       * sysdeps/i386/i686/memmove.S (__memmove_chk): Add checking
+       routine.
+       * sysdeps/i386/i686/memcpy.S (__memcpy_chk): Likewise.
+       * sysdeps/i386/i686/mempcpy.S (__mempcpy_chk): Likewise.
+       * sysdeps/i386/i686/memset.S (__memset_chk): Likewise.
+       * sysdeps/i386/i686/memmove-chk.S: New file.
+       * sysdeps/i386/i686/memcpy-chk.S: Likewise.
+       * sysdeps/i386/i686/mempcpy-chk.S: Likewise.
+       * sysdeps/i386/i686/memset-chk.S: Likewise.
+       * sysdeps/generic/strcat-chk.c (__strcat_chk): Don't __chk_fail
+       if exactly fitting into buffer.
+       * sysdeps/generic/strncat-chk.c (__strncat_chk): Likewise.
+       * sysdeps/generic/readonly-area.c: New file.
+       * sysdeps/generic/strncpy-chk.c (__strncpy_chk): Only test
+       destlen once.
+       * sysdeps/x86_64/memset.S (__memset_chk): Add checking routine.
+       * sysdeps/x86_64/memcpy.S (__memcpy_chk): Likewise.
+       * sysdeps/x86_64/mempcpy.S (__memcpy_chk): Define to __mempcpy_chk.
+       * sysdeps/x86_64/memcpy-chk.S: New file.
+       * sysdeps/x86_64/mempcpy-chk.S: Likewise.
+       * sysdeps/x86_64/memset-chk.S: Likewise.
+       * sysdeps/x86_64/strcpy-chk.S: Likewise.
+       * sysdeps/x86_64/stpcpy-chk.S: Likewise.
+       * argp/argp-xinl.c (__OPTIMIZE__): Define to 1 instead of nothing.
+       * argp/argp-fs-xinl.c (__OPTIMIZE__): Likewise.
+       * debug/tst-chk1.c: New test.
+       * debug/tst-chk2.c: Likewise.
+       * debug/tst-chk3.c: Likewise.
+       * debug/test-strcpy_chk.c: Likewise.
+       * debug/test-stpcpy_chk.c: Likewise.
+       * debug/vsprintf_chk.c (__vsprintf_chk): If flags > 0, request
+       _IO_FLAGS2_CHECK_PERCENT_N.  Add libc_hidden_def.
+       * debug/Makefile (routines): Add printf_chk, fprintf_chk, vprintf_chk,
+       vfprintf_chk, gets_chk and readonly-area.
+       (CFLAGS-*_chk.c): Set.
+       (tests): Add tst-chk1, tst-chk2, tst-chk3, test-strcpy_chk and
+       test-stpcpy_chk.
+       * debug/vprintf_chk.c: New file.
+       * debug/printf_chk.c: Likewise.
+       * debug/vfprintf_chk.c: Likewise.
+       * debug/fprintf_chk.c: Likewise.
+       * debug/gets_chk.c: Likewise.
+       * debug/chk_fail.c (__chk_fail): Add libc_hidden_def.
+       * debug/snprintf_chk.c (__snprintf_chk): Fix order of arguments
+       passed to __vsnprintf_chk.
+       * debug/Versions (libc): Export __printf_chk, __fprintf_chk,
+       __vprintf_chk, __vfprintf_chk and __gets_chk @GLIBC_2.3.4.
+       * debug/vsnprintf_chk.c (__vsnprintf_chk): Don't call
+       __vsnprintf, instead create a temporary file with
+       _IO_strn_jumps jumptable.  If flags > 0, request
+       _IO_FLAGS2_CHECK_PERCENT_N.  Add libc_hidden_def.
+       * libio/Makefile (headers): Add bits/stdio2.h.
+       * libio/stdio.h: Include <bits/stdio2.h> if __USE_FORTIFY_LEVEL.
+       (sprintf, snprintf, vsprintf, vsnprintf): Remove defines.
+       * libio/strfile.h (_IO_strnfile): New type.
+       (_IO_strn_jumps): New extern.
+       * libio/vsnprintf.c (_IO_strnfile): Remove.
+       (_IO_strn_jumps): Remove static.
+       * libio/bits/stdio2.h: New file.
+       * libio/vswprintf.c (_IO_strnfile): Rename type to...
+       (_IO_wstrnfile): ...this.  Adjust all uses.
+       * libio/libio.h (_IO_FLAGS2_CHECK_PERCENT_N): Define.
+       * stdio-common/vfprintf.c (STR_LEN): Define.
+       (vfprintf): Add readonly_format variable.
+       Handle _IO_FLAGS2_CHECK_PERCENT_N.
+       (buffered_vfprintf): Copy _flags2.
+       * include/stdio.h (__sprintf_chk, __snprintf_chk, __vsprintf_chk,
+       __vsnprintf_chk, __printf_chk, __fprintf_chk, __vprintf_chk,
+       __vfprintf_chk): New prototypes.
+       (__vsprintf_chk, __vsnprintf_chk): Add libc_hidden_proto.
+       * include/string.h (__memcpy_chk, __memmove_chk, __mempcpy_chk,
+       __memset_chk, __strcpy_chk, __stpcpy_chk, __strncpy_chk, __strcat_chk,
+       __strncat_chk): New prototypes.
+       * include/bits/string3.h: New file.
+       * include/sys/cdefs.h (__chk_fail): Add libc_hidden_proto
+       and rtld_hidden_proto.
+       * string/Makefile (headers): Add bits/string3.h.
+       * string/bits/string3.h (bcopy, bzero): New defines.
+       (memset, memcpy, memmove, strcpy, strncpy, strcat, strncat): Change
+       macros so that inlines are used only if unknown destination size
+       or side-effects in destination argument.
+       (mempcpy, stpcpy): Likewise.  Protect with #ifdef __USE_GNU.
+
+2004-09-16  Ulrich Drepper  <drepper@redhat.com>
+
+       * debug/Makefile (routines): Add *_chk.
+       * debug/Versions (libc): Export __chk_fail, __memcpy_chk,
+       __memmove_chk, __mempcpy_chk, __memset_chk, __stpcpy_chk,
+       __strcat_chk, __strcpy_chk, __strncat_chk, __strncpy_chk,
+       __sprintf_chk, __vsprintf_chk, __snprintf_chk, __vsnprintf_chk
+       @GLIBC_2.3.4.
+       * debug/chk_fail.c: New file.
+       * debug/snprintf_chk.c: Likewise.
+       * debug/sprintf_chk.c: Likewise.
+       * debug/vsnprintf_chk.c: Likewise.
+       * debug/vsprintf_chk.c: Likewise.
+       * include/features.h (_FORTIFY_SOURCE): Document, handle.
+       (__USE_FORTIFY_LEVEL): Define.
+       (__GNUC_PREREQ): Move to earlier location.
+       * include/sys/cdefs.h (__chk_fail): New prototype.
+       * libio/bits/stdio.h (sprintf, vsprintf, snprintf, vsnprintf):
+       Define if __USE_FORTIFY_LEVEL.
+       * misc/sys/cdefs.h (__bos, __bos0): Define.
+       * string/string.h: Include <bits/string3.h> if __USE_FORTIFY_LEVEL.
+       * bits/string/string3.h: New header.
+       * sysdeps/generic/memcpy_chk.c: New file.
+       * sysdeps/generic/memmove_chk.c: Likewise.
+       * sysdeps/generic/mempcpy_chk.c: Likewise.
+       * sysdeps/generic/memset_chk.c: Likewise.
+       * sysdeps/generic/stpcpy_chk.c: Likewise.
+       * sysdeps/generic/strcat_chk.c: Likewise.
+       * sysdeps/generic/strcpy_chk.c: Likewise.
+       * sysdeps/generic/strncat_chk.c: Likewise.
+       * sysdeps/generic/strncpy_chk.c: Likewise.
+
 2004-10-17  Roland McGrath  <roland@frob.com>
 
        * manual/memory.texi (Page Lock Functions): Typo fix.
index 21f9bd9..3cf1f98 100644 (file)
@@ -1,5 +1,5 @@
 /* Real definitions for extern inline functions in argp-fmtstream.h
-   Copyright (C) 1997, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1997, 2003, 2004 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Miles Bader <miles@gnu.ai.mit.edu>.
 
@@ -24,7 +24,7 @@
 
 #define ARGP_FS_EI
 #undef __OPTIMIZE__
-#define __OPTIMIZE__
+#define __OPTIMIZE__ 1
 #include "argp-fmtstream.h"
 
 #if 0
index 2431093..7317758 100644 (file)
@@ -1,5 +1,5 @@
 /* Real definitions for extern inline functions in argp.h
-   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998, 2004 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Miles Bader <miles@gnu.ai.mit.edu>.
 
@@ -31,7 +31,7 @@
 #endif
 #define ARGP_EI
 #undef __OPTIMIZE__
-#define __OPTIMIZE__
+#define __OPTIMIZE__ 1
 #include "argp.h"
 
 /* Add weak aliases.  */
index aba9892..fed60d7 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+# Copyright (C) 1998, 1999, 2000, 2001, 2004 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
@@ -24,11 +24,26 @@ subdir      := debug
 headers        := execinfo.h
 distribute = sigcontextinfo.h register-dump.h frame.h
 
-routines := backtrace backtracesyms backtracesymsfd noophooks
+routines := backtrace backtracesyms backtracesymsfd noophooks \
+           memcpy_chk memmove_chk mempcpy_chk memset_chk stpcpy_chk \
+           strcat_chk strcpy_chk strncat_chk strncpy_chk \
+           sprintf_chk vsprintf_chk snprintf_chk vsnprintf_chk \
+           printf_chk fprintf_chk vprintf_chk vfprintf_chk \
+           gets_chk chk_fail readonly-area
 
 CFLAGS-backtrace.c = -fno-omit-frame-pointer
-
-tests = backtrace-tst
+CFLAGS-sprintf_chk.c = -D_IO_MTSAFE_IO
+CFLAGS-snprintf_chk.c = -D_IO_MTSAFE_IO
+CFLAGS-vsprintf_chk.c = -D_IO_MTSAFE_IO
+CFLAGS-vsnprintf_chk.c = -D_IO_MTSAFE_IO
+CFLAGS-printf_chk.c = -D_IO_MTSAFE_IO $(exceptions)
+CFLAGS-fprintf_chk.c = -D_IO_MTSAFE_IO $(exceptions)
+CFLAGS-vprintf_chk.c = -D_IO_MTSAFE_IO $(exceptions) 
+CFLAGS-vfprintf_chk.c = -D_IO_MTSAFE_IO $(exceptions)
+CFLAGS-gets_chk.c = -D_IO_MTSAFE_IO $(exceptions)
+
+tests = backtrace-tst tst-chk1 tst-chk2 tst-chk3 \
+       test-strcpy_chk test-stpcpy_chk
 
 extra-libs = libSegFault libpcprofile
 extra-libs-others = $(extra-libs)
index c2b6396..07d6fbb 100644 (file)
@@ -10,4 +10,12 @@ libc {
     # These are to support some gcc features.
     __cyg_profile_func_enter; __cyg_profile_func_exit;
   }
+  GLIBC_2.3.4 {
+    __chk_fail;
+    __memcpy_chk; __memmove_chk; __mempcpy_chk; __memset_chk; __stpcpy_chk;
+    __strcat_chk; __strcpy_chk; __strncat_chk; __strncpy_chk;
+    __sprintf_chk; __vsprintf_chk; __snprintf_chk; __vsnprintf_chk;
+    __printf_chk; __fprintf_chk; __vprintf_chk; __vfprintf_chk;
+    __gets_chk;
+  }
 }
diff --git a/debug/chk_fail.c b/debug/chk_fail.c
new file mode 100644 (file)
index 0000000..48848fb
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <abort-instr.h>
+
+
+void
+__attribute__ ((noreturn))
+__chk_fail (void)
+{
+  while (1)
+    {
+      /* This will leave a nice backtrace.  */
+      abort ();
+#ifdef ABORT_INSTRUCTION
+      ABORT_INSTRUCTION;
+#endif
+      _exit (127);
+    }
+}
+libc_hidden_def (__chk_fail)
diff --git a/debug/fprintf_chk.c b/debug/fprintf_chk.c
new file mode 100644 (file)
index 0000000..77508b9
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2001, 2004
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "../libio/libioP.h"
+
+
+/* Write formatted output to FP from the format string FORMAT.  */
+int
+__fprintf_chk (FILE *fp, int flag, const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  _IO_acquire_lock (fp);
+  if (flag > 0)
+    fp->_flags2 |= _IO_FLAGS2_CHECK_PERCENT_N;
+
+  va_start (ap, format);
+  done = vfprintf (fp, format, ap);
+  va_end (ap);
+
+  if (flag > 0)
+    fp->_flags2 &= ~_IO_FLAGS2_CHECK_PERCENT_N;
+  _IO_release_lock (fp);
+
+  return done;
+}
diff --git a/debug/gets_chk.c b/debug/gets_chk.c
new file mode 100644 (file)
index 0000000..3715a39
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright (C) 1993, 1996, 1997, 1998, 2002, 2003, 2004
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.
+
+   As a special exception, if you link the code in this file with
+   files compiled with a GNU compiler to produce an executable,
+   that does not cause the resulting executable to be covered by
+   the GNU Lesser General Public License.  This exception does not
+   however invalidate any other reasons why the executable file
+   might be covered by the GNU Lesser General Public License.
+   This exception applies to code released by its copyright holders
+   in files containing the exception.  */
+
+#include "../libio/libioP.h"
+#include <limits.h>
+
+char *
+__gets_chk (char *buf, size_t size)
+{
+  _IO_size_t count;
+  int ch;
+  char *retval;
+
+  if (size == 0)
+    __chk_fail ();
+
+  _IO_acquire_lock (_IO_stdin);
+  ch = _IO_getc_unlocked (_IO_stdin);
+  if (ch == EOF)
+    {
+      retval = NULL;
+      goto unlock_return;
+    }
+  if (ch == '\n')
+    count = 0;
+  else
+    {
+      /* This is very tricky since a file descriptor may be in the
+        non-blocking mode. The error flag doesn't mean much in this
+        case. We return an error only when there is a new error. */
+      int old_error = _IO_stdin->_IO_file_flags & _IO_ERR_SEEN;
+      _IO_stdin->_IO_file_flags &= ~_IO_ERR_SEEN;
+      buf[0] = (char) ch;
+      count = INTUSE(_IO_getline) (_IO_stdin, buf + 1, size - 1, '\n', 0) + 1;
+      if (_IO_stdin->_IO_file_flags & _IO_ERR_SEEN)
+       {
+         retval = NULL;
+         goto unlock_return;
+       }
+      else
+       _IO_stdin->_IO_file_flags |= old_error;
+    }
+  if (count >= size)
+    __chk_fail ();
+  buf[count] = 0;
+  retval = buf;
+unlock_return:
+  _IO_release_lock (_IO_stdin);
+  return retval;
+}
+
+link_warning (__gets_chk, "the `gets' function is dangerous and should not be used.")
diff --git a/debug/printf_chk.c b/debug/printf_chk.c
new file mode 100644 (file)
index 0000000..d2b3873
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2001, 2004
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "../libio/libioP.h"
+
+
+/* Write formatted output to stdout from the format string FORMAT.  */
+int
+__printf_chk (int flag, const char *format, ...)
+{
+  va_list ap;
+  int done;
+
+  _IO_acquire_lock (stdout);
+  if (flag > 0)
+    stdout->_flags2 |= _IO_FLAGS2_CHECK_PERCENT_N;
+
+  va_start (ap, format);
+  done = vfprintf (stdout, format, ap);
+  va_end (ap);
+
+  if (flag > 0)
+    stdout->_flags2 &= ~_IO_FLAGS2_CHECK_PERCENT_N;
+  _IO_release_lock (stdout);
+
+  return done;
+}
diff --git a/debug/snprintf_chk.c b/debug/snprintf_chk.c
new file mode 100644 (file)
index 0000000..5a77afe
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 1991, 1995, 1997, 1998, 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+
+/* Write formatted output into S, according to the format
+   string FORMAT, writing no more than MAXLEN characters.  */
+/* VARARGS5 */
+int
+__snprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
+               const char *format, ...)
+{
+  va_list arg;
+  int done;
+
+  va_start (arg, format);
+  done = __vsnprintf_chk (s, maxlen, flags, slen, format, arg);
+  va_end (arg);
+
+  return done;
+}
diff --git a/debug/sprintf_chk.c b/debug/sprintf_chk.c
new file mode 100644 (file)
index 0000000..d141633
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 1991,1995,1997,1998,2002,2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+/* Write formatted output into S, according to the format string FORMAT.  */
+/* VARARGS4 */
+int
+__sprintf_chk (char *s, int flags, size_t slen, const char *format, ...)
+{
+  va_list arg;
+  int done;
+
+  va_start (arg, format);
+  done = __vsprintf_chk (s, flags, slen, format, arg);
+  va_end (arg);
+
+  return done;
+}
diff --git a/debug/test-stpcpy_chk.c b/debug/test-stpcpy_chk.c
new file mode 100644 (file)
index 0000000..d717ca7
--- /dev/null
@@ -0,0 +1,46 @@
+/* Test and measure stpcpy checking functions.
+   Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Written by Jakub Jelinek <jakub@redhat.com>, 1999.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define STRCPY_RESULT(dst, len) ((dst) + (len))
+#define TEST_MAIN
+#include "../string/test-string.h"
+
+extern void __attribute__ ((noreturn)) __chk_fail (void);
+char *simple_stpcpy_chk (char *, const char *, size_t);
+extern char *normal_stpcpy (char *, const char *, size_t)
+  __asm ("stpcpy");
+extern char *__stpcpy_chk (char *, const char *, size_t);
+
+IMPL (simple_stpcpy_chk, 0)
+IMPL (normal_stpcpy, 1)
+IMPL (__stpcpy_chk, 2)
+
+char *
+simple_stpcpy_chk (char *dst, const char *src, size_t len)
+{
+  if (! len)
+    __chk_fail ();
+  while ((*dst++ = *src++) != '\0')
+    if (--len == 0)
+      __chk_fail ();
+  return dst - 1;
+}
+
+#include "test-strcpy_chk.c"
diff --git a/debug/test-strcpy_chk.c b/debug/test-strcpy_chk.c
new file mode 100644 (file)
index 0000000..4c61f4f
--- /dev/null
@@ -0,0 +1,370 @@
+/* Test and measure __strcpy_chk functions.
+   Copyright (C) 1999, 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Written by Jakub Jelinek <jakub@redhat.com>, 1999.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef STRCPY_RESULT
+# define STRCPY_RESULT(dst, len) dst
+# define TEST_MAIN
+# include "../string/test-string.h"
+
+extern void __attribute__ ((noreturn)) __chk_fail (void);
+char *simple_strcpy_chk (char *, const char *, size_t);
+extern char *normal_strcpy (char *, const char *, size_t)
+  __asm ("strcpy");
+extern char *__strcpy_chk (char *, const char *, size_t);
+
+IMPL (simple_strcpy_chk, 0)
+IMPL (normal_strcpy, 1)
+IMPL (__strcpy_chk, 2)
+
+char *
+simple_strcpy_chk (char *dst, const char *src, size_t len)
+{
+  char *ret = dst;
+  if (! len)
+    __chk_fail ();
+  while ((*dst++ = *src++) != '\0')
+    if (--len == 0)
+      __chk_fail ();
+  return ret;
+}
+#endif
+
+#include <setjmp.h>
+#include <signal.h>
+
+volatile int chk_fail_ok;
+jmp_buf chk_fail_buf;
+
+static void
+handler (int sig)
+{
+  if (chk_fail_ok)
+    {
+      chk_fail_ok = 0;
+      longjmp (chk_fail_buf, 1);
+    }
+  else
+    _exit (127);
+}
+
+typedef char *(*proto_t) (char *, const char *, size_t);
+
+static void
+do_one_test (impl_t *impl, char *dst, const char *src,
+            size_t len, size_t dlen)
+{
+  char *res;
+  if (dlen <= len)
+    {
+      if (impl->test == 1)
+       return;
+
+      chk_fail_ok = 1;
+      if (setjmp (chk_fail_buf) == 0)
+       {
+         res = CALL (impl, dst, src, dlen);
+         error (0, 0, "Function %s (%zd; %zd) did not __chk_fail",
+                impl->name, len, dlen);
+         chk_fail_ok = 0;
+         ret = 1;
+       }
+      return;
+    }
+  else
+    res = CALL (impl, dst, src, dlen);
+
+  if (res != STRCPY_RESULT (dst, len))
+    {
+      error (0, 0, "Wrong result in function %s %p %p", impl->name,
+            res, STRCPY_RESULT (dst, len));
+      ret = 1;
+      return;
+    }
+
+  if (strcmp (dst, src) != 0)
+    {
+      error (0, 0, "Wrong result in function %s dst \"%s\" src \"%s\"",
+            impl->name, dst, src);
+      ret = 1;
+      return;
+    }
+
+  if (HP_TIMING_AVAIL)
+    {
+      hp_timing_t start __attribute ((unused));
+      hp_timing_t stop __attribute ((unused));;
+      hp_timing_t best_time = ~ (hp_timing_t) 0;
+      size_t i;
+
+      for (i = 0; i < 32; ++i)
+       {
+         HP_TIMING_NOW (start);
+         CALL (impl, dst, src, dlen);
+         HP_TIMING_NOW (stop);
+         HP_TIMING_BEST (best_time, start, stop);
+       }
+
+      printf ("\t%zd", (size_t) best_time);
+    }
+}
+
+static void
+do_test (size_t align1, size_t align2, size_t len, size_t dlen, int max_char)
+{
+  size_t i;
+  char *s1, *s2;
+
+  align1 &= 7;
+  if (align1 + len >= page_size)
+    return;
+
+  align2 &= 7;
+  if (align2 + len >= page_size)
+    return;
+
+  s1 = buf1 + align1;
+  s2 = buf2 + align2;
+
+  for (i = 0; i < len; i++)
+    s1[i] = 32 + 23 * i % (max_char - 32);
+  s1[len] = 0;
+
+  if (HP_TIMING_AVAIL && dlen > len)
+    printf ("Length %4zd, alignment %2zd/%2zd:", len, align1, align2);
+
+  FOR_EACH_IMPL (impl, 0)
+    do_one_test (impl, s2, s1, len, dlen);
+
+  if (HP_TIMING_AVAIL && dlen > len)
+    putchar ('\n');
+}
+
+static void
+do_random_tests (void)
+{
+  size_t i, j, n, align1, align2, len, dlen;
+  unsigned char *p1 = buf1 + page_size - 512;
+  unsigned char *p2 = buf2 + page_size - 512;
+  unsigned char *res;
+
+  for (n = 0; n < ITERATIONS; n++)
+    {
+      align1 = random () & 31;
+      if (random () & 1)
+       align2 = random () & 31;
+      else
+       align2 = align1 + (random () & 24);
+      len = random () & 511;
+      j = align1;
+      if (align2 > j)
+       j = align2;
+      if (len + j >= 511)
+       len = 510 - j - (random () & 7);
+      j = len + align1 + 64;
+      if (j > 512)
+       j = 512;
+      for (i = 0; i < j; i++)
+       {
+         if (i == len + align1)
+           p1[i] = 0;
+         else
+           {
+             p1[i] = random () & 255;
+             if (i >= align1 && i < len + align1 && !p1[i])
+               p1[i] = (random () & 127) + 3;
+           }
+       }
+
+      switch (random () & 7)
+       {
+       case 0:
+         dlen = len - (random () & 31);
+         if (dlen > len)
+           dlen = len;
+         break;
+       case 1:
+         dlen = (size_t) -1;
+         break;
+       case 2:
+         dlen = len + 1 + (random () & 65535);
+         break;
+       case 3:
+         dlen = len + 1 + (random () & 255);
+         break;
+       case 4:
+         dlen = len + 1 + (random () & 31);
+         break;
+       case 5:
+         dlen = len + 1 + (random () & 7);
+         break;
+       case 6:
+         dlen = len + 1 + (random () & 3);
+         break;
+       default:
+         dlen = len + 1;
+         break;
+       }
+
+      FOR_EACH_IMPL (impl, 1)
+       {
+         if (dlen <= len)
+           {
+             if (impl->test != 1)
+               {
+                 chk_fail_ok = 1;
+                 if (setjmp (chk_fail_buf) == 0)
+                   {
+                     res = CALL (impl, p2 + align2, p1 + align1, dlen);
+                     error (0, 0, "Iteration %zd - did not __chk_fail", n);
+                     chk_fail_ok = 0;
+                     ret = 1;
+                   }
+               }
+             continue;
+           }
+         memset (p2 - 64, '\1', 512 + 64);
+         res = CALL (impl, p2 + align2, p1 + align1, dlen);
+         if (res != STRCPY_RESULT (p2 + align2, len))
+           {
+             error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd) %p != %p",
+                    n, impl->name, align1, align2, len, res,
+                    STRCPY_RESULT (p2 + align2, len));
+             ret = 1;
+           }
+         for (j = 0; j < align2 + 64; ++j)
+           {
+             if (p2[j - 64] != '\1')
+               {
+                 error (0, 0, "Iteration %zd - garbage before, %s (%zd, %zd, %zd)",
+                        n, impl->name, align1, align2, len);
+                 ret = 1;
+                 break;
+               }
+           }
+         for (j = align2 + len + 1; j < 512; ++j)
+           {
+             if (p2[j] != '\1')
+               {
+                 error (0, 0, "Iteration %zd - garbage after, %s (%zd, %zd, %zd)",
+                        n, impl->name, align1, align2, len);
+                 ret = 1;
+                 break;
+               }
+           }
+         if (memcmp (p1 + align1, p2 + align2, len + 1))
+           {
+             error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd)",
+                    n, impl->name, align1, align2, len);
+             ret = 1;
+           }
+       }
+    }
+}
+
+int
+test_main (void)
+{
+  size_t i;
+
+  struct sigaction sa;
+  sa.sa_handler = handler;
+  sa.sa_flags = 0;
+  sigemptyset (&sa.sa_mask);
+
+  sigaction (SIGABRT, &sa, NULL);
+
+  test_init ();
+
+  printf ("%23s", "");
+  FOR_EACH_IMPL (impl, 0)
+    printf ("\t%s", impl->name);
+  putchar ('\n');
+
+  for (i = 0; i < 16; ++i)
+    {
+      do_test (0, 0, i, i + 1, 127);
+      do_test (0, 0, i, i + 1, 255);
+      do_test (0, i, i, i + 1, 127);
+      do_test (i, 0, i, i + 1, 255);
+    }
+
+  for (i = 1; i < 8; ++i)
+    {
+      do_test (0, 0, 8 << i, (8 << i) + 1, 127);
+      do_test (8 - i, 2 * i, (8 << i), (8 << i) + 1, 127);
+    }
+
+  for (i = 1; i < 8; ++i)
+    {
+      do_test (i, 2 * i, (8 << i), (8 << i) + 1, 127);
+      do_test (2 * i, i, (8 << i), (8 << i) + 1, 255);
+      do_test (i, i, (8 << i), (8 << i) + 1, 127);
+      do_test (i, i, (8 << i), (8 << i) + 1, 255);
+    }
+
+  for (i = 0; i < 16; ++i)
+    {
+      do_test (0, 0, i, i + 256, 127);
+      do_test (0, 0, i, i + 256, 255);
+      do_test (0, i, i, i + 256, 127);
+      do_test (i, 0, i, i + 256, 255);
+    }
+
+  for (i = 1; i < 8; ++i)
+    {
+      do_test (0, 0, 8 << i, (8 << i) + 256, 127);
+      do_test (8 - i, 2 * i, (8 << i), (8 << i) + 256, 127);
+    }
+
+  for (i = 1; i < 8; ++i)
+    {
+      do_test (i, 2 * i, (8 << i), (8 << i) + 256, 127);
+      do_test (2 * i, i, (8 << i), (8 << i) + 256, 255);
+      do_test (i, i, (8 << i), (8 << i) + 256, 127);
+      do_test (i, i, (8 << i), (8 << i) + 256, 255);
+    }
+
+  for (i = 0; i < 16; ++i)
+    {
+      do_test (0, 0, i, i, 127);
+      do_test (0, 0, i, i + 2, 255);
+      do_test (0, i, i, i + 3, 127);
+      do_test (i, 0, i, i + 4, 255);
+    }
+
+  for (i = 1; i < 8; ++i)
+    {
+      do_test (0, 0, 8 << i, (8 << i) - 15, 127);
+      do_test (8 - i, 2 * i, (8 << i), (8 << i) + 5, 127);
+    }
+
+  for (i = 1; i < 8; ++i)
+    {
+      do_test (i, 2 * i, (8 << i), (8 << i) + i, 127);
+      do_test (2 * i, i, (8 << i), (8 << i) + (i - 1), 255);
+      do_test (i, i, (8 << i), (8 << i) + i + 2, 127);
+      do_test (i, i, (8 << i), (8 << i) + i + 3, 255);
+    }
+
+  do_random_tests ();
+  return ret;
+}
+
+#include "../test-skeleton.c"
diff --git a/debug/tst-chk1.c b/debug/tst-chk1.c
new file mode 100644 (file)
index 0000000..639da38
--- /dev/null
@@ -0,0 +1,466 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *temp_filename;
+static void do_prepare (void);
+static int do_test (void);
+#define PREPARE(argc, argv) do_prepare ()
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
+static void
+do_prepare (void)
+{
+  int temp_fd = create_temp_file ("tst-chk1.", &temp_filename);
+  if (temp_fd == -1)
+    {
+      printf ("cannot create temporary file: %m\n");
+      exit (1);
+    }
+
+  const char *strs = "abcdefgh\nABCDEFGHI\nabcdefghij\nABCDEFGHIJ";
+  if (write (temp_fd, strs, strlen (strs)) != strlen (strs))
+    {
+      puts ("could not write test strings into file");
+      unlink (temp_filename);
+      exit (1);
+    }
+}
+
+volatile int chk_fail_ok;
+jmp_buf chk_fail_buf;
+
+static void
+handler (int sig)
+{
+  if (chk_fail_ok)
+    {
+      chk_fail_ok = 0;
+      longjmp (chk_fail_buf, 1);
+    }
+  else
+    _exit (127);
+}
+
+char buf[10];
+volatile size_t l0;
+volatile char *p;
+const char *str1 = "JIHGFEDCBA";
+const char *str2 = "F";
+const char *str3 = "%s%n%s%n";
+const char *str4 = "Hello, ";
+const char *str5 = "World!\n";
+char buf2[10] = "%s";
+int num1 = 67;
+int num2 = 987654;
+
+#define FAIL() \
+  do { printf ("Failure on line %d\n", __LINE__); ret = 1; } while (0)
+#define CHK_FAIL_START \
+  chk_fail_ok = 1;                             \
+  if (! setjmp (chk_fail_buf))                 \
+    {
+#define CHK_FAIL_END \
+      chk_fail_ok = 0;                         \
+      FAIL ();                                 \
+      ret = 1;                                 \
+    }
+#if __USE_FORTIFY_LEVEL >= 2
+#define CHK_FAIL2_START CHK_FAIL_START
+#define CHK_FAIL2_END CHK_FAIL_END
+#else
+#define CHK_FAIL2_START
+#define CHK_FAIL2_END
+#endif
+
+static int
+do_test (void)
+{
+  int ret = 0;
+  struct sigaction sa;
+  sa.sa_handler = handler;
+  sa.sa_flags = 0;
+  sigemptyset (&sa.sa_mask);
+
+  sigaction (SIGABRT, &sa, NULL);
+
+  struct A { char buf1[9]; char buf2[1]; } a;
+
+  printf ("Test checking routines at fortify level %d\n",
+#ifdef __USE_FORTIFY_LEVEL
+         (int) __USE_FORTIFY_LEVEL
+#else
+         0
+#endif
+         );
+
+  /* These ops can be done without runtime checking of object size.  */
+  memcpy (buf, "abcdefghij", 10);
+  memmove (buf + 1, buf, 9);
+  if (memcmp (buf, "aabcdefghi", 10))
+    FAIL ();
+
+  if (mempcpy (buf + 5, "abcde", 5) != buf + 10 || memcmp (buf, "aabcdabcde", 10))
+    FAIL ();
+
+  memset (buf + 8, 'j', 2);
+  if (memcmp (buf, "aabcdabcjj", 10))
+    FAIL ();
+
+  strcpy (buf + 4, "EDCBA");
+  if (memcmp (buf, "aabcEDCBA", 10))
+    FAIL ();
+
+  if (stpcpy (buf + 8, "F") != buf + 9 || memcmp (buf, "aabcEDCBF", 10))
+    FAIL ();
+
+  strncpy (buf + 6, "X", 4);
+  if (memcmp (buf, "aabcEDX\0\0", 10))
+    FAIL ();
+
+  if (sprintf (buf + 7, "%s", "67") != 2 || memcmp (buf, "aabcEDX67", 10))
+    FAIL ();
+
+  if (snprintf (buf + 7, 3, "%s", "987654") != 6
+      || memcmp (buf, "aabcEDX98", 10))
+    FAIL ();
+
+  /* These ops need runtime checking, but shouldn't __chk_fail.  */
+  memcpy (buf, "abcdefghij", l0 + 10);
+  memmove (buf + 1, buf, l0 + 9);
+  if (memcmp (buf, "aabcdefghi", 10))
+    FAIL ();
+
+  if (mempcpy (buf + 5, "abcde", l0 + 5) != buf + 10 || memcmp (buf, "aabcdabcde", 10))
+    FAIL ();
+
+  memset (buf + 8, 'j', l0 + 2);
+  if (memcmp (buf, "aabcdabcjj", 10))
+    FAIL ();
+
+  strcpy (buf + 4, str1 + 5);
+  if (memcmp (buf, "aabcEDCBA", 10))
+    FAIL ();
+
+  if (stpcpy (buf + 8, str2) != buf + 9 || memcmp (buf, "aabcEDCBF", 10))
+    FAIL ();
+
+  strncpy (buf + 6, "X", l0 + 4);
+  if (memcmp (buf, "aabcEDX\0\0", 10))
+    FAIL ();
+
+  if (sprintf (buf + 7, "%d", num1) != 2 || memcmp (buf, "aabcEDX67", 10))
+    FAIL ();
+
+  if (snprintf (buf + 7, 3, "%d", num2) != 6 || memcmp (buf, "aabcEDX98", 10))
+    FAIL ();
+
+  buf[l0 + 8] = '\0';
+  strcat (buf, "A");
+  if (memcmp (buf, "aabcEDX9A", 10))
+    FAIL ();
+
+  buf[l0 + 7] = '\0';
+  strncat (buf, "ZYXWV", l0 + 2);
+  if (memcmp (buf, "aabcEDXZY", 10))
+    FAIL ();
+
+  memcpy (a.buf1, "abcdefghij", l0 + 10);
+  memmove (a.buf1 + 1, a.buf1, l0 + 9);
+  if (memcmp (a.buf1, "aabcdefghi", 10))
+    FAIL ();
+
+  if (mempcpy (a.buf1 + 5, "abcde", l0 + 5) != a.buf1 + 10
+      || memcmp (a.buf1, "aabcdabcde", 10))
+    FAIL ();
+
+  memset (a.buf1 + 8, 'j', l0 + 2);
+  if (memcmp (a.buf1, "aabcdabcjj", 10))
+    FAIL ();
+
+#if __USE_FORTIFY_LEVEL < 2
+  /* The following tests are supposed to crash with -D_FORTIFY_SOURCE=2
+     and sufficient GCC support, as the string operations overflow
+     from a.buf1 into a.buf2.  */
+  strcpy (a.buf1 + 4, str1 + 5);
+  if (memcmp (a.buf1, "aabcEDCBA", 10))
+    FAIL ();
+
+  if (stpcpy (a.buf1 + 8, str2) != a.buf1 + 9 || memcmp (a.buf1, "aabcEDCBF", 10))
+    FAIL ();
+
+  strncpy (a.buf1 + 6, "X", l0 + 4);
+  if (memcmp (a.buf1, "aabcEDX\0\0", 10))
+    FAIL ();
+
+  if (sprintf (a.buf1 + 7, "%d", num1) != 2 || memcmp (a.buf1, "aabcEDX67", 10))
+    FAIL ();
+
+  if (snprintf (a.buf1 + 7, 3, "%d", num2) != 6
+      || memcmp (a.buf1, "aabcEDX98", 10))
+    FAIL ();
+
+  a.buf1[l0 + 8] = '\0';
+  strcat (a.buf1, "A");
+  if (memcmp (a.buf1, "aabcEDX9A", 10))
+    FAIL ();
+
+  a.buf1[l0 + 7] = '\0';
+  strncat (a.buf1, "ZYXWV", l0 + 2);
+  if (memcmp (a.buf1, "aabcEDXZY", 10))
+    FAIL ();
+
+#endif
+
+#if __USE_FORTIFY_LEVEL >= 1
+  /* Now check if all buffer overflows are caught at runtime.  */
+
+  CHK_FAIL_START
+  memcpy (buf + 1, "abcdefghij", l0 + 10);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  memmove (buf + 2, buf + 1, l0 + 9);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  p = mempcpy (buf + 6, "abcde", l0 + 5);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  memset (buf + 9, 'j', l0 + 2);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  strcpy (buf + 5, str1 + 5);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  p = stpcpy (buf + 9, str2);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  strncpy (buf + 7, "X", l0 + 4);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  sprintf (buf + 8, "%d", num1);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  snprintf (buf + 8, l0 + 3, "%d", num2);
+  CHK_FAIL_END
+
+  memcpy (buf, str1 + 2, l0 + 9);
+  CHK_FAIL_START
+  strcat (buf, "AB");
+  CHK_FAIL_END
+
+  memcpy (buf, str1 + 3, l0 + 8);
+  CHK_FAIL_START
+  strncat (buf, "ZYXWV", l0 + 3);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  memcpy (a.buf1 + 1, "abcdefghij", l0 + 10);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  memmove (a.buf1 + 2, a.buf1 + 1, l0 + 9);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  p = mempcpy (a.buf1 + 6, "abcde", l0 + 5);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  memset (a.buf1 + 9, 'j', l0 + 2);
+  CHK_FAIL_END
+
+#if __USE_FORTIFY_LEVEL >= 2
+# define O 0
+#else
+# define O 1
+#endif
+
+  CHK_FAIL_START
+  strcpy (a.buf1 + (O + 4), str1 + 5);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  p = stpcpy (a.buf1 + (O + 8), str2);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  strncpy (a.buf1 + (O + 6), "X", l0 + 4);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  sprintf (a.buf1 + (O + 7), "%d", num1);
+  CHK_FAIL_END
+
+  CHK_FAIL_START
+  snprintf (a.buf1 + (O + 7), l0 + 3, "%d", num2);
+  CHK_FAIL_END
+
+  memcpy (a.buf1, str1 + (3 - O), l0 + 8 + O);
+  CHK_FAIL_START
+  strcat (a.buf1, "AB");
+  CHK_FAIL_END
+
+  memcpy (a.buf1, str1 + (4 - O), l0 + 7 + O);
+  CHK_FAIL_START
+  strncat (a.buf1, "ZYXWV", l0 + 3);
+  CHK_FAIL_END
+#endif
+
+  /* Now checks for %n protection.  */
+
+  /* Constant literals passed directly are always ok
+     (even with warnings about possible bugs from GCC).  */
+  int n1, n2;
+  if (sprintf (buf, "%s%n%s%n", str2, &n1, str2, &n2) != 2
+      || n1 != 1 || n2 != 2)
+    FAIL ();
+
+  /* In this case the format string is not known at compile time,
+     but resides in read-only memory, so is ok.  */
+  if (snprintf (buf, 4, str3, str2, &n1, str2, &n2) != 2
+      || n1 != 1 || n2 != 2)
+    FAIL ();
+
+  strcpy (buf2 + 2, "%n%s%n");
+  /* When the format string is writable and contains %n,
+     with -D_FORTIFY_SOURCE=2 it causes __chk_fail.  */
+  CHK_FAIL2_START
+  if (sprintf (buf, buf2, str2, &n1, str2, &n1) != 2)
+    FAIL ();
+  CHK_FAIL2_END
+
+  CHK_FAIL2_START
+  if (snprintf (buf, 3, buf2, str2, &n1, str2, &n1) != 2)
+    FAIL ();
+  CHK_FAIL2_END
+
+  /* But if there is no %n, even writable format string
+     should work.  */
+  buf2[6] = '\0';
+  if (sprintf (buf, buf2 + 4, str2) != 1)
+    FAIL ();
+
+  /* Constant literals passed directly are always ok
+     (even with warnings about possible bugs from GCC).  */
+  if (printf ("%s%n%s%n", str4, &n1, str5, &n2) != 14
+      || n1 != 7 || n2 != 14)
+    FAIL ();
+
+  /* In this case the format string is not known at compile time,
+     but resides in read-only memory, so is ok.  */
+  if (printf (str3, str4, &n1, str5, &n2) != 14
+      || n1 != 7 || n2 != 14)
+    FAIL ();
+
+  strcpy (buf2 + 2, "%n%s%n");
+  /* When the format string is writable and contains %n,
+     with -D_FORTIFY_SOURCE=2 it causes __chk_fail.  */
+  CHK_FAIL2_START
+  if (printf (buf2, str4, &n1, str5, &n1) != 14)
+    FAIL ();
+  CHK_FAIL2_END
+
+  /* But if there is no %n, even writable format string
+     should work.  */
+  buf2[6] = '\0';
+  if (printf (buf2 + 4, str5) != 7)
+    FAIL ();
+
+  FILE *fp = stdout;
+
+  /* Constant literals passed directly are always ok
+     (even with warnings about possible bugs from GCC).  */
+  if (fprintf (fp, "%s%n%s%n", str4, &n1, str5, &n2) != 14
+      || n1 != 7 || n2 != 14)
+    FAIL ();
+
+  /* In this case the format string is not known at compile time,
+     but resides in read-only memory, so is ok.  */
+  if (fprintf (fp, str3, str4, &n1, str5, &n2) != 14
+      || n1 != 7 || n2 != 14)
+    FAIL ();
+
+  strcpy (buf2 + 2, "%n%s%n");
+  /* When the format string is writable and contains %n,
+     with -D_FORTIFY_SOURCE=2 it causes __chk_fail.  */
+  CHK_FAIL2_START
+  if (fprintf (fp, buf2, str4, &n1, str5, &n1) != 14)
+    FAIL ();
+  CHK_FAIL2_END
+
+  /* But if there is no %n, even writable format string
+     should work.  */
+  buf2[6] = '\0';
+  if (fprintf (fp, buf2 + 4, str5) != 7)
+    FAIL ();
+
+  if (freopen (temp_filename, "r", stdin) == NULL)
+    {
+      puts ("could not open temporary file");
+      exit (1);
+    }
+
+  if (gets (buf) != buf || memcmp (buf, "abcdefgh", 9))
+    FAIL ();
+  if (gets (buf) != buf || memcmp (buf, "ABCDEFGHI", 10))
+    FAIL ();
+
+#if __USE_FORTIFY_LEVEL >= 1
+  CHK_FAIL_START
+  if (gets (buf) != buf)
+    FAIL ();
+  CHK_FAIL_END
+#endif
+
+  if (freopen (temp_filename, "r", stdin) == NULL)
+    {
+      puts ("could not open temporary file");
+      exit (1);
+    }
+
+  if (fseek (stdin, 9 + 10 + 11, SEEK_SET))
+    {
+      puts ("could not seek in test file");
+      exit (1);
+    }
+
+#if __USE_FORTIFY_LEVEL >= 1
+  CHK_FAIL_START
+  if (gets (buf) != buf)
+    FAIL ();
+  CHK_FAIL_END
+#endif
+
+  return ret;
+}
diff --git a/debug/tst-chk2.c b/debug/tst-chk2.c
new file mode 100644 (file)
index 0000000..be37ce2
--- /dev/null
@@ -0,0 +1,2 @@
+#define _FORTIFY_SOURCE 1
+#include "tst-chk1.c"
diff --git a/debug/tst-chk3.c b/debug/tst-chk3.c
new file mode 100644 (file)
index 0000000..38b8e4f
--- /dev/null
@@ -0,0 +1,2 @@
+#define _FORTIFY_SOURCE 2
+#include "tst-chk1.c"
diff --git a/debug/vfprintf_chk.c b/debug/vfprintf_chk.c
new file mode 100644 (file)
index 0000000..a9e107d
--- /dev/null
@@ -0,0 +1,42 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2001, 2004
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "../libio/libioP.h"
+
+
+/* Write formatted output to FP from the format string FORMAT.  */
+int
+__vfprintf_chk (FILE *fp, int flag, const char *format, va_list ap)
+{
+  int done;
+
+  _IO_acquire_lock (fp);
+  if (flag > 0)
+    fp->_flags2 |= _IO_FLAGS2_CHECK_PERCENT_N;
+
+  done = vfprintf (fp, format, ap);
+
+  if (flag > 0)
+    fp->_flags2 &= ~_IO_FLAGS2_CHECK_PERCENT_N;
+  _IO_release_lock (fp);
+
+  return done;
+}
diff --git a/debug/vprintf_chk.c b/debug/vprintf_chk.c
new file mode 100644 (file)
index 0000000..f477f15
--- /dev/null
@@ -0,0 +1,42 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2001, 2004
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "../libio/libioP.h"
+
+
+/* Write formatted output to stdout from the format string FORMAT.  */
+int
+__vprintf_chk (int flag, const char *format, va_list ap)
+{
+  int done;
+
+  _IO_acquire_lock (stdout);
+  if (flag > 0)
+    stdout->_flags2 |= _IO_FLAGS2_CHECK_PERCENT_N;
+
+  done = vfprintf (stdout, format, ap);
+
+  if (flag > 0)
+    stdout->_flags2 &= ~_IO_FLAGS2_CHECK_PERCENT_N;
+  _IO_release_lock (stdout);
+
+  return done;
+}
diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
new file mode 100644 (file)
index 0000000..850cd5a
--- /dev/null
@@ -0,0 +1,70 @@
+/* Copyright (C) 1991, 1995, 1997, 1998, 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "../libio/libioP.h"
+#include "../libio/strfile.h"
+
+extern const struct _IO_jump_t _IO_strn_jumps attribute_hidden;
+
+/* Write formatted output into S, according to the format
+   string FORMAT, writing no more than MAXLEN characters.  */
+/* VARARGS5 */
+int
+__vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
+                const char *format, va_list args)
+{
+  /* XXX Maybe for less strict version do not fail immediately.
+     Though, maxlen is supposed to be the size of buffer pointed
+     to by s, so a conforming program can't pass such maxlen
+     to *snprintf.  */
+  if (__builtin_expect (slen < maxlen, 0))
+    __chk_fail ();
+
+  _IO_strnfile sf;
+  int ret;
+#ifdef _IO_MTSAFE_IO
+  sf.f._sbf._f._lock = NULL;
+#endif
+
+  /* We need to handle the special case where MAXLEN is 0.  Use the
+     overflow buffer right from the start.  */
+  if (maxlen == 0)
+    {
+      s = sf.overflow_buf;
+      maxlen = sizeof (sf.overflow_buf);
+    }
+
+  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
+  _IO_JUMPS ((struct _IO_FILE_plus *) &sf.f._sbf) = &_IO_strn_jumps;
+  s[0] = '\0';
+
+  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  if (flags > 0)
+    sf.f._sbf._f._flags2 |= _IO_FLAGS2_CHECK_PERCENT_N;
+
+  _IO_str_init_static_internal (&sf.f, s, maxlen - 1, s);
+  ret = INTUSE(_IO_vfprintf) ((_IO_FILE *) &sf.f._sbf, format, args);
+
+  if (sf.f._sbf._f._IO_buf_base != sf.overflow_buf)
+    *sf.f._sbf._f._IO_write_ptr = '\0';
+  return ret;
+}
+libc_hidden_def (__vsnprintf_chk)
diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
new file mode 100644 (file)
index 0000000..8338328
--- /dev/null
@@ -0,0 +1,91 @@
+/* Copyright (C) 1994, 1997, 1999-2003, 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "../libio/libioP.h"
+#include "../libio/strfile.h"
+
+
+static int _IO_str_chk_overflow (_IO_FILE *fp, int c) __THROW;
+
+static int
+_IO_str_chk_overflow (fp, c)
+     _IO_FILE *fp;
+     int c;
+{
+  /* When we come to here this means the user supplied buffer is
+     filled.  */
+  __chk_fail ();
+}
+
+
+static const struct _IO_jump_t _IO_str_chk_jumps =
+{
+  JUMP_INIT_DUMMY,
+  JUMP_INIT(finish, _IO_str_finish),
+  JUMP_INIT(overflow, _IO_str_chk_overflow),
+  JUMP_INIT(underflow, INTUSE(_IO_str_underflow)),
+  JUMP_INIT(uflow, INTUSE(_IO_default_uflow)),
+  JUMP_INIT(pbackfail, INTUSE(_IO_str_pbackfail)),
+  JUMP_INIT(xsputn, INTUSE(_IO_default_xsputn)),
+  JUMP_INIT(xsgetn, INTUSE(_IO_default_xsgetn)),
+  JUMP_INIT(seekoff, INTUSE(_IO_str_seekoff)),
+  JUMP_INIT(seekpos, _IO_default_seekpos),
+  JUMP_INIT(setbuf, _IO_default_setbuf),
+  JUMP_INIT(sync, _IO_default_sync),
+  JUMP_INIT(doallocate, INTUSE(_IO_default_doallocate)),
+  JUMP_INIT(read, _IO_default_read),
+  JUMP_INIT(write, _IO_default_write),
+  JUMP_INIT(seek, _IO_default_seek),
+  JUMP_INIT(close, _IO_default_close),
+  JUMP_INIT(stat, _IO_default_stat),
+  JUMP_INIT(showmanyc, _IO_default_showmanyc),
+  JUMP_INIT(imbue, _IO_default_imbue)
+};
+
+
+int
+__vsprintf_chk (char *s, int flags, size_t slen, const char *format,
+               va_list args)
+{
+  _IO_strfile f;
+  int ret;
+#ifdef _IO_MTSAFE_IO
+  f._sbf._f._lock = NULL;
+#endif
+
+  if (slen == 0)
+    __chk_fail ();
+
+  _IO_no_init (&f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
+  _IO_JUMPS ((struct _IO_FILE_plus *) &f._sbf) = &_IO_str_chk_jumps;
+  s[0] = '\0';
+  _IO_str_init_static_internal (&f, s, slen - 1, s);
+
+  /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  if (flags > 0)
+    f._sbf._f._flags2 |= _IO_FLAGS2_CHECK_PERCENT_N;
+
+  ret = INTUSE(_IO_vfprintf) ((_IO_FILE *) &f._sbf, format, args);
+
+  *f._sbf._f._IO_write_ptr = '\0';
+  return ret;
+}
+libc_hidden_def (__vsprintf_chk)
index 4ec2ebc..adb85e6 100644 (file)
@@ -354,6 +354,13 @@ __strsep (char **stringp, const char *delim)
 weak_alias (__strsep, strsep)
 strong_alias (__strsep, __strsep_g)
 
+void
+__attribute__ ((noreturn))
+__chk_fail (void)
+{
+  _exit (127);
+}
+rtld_hidden_def (__chk_fail)
 
 /* The '_itoa_lower_digits' variable in libc.so is able to handle bases
    up to 36.  We don't need this here.  */
diff --git a/include/bits/string3.h b/include/bits/string3.h
new file mode 100644 (file)
index 0000000..1ddd981
--- /dev/null
@@ -0,0 +1 @@
+#include <string/bits/string3.h>
index 59ae3c4..8b03e16 100644 (file)
@@ -41,6 +41,8 @@
    _GNU_SOURCE         All of the above, plus GNU extensions.
    _REENTRANT          Select additionally reentrant object.
    _THREAD_SAFE                Same as _REENTRANT, often used by other systems.
+   _FORTIFY_SOURCE     If set to numeric value > 0 additional security
+                       measures are defined, according to level.
 
    The `-ansi' switch to the GNU C compiler defines __STRICT_ANSI__.
    If none of these are defined, the default is to have _SVID_SOURCE,
@@ -69,6 +71,7 @@
    __USE_MISC          Define things common to BSD and System V Unix.
    __USE_GNU           Define GNU extensions.
    __USE_REENTRANT     Define reentrant/thread-safe *_r functions.
+   __USE_FORTIFY_LEVEL Additional security measures used, according to level.
    __FAVOR_BSD         Favor 4.3BSD things in cases of conflict.
 
    The macros `__GNU_LIBRARY__', `__GLIBC__', and `__GLIBC_MINOR__' are
 #undef __USE_MISC
 #undef __USE_GNU
 #undef __USE_REENTRANT
+#undef __USE_FORTIFY_LEVEL
 #undef __FAVOR_BSD
 #undef __KERNEL_STRICT_NAMES
 
 /* Always use ISO C things.  */
 #define        __USE_ANSI      1
 
+/* Convenience macros to test the versions of glibc and gcc.
+   Use them like this:
+   #if __GNUC_PREREQ (2,8)
+   ... code requiring gcc 2.8 or later ...
+   #endif
+   Note - they won't work for gcc1 or glibc1, since the _MINOR macros
+   were not defined then.  */
+#if defined __GNUC__ && defined __GNUC_MINOR__
+# define __GNUC_PREREQ(maj, min) \
+       ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+# define __GNUC_PREREQ(maj, min) 0
+#endif
+
 
 /* If _BSD_SOURCE was defined by the user, favor BSD over POSIX.  */
 #if defined _BSD_SOURCE && \
 # define __USE_REENTRANT       1
 #endif
 
+#if _FORTIFY_SOURCE > 0 && __GNUC_PREREQ (4, 1) && __OPTIMIZE__ > 0
+# if _FORTIFY_SOURCE == 1
+#  define __USE_FORTIFY_LEVEL 1
+# elif _FORTIFY_SOURCE > 1
+#  define __USE_FORTIFY_LEVEL 2
+# endif
+#endif
+
 /* We do support the IEC 559 math functionality, real and complex.  */
 #define __STDC_IEC_559__               1
 #define __STDC_IEC_559_COMPLEX__       1
 #define        __GLIBC__       2
 #define        __GLIBC_MINOR__ 3
 
-/* Convenience macros to test the versions of glibc and gcc.
-   Use them like this:
-   #if __GNUC_PREREQ (2,8)
-   ... code requiring gcc 2.8 or later ...
-   #endif
-   Note - they won't work for gcc1 or glibc1, since the _MINOR macros
-   were not defined then.  */
-#if defined __GNUC__ && defined __GNUC_MINOR__
-# define __GNUC_PREREQ(maj, min) \
-       ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#else
-# define __GNUC_PREREQ(maj, min) 0
-#endif
-
 #define __GLIBC_PREREQ(maj, min) \
        ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
 
index b871abc..05a91b4 100644 (file)
@@ -27,6 +27,18 @@ extern int __vsscanf (__const char *__restrict __s,
                      _G_va_list __arg)
      __attribute__ ((__format__ (__scanf__, 2, 0)));
 
+extern int __sprintf_chk (char *, int, size_t, const char *, ...) __THROW;
+extern int __snprintf_chk (char *, size_t, int, size_t, const char *, ...)
+     __THROW;
+extern int __vsprintf_chk (char *, int, size_t, const char *,
+                          _G_va_list) __THROW;
+extern int __vsnprintf_chk (char *, size_t, int, size_t, const char *,
+                           _G_va_list) __THROW;
+extern int __printf_chk (int, const char *, ...);
+extern int __fprintf_chk (FILE *, int, const char *, ...);
+extern int __vprintf_chk (int, const char *, _G_va_list);
+extern int __vfprintf_chk (FILE *, int, const char *, _G_va_list);
+
 /* Prototypes for compatibility functions.  */
 extern FILE *__new_tmpfile (void);
 extern FILE *__old_tmpfile (void);
@@ -109,6 +121,8 @@ libc_hidden_proto (fgets_unlocked)
 libc_hidden_proto (fputs_unlocked)
 libc_hidden_proto (open_memstream)
 libc_hidden_proto (__libc_fatal)
+libc_hidden_proto (__vsprintf_chk)
+libc_hidden_proto (__vsnprintf_chk)
 
 #  if !defined NOT_IN_libc && defined SHARED && defined DO_VERSIONING \
   && defined HAVE_VISIBILITY_ATTRIBUTE && !defined HAVE_BROKEN_ALIAS_ATTRIBUTE\
index afc6adf..738dd8e 100644 (file)
@@ -3,7 +3,7 @@
 #include <sys/types.h>
 
 extern void *__memccpy (void *__dest, __const void *__src,
-                         int __c, size_t __n);
+                       int __c, size_t __n);
 
 extern size_t __strnlen (__const char *__string, size_t __maxlen)
      __attribute_pure__;
@@ -114,4 +114,30 @@ libc_hidden_builtin_proto (ffs)
 #  endif
 # endif
 
+extern void *__memcpy_chk (void *__restrict __dest,
+                          const void *__restrict __src, size_t __len,
+                          size_t __destlen) __THROW;
+extern void *__memmove_chk (void *__dest, const void *__src, size_t __len,
+                           size_t __destlen) __THROW;
+extern void *__mempcpy_chk (void *__restrict __dest,
+                           const void *__restrict __src, size_t __len,
+                           size_t __destlen) __THROW;
+extern void *__memset_chk (void *__dest, int __ch, size_t __len,
+                          size_t __destlen) __THROW;
+extern char *__strcpy_chk (char *__restrict __dest,
+                          const char *__restrict __src,
+                          size_t __destlen) __THROW;
+extern char *__stpcpy_chk (char *__restrict __dest,
+                          const char *__restrict __src,
+                          size_t __destlen) __THROW;
+extern char *__strncpy_chk (char *__restrict __dest,
+                           const char *__restrict __src,
+                           size_t __len, size_t __destlen) __THROW;
+extern char *__strcat_chk (char *__restrict __dest,
+                          const char *__restrict __src,
+                          size_t __destlen) __THROW;
+extern char *__strncat_chk (char *__restrict __dest,
+                           const char *__restrict __src,
+                           size_t __len, size_t __destlen) __THROW;
+
 #endif
index 200abb4..8ba9804 100644 (file)
@@ -1 +1,9 @@
+#ifndef _SYS_CDEFS_H
+
 #include <misc/sys/cdefs.h>
+
+extern void __chk_fail (void) __attribute__ ((__noreturn__));
+libc_hidden_proto (__chk_fail)
+rtld_hidden_proto (__chk_fail)
+
+#endif
index c7253ff..a9384b5 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 1995-2002, 2003 Free Software Foundation, Inc.
+# Copyright (C) 1995-2002, 2003, 2004 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
@@ -22,7 +22,7 @@
 subdir := libio
 
 headers        := stdio.h libio.h _G_config.h bits/stdio.h bits/stdio-lock.h \
-          bits/sys_errlist.h
+          bits/sys_errlist.h bits/stdio2.h
 
 routines       :=                                                            \
        filedoalloc iofclose iofdopen iofflush iofgetpos iofgets iofopen      \
diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
new file mode 100644 (file)
index 0000000..acf07ea
--- /dev/null
@@ -0,0 +1,78 @@
+/* Checking macros for stdio functions.
+   Copyright (C) 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _STDIO_H
+# error "Never include <bits/stdio2.h> directly; use <stdio.h> instead."
+#endif
+
+extern int __sprintf_chk (char *__restrict __s, int __flag, size_t __slen,
+                         __const char *__restrict __format, ...) __THROW;
+extern int __vsprintf_chk (char *__restrict __s, int __flag, size_t __slen,
+                          __const char *__restrict __format,
+                          _G_va_list __ap) __THROW;
+
+#define sprintf(str, ...) \
+  __builtin___sprintf_chk (str, __USE_FORTIFY_LEVEL - 1, __bos (str), \
+                          __VA_ARGS__)
+#define vsprintf(str, fmt, ap) \
+  __builtin___vsprintf_chk (str, __USE_FORTIFY_LEVEL - 1, __bos (str), fmt, ap)
+
+#if defined __USE_BSD || defined __USE_ISOC99 || defined __USE_UNIX98
+
+extern int __snprintf_chk (char *__restrict __s, size_t __n, int __flag,
+                          size_t __slen, __const char *__restrict __format,
+                          ...) __THROW;
+extern int __vsnprintf_chk (char *__restrict __s, size_t __n, int __flag,
+                           size_t __slen, __const char *__restrict __format,
+                           _G_va_list __ap) __THROW;
+
+# define snprintf(str, len, ...) \
+  __builtin___snprintf_chk (str, len, __USE_FORTIFY_LEVEL - 1, __bos (str), \
+                           __VA_ARGS__)
+# define vsnprintf(str, len, fmt, ap) \
+  __builtin___vsnprintf_chk (str, len, __USE_FORTIFY_LEVEL - 1, __bos (str), \
+                            fmt, ap)
+
+#endif                      
+
+#if __USE_FORTIFY_LEVEL > 1
+
+extern int __fprintf_chk (FILE *__restrict __stream, int __flag,
+                         __const char *__restrict __format, ...);
+extern int __printf_chk (int __flag, __const char *__restrict __format, ...);
+extern int __vfprintf_chk (FILE *__restrict __stream, int __flag,
+                          __const char *__restrict __format, _G_va_list __ap);
+extern int __vprintf_chk (int __flag, __const char *__restrict __format,
+                         _G_va_list __ap);
+
+# define printf(...) \
+  __printf_chk (__USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
+# define fprintf(stream, ...) \
+  __fprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
+# define vprintf(format, ap) \
+  __vprintf_chk (__USE_FORTIFY_LEVEL - 1, format, ap)
+# define vfprintf(stream, format, ap) \
+  __vfprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, format, ap)
+
+#endif
+
+extern char *__gets_chk (char *__str, size_t);
+#define gets(__str) \
+  ((__bos (__str) == (size_t) -1)                              \
+   ? (gets) (__str) : __gets_chk (__str, __bos (__str)))
index 1672f7b..645f9fb 100644 (file)
 
 #define _IO_FLAGS2_MMAP 1
 #define _IO_FLAGS2_NOTCANCEL 2
+#ifdef _LIBC
+# define _IO_FLAGS2_CHECK_PERCENT_N 4
+#endif
 
 /* These are "formatting flags" matching the iostream fmtflags enum values. */
 #define _IO_SKIPWS 01
index 5990942..e1081c9 100644 (file)
@@ -827,6 +827,9 @@ extern void funlockfile (FILE *__stream) __THROW;
 #ifdef __USE_EXTERN_INLINES
 # include <bits/stdio.h>
 #endif
+#if __USE_FORTIFY_LEVEL > 0 && !defined __cplusplus
+# include <bits/stdio2.h>
+#endif
 
 __END_DECLS
 
index bcac784..b91111a 100644 (file)
@@ -63,3 +63,13 @@ typedef struct _IO_strfile_
 /* frozen: set when the program has requested that the array object not
    be altered, reallocated, or freed. */
 #define _IO_STR_FROZEN(FP) ((FP)->_f._IO_file_flags & _IO_USER_BUF)
+
+typedef struct
+{
+  _IO_strfile f;
+  /* This is used for the characters which do not fit in the buffer
+     provided by the user.  */
+  char overflow_buf[64];
+} _IO_strnfile;
+
+extern const struct _IO_jump_t _IO_strn_jumps attribute_hidden;
index e2cfb16..4250c2d 100644 (file)
 #include "libioP.h"
 #include "strfile.h"
 
-
-typedef struct
-{
-  _IO_strfile f;
-  /* This is used for the characters which do not fit in the buffer
-     provided by the user.  */
-  char overflow_buf[64];
-} _IO_strnfile;
-
-
 static int _IO_strn_overflow (_IO_FILE *fp, int c) __THROW;
 
 static int
@@ -77,7 +67,7 @@ _IO_strn_overflow (fp, c)
 }
 
 
-static const struct _IO_jump_t _IO_strn_jumps =
+const struct _IO_jump_t _IO_strn_jumps attribute_hidden =
 {
   JUMP_INIT_DUMMY,
   JUMP_INIT(finish, _IO_str_finish),
index 3cf01e2..42168aa 100644 (file)
@@ -35,7 +35,7 @@ typedef struct
   /* This is used for the characters which do not fit in the buffer
      provided by the user.  */
   wchar_t overflow_buf[64];
-} _IO_strnfile;
+} _IO_wstrnfile;
 
 
 static wint_t _IO_wstrn_overflow (_IO_FILE *fp, wint_t c) __THROW;
@@ -49,8 +49,8 @@ _IO_wstrn_overflow (fp, c)
      filled.  But since we must return the number of characters which
      would have been written in total we must provide a buffer for
      further use.  We can do this by writing on and on in the overflow
-     buffer in the _IO_strnfile structure.  */
-  _IO_strnfile *snf = (_IO_strnfile *) fp;
+     buffer in the _IO_wstrnfile structure.  */
+  _IO_wstrnfile *snf = (_IO_wstrnfile *) fp;
 
   if (fp->_wide_data->_IO_buf_base != snf->overflow_buf)
     {
@@ -107,7 +107,7 @@ _IO_vswprintf (string, maxlen, format, args)
      const wchar_t *format;
      _IO_va_list args;
 {
-  _IO_strnfile sf;
+  _IO_wstrnfile sf;
   int ret;
   struct _IO_wide_data wd;
 #ifdef _IO_MTSAFE_IO
index 8894d0d..475cf62 100644 (file)
 #endif
 
 
+/* Fortify support.  */
+#define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1)
+#define __bos0(ptr) __builtin_object_size (ptr, 0)
+
+
 /* Support for flexible arrays.  */
 #if __GNUC_PREREQ (2,97)
 /* GCC 2.97 supports C99 flexible array members.  */
index 38da382..5e480ad 100644 (file)
@@ -70,6 +70,7 @@
 # define INT_T         int
 # define L_(Str)       Str
 # define ISDIGIT(Ch)   ((unsigned int) ((Ch) - '0') < 10)
+# define STR_LEN(Str)  strlen (Str)
 
 # define PUT(F, S, N)  _IO_sputn ((F), (S), (N))
 # define PAD(Padchar) \
@@ -86,6 +87,7 @@
 # define INT_T         wint_t
 # define L_(Str)       L##Str
 # define ISDIGIT(Ch)   ((unsigned int) ((Ch) - L'0') < 10)
+# define STR_LEN(Str)  __wcslen (Str)
 
 # include "_itowa.h"
 
@@ -219,6 +221,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
   /* For the %m format we may need the current `errno' value.  */
   int save_errno = errno;
 
+  /* 1 if format is in read-only memory, -1 if it is in writable memory,
+     0 if unknown.  */
+  int readonly_format = 0;
 
   /* This table maps a character into a number representing a
      class.  In each step there is a destination label for each
@@ -877,6 +882,19 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
       /* NOTREACHED */                                                       \
                                                                              \
     LABEL (form_number):                                                     \
+      if (s->_flags2 & _IO_FLAGS2_CHECK_PERCENT_N)                           \
+       {                                                                     \
+         if (! readonly_format)                                              \
+           {                                                                 \
+             extern int __readonly_area (const void *, size_t)               \
+               attribute_hidden;                                             \
+             readonly_format                                                 \
+               = __readonly_area (format, (STR_LEN (format) + 1)             \
+                                          * sizeof (CHAR_T));                \
+           }                                                                 \
+         if (readonly_format < 0)                                            \
+           __chk_fail ();                                                    \
+       }                                                                     \
       /* Answer the count of characters written.  */                         \
       if (fspec == NULL)                                                     \
        {                                                                     \
@@ -2091,6 +2109,7 @@ buffered_vfprintf (register _IO_FILE *s, const CHAR_T *format,
 #ifdef _IO_MTSAFE_IO
   hp->_lock = NULL;
 #endif
+  hp->_flags2 = s->_flags2;
   _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
 
   /* Now print to helper instead.  */
index 5ab487f..66469f5 100644 (file)
@@ -23,7 +23,7 @@ subdir        := string
 
 headers        := string.h strings.h memory.h endian.h bits/endian.h \
           argz.h envz.h byteswap.h bits/byteswap.h bits/string.h \
-          bits/string2.h
+          bits/string2.h bits/string3.h
 
 routines       := strcat strchr strcmp strcoll strcpy strcspn          \
                   strverscmp strdup strndup                            \
diff --git a/string/bits/string3.h b/string/bits/string3.h
new file mode 100644 (file)
index 0000000..87cbe35
--- /dev/null
@@ -0,0 +1,167 @@
+/* Copyright (C) 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _STRING_H
+# error "Never use <bits/string3.h> directly; include <string.h> instead."
+#endif
+
+/* XXX This is temporarily.  We should not redefine any of the symbols
+   and instead integrate the error checking into the original
+   definitions.  */
+#undef memcpy
+#undef memmove
+#undef memset
+#undef strcat
+#undef strcpy
+#undef strncat
+#undef strncpy
+#ifdef __USE_GNU
+# undef mempcpy
+# undef stpcpy
+#endif
+#ifdef __USE_BSD
+# undef bcopy
+# undef bzero
+#endif
+
+
+#define memcpy(dest, src, len) \
+  ((__bos0 (dest) != (size_t) -1)                                      \
+   ? __builtin___memcpy_chk (dest, src, len, __bos0 (dest))            \
+   : __memcpy_ichk (dest, src, len))
+static __inline__ void *
+__attribute__ ((__always_inline__))
+__memcpy_ichk (void *__restrict __dest, const void *__restrict __src,
+              size_t __len)
+{
+  return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
+}
+
+
+#define memmove(dest, src, len) \
+  ((__bos0 (dest) != (size_t) -1)                                      \
+   ? __builtin___memmove_chk (dest, src, len, __bos0 (dest))           \
+   : __memmove_ichk (dest, src, len))
+static __inline__ void *
+__attribute__ ((__always_inline__))
+__memmove_ichk (void *__dest, const void *__src, size_t __len)
+{
+  return __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest));
+}
+
+
+#ifdef __USE_GNU
+# define mempcpy(dest, src, len) \
+  ((__bos0 (dest) != (size_t) -1)                                      \
+   ? __builtin___mempcpy_chk (dest, src, len, __bos0 (dest))           \
+   : __mempcpy_ichk (dest, src, len))
+static __inline__ void *
+__attribute__ ((__always_inline__))
+__mempcpy_ichk (void *__restrict __dest, const void *__restrict __src,
+               size_t __len)
+{
+  return __builtin___mempcpy_chk (__dest, __src, __len, __bos0 (__dest));
+}
+#endif
+
+
+#define memset(dest, ch, len) \
+  ((__bos0 (dest) != (size_t) -1)                                      \
+   ? __builtin___memset_chk (dest, ch, len, __bos0 (dest))             \
+   : __memset_ichk (dest, ch, len))
+static __inline__ void *
+__attribute__ ((__always_inline__))
+__memset_ichk (void *__dest, int __ch, size_t __len)
+{
+  return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest));
+}
+
+#ifdef __USE_BSD
+# define bcopy(src, dest, len) ((void) \
+  ((__bos0 (dest) != (size_t) -1)                                      \
+   ? __builtin___memmove_chk (dest, src, len, __bos0 (dest))           \
+   : __memmove_ichk (dest, src, len)))
+# define bzero(dest, len) ((void) \
+  ((__bos0 (dest) != (size_t) -1)                                      \
+   ? __builtin___memset_chk (dest, '\0', len, __bos0 (dest))           \
+   : __memset_ichk (dest, '\0', len)))
+#endif
+
+
+#define strcpy(dest, src) \
+  ((__bos (dest) != (size_t) -1)                                       \
+   ? __builtin___strcpy_chk (dest, src, __bos (dest))                  \
+   : __strcpy_ichk (dest, src))
+static __inline__ char *
+__attribute__ ((__always_inline__))
+__strcpy_ichk (char *__restrict __dest, const char *__restrict __src)
+{
+  return __builtin___strcpy_chk (__dest, __src, __bos (__dest));
+}
+
+
+#ifdef __USE_GNU
+# define stpcpy(dest, src) \
+  ((__bos (dest) != (size_t) -1)                                       \
+   ? __builtin___stpcpy_chk (dest, src, __bos (dest))                  \
+   : __stpcpy_ichk (dest, src))
+static __inline__ char *
+__attribute__ ((__always_inline__))
+__stpcpy_ichk (char *__restrict __dest, const char *__restrict __src)
+{
+  return __builtin___stpcpy_chk (__dest, __src, __bos (__dest));
+}
+#endif
+
+
+#define strncpy(dest, src, len) \
+  ((__bos (dest) != (size_t) -1)                                       \
+   ? __builtin___strncpy_chk (dest, src, len, __bos (dest))            \
+   : __strncpy_ichk (dest, src, len))
+static __inline__ char *
+__attribute__ ((__always_inline__))
+__strncpy_ichk (char *__restrict __dest, const char *__restrict __src,
+               size_t __len)
+{
+  return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
+}
+
+
+#define strcat(dest, src) \
+  ((__bos (dest) != (size_t) -1)                                       \
+   ? __builtin___strcat_chk (dest, src, __bos (dest))                  \
+   : __strcat_ichk (dest, src))
+static __inline__ char *
+__attribute__ ((__always_inline__))
+__strcat_ichk (char *__restrict __dest, const char *__restrict __src)
+{
+  return __builtin___strcat_chk (__dest, __src, __bos (__dest));
+}
+
+
+#define strncat(dest, src, len) \
+  ((__bos (dest) != (size_t) -1)                                       \
+   ? __builtin___strncat_chk (dest, src, len, __bos (dest))            \
+   : __strncat_ichk (dest, src, len))
+static __inline__ char *
+__attribute__ ((__always_inline__))
+__strncat_ichk (char *__restrict __dest, const char *__restrict __src,
+               size_t __len)
+{
+  return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest));
+}
index 4ea3a74..1adf925 100644 (file)
@@ -416,6 +416,11 @@ extern char *basename (__const char *__filename) __THROW __nonnull ((1));
 /* These are generic optimizations which do not add too much inline code.  */
 #  include <bits/string2.h>
 # endif
+
+# if __USE_FORTIFY_LEVEL > 0 && !defined __cplusplus
+/* Functions with security checks.  */
+#  include <bits/string3.h>
+# endif
 #endif
 
 __END_DECLS
diff --git a/sysdeps/generic/memcpy_chk.c b/sysdeps/generic/memcpy_chk.c
new file mode 100644 (file)
index 0000000..638cd0e
--- /dev/null
@@ -0,0 +1,66 @@
+/* Copy memory to memory until the specified number of bytes
+   has been copied with error checking.  Overlap is NOT handled correctly.
+   Copyright (C) 1991, 1997, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Torbjorn Granlund (tege@sics.se).
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include <memcopy.h>
+#include <pagecopy.h>
+
+void *
+__memcpy_chk (dstpp, srcpp, len, dstlen)
+     void *dstpp;
+     const void *srcpp;
+     size_t len;
+     size_t dstlen;
+{
+  if (__builtin_expect (dstlen < len, 0))
+    __chk_fail ();
+
+  unsigned long int dstp = (long int) dstpp;
+  unsigned long int srcp = (long int) srcpp;
+
+  /* Copy from the beginning to the end.  */
+
+  /* If there not too few bytes to copy, use word copy.  */
+  if (len >= OP_T_THRES)
+    {
+      /* Copy just a few bytes to make DSTP aligned.  */
+      len -= (-dstp) % OPSIZ;
+      BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);
+
+      /* Copy whole pages from SRCP to DSTP by virtual address manipulation,
+        as much as possible.  */
+
+      PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);
+
+      /* Copy from SRCP to DSTP taking advantage of the known alignment of
+        DSTP.  Number of bytes remaining is put in the third argument,
+        i.e. in LEN.  This number may vary from machine to machine.  */
+
+      WORD_COPY_FWD (dstp, srcp, len, len);
+
+      /* Fall out and copy the tail.  */
+    }
+
+  /* There are just a few bytes to copy.  Use byte memory operations.  */
+  BYTE_COPY_FWD (dstp, srcp, len);
+
+  return dstpp;
+}
diff --git a/sysdeps/generic/memmove_chk.c b/sysdeps/generic/memmove_chk.c
new file mode 100644 (file)
index 0000000..f3b74d2
--- /dev/null
@@ -0,0 +1,98 @@
+/* Copy memory to memory until the specified number of bytes
+   has been copied with error checking.  Overlap is handled correctly.
+   Copyright (C) 1991,1995,1996,1997,2003,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Torbjorn Granlund (tege@sics.se).
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include <memcopy.h>
+#include <pagecopy.h>
+
+void *
+__memmove_chk (dest, src, len, destlen)
+     void *dest;
+     const void *src;
+     size_t len;
+     size_t destlen;
+{
+  if (__builtin_expect (destlen < len, 0))
+    __chk_fail ();
+
+  unsigned long int dstp = (long int) dest;
+  unsigned long int srcp = (long int) src;
+
+  /* This test makes the forward copying code be used whenever possible.
+     Reduces the working set.  */
+  if (dstp - srcp >= len)      /* *Unsigned* compare!  */
+    {
+      /* Copy from the beginning to the end.  */
+
+      /* If there not too few bytes to copy, use word copy.  */
+      if (len >= OP_T_THRES)
+       {
+         /* Copy just a few bytes to make DSTP aligned.  */
+         len -= (-dstp) % OPSIZ;
+         BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);
+
+         /* Copy whole pages from SRCP to DSTP by virtual address
+            manipulation, as much as possible.  */
+
+         PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);
+
+         /* Copy from SRCP to DSTP taking advantage of the known
+            alignment of DSTP.  Number of bytes remaining is put
+            in the third argument, i.e. in LEN.  This number may
+            vary from machine to machine.  */
+
+         WORD_COPY_FWD (dstp, srcp, len, len);
+
+         /* Fall out and copy the tail.  */
+       }
+
+      /* There are just a few bytes to copy.  Use byte memory operations.  */
+      BYTE_COPY_FWD (dstp, srcp, len);
+    }
+  else
+    {
+      /* Copy from the end to the beginning.  */
+      srcp += len;
+      dstp += len;
+
+      /* If there not too few bytes to copy, use word copy.  */
+      if (len >= OP_T_THRES)
+       {
+         /* Copy just a few bytes to make DSTP aligned.  */
+         len -= dstp % OPSIZ;
+         BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ);
+
+         /* Copy from SRCP to DSTP taking advantage of the known
+            alignment of DSTP.  Number of bytes remaining is put
+            in the third argument, i.e. in LEN.  This number may
+            vary from machine to machine.  */
+
+         WORD_COPY_BWD (dstp, srcp, len, len);
+
+         /* Fall out and copy the tail.  */
+       }
+
+      /* There are just a few bytes to copy.  Use byte memory operations.  */
+      BYTE_COPY_BWD (dstp, srcp, len);
+    }
+
+  return dest;
+}
diff --git a/sysdeps/generic/mempcpy_chk.c b/sysdeps/generic/mempcpy_chk.c
new file mode 100644 (file)
index 0000000..5297bba
--- /dev/null
@@ -0,0 +1,67 @@
+/* Copy memory to memory until the specified number of bytes
+   has been copied, return pointer to following byte, with error checking.
+   Overlap is NOT handled correctly.
+   Copyright (C) 1991, 1997, 1998, 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Torbjorn Granlund (tege@sics.se).
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include <memcopy.h>
+#include <pagecopy.h>
+
+void *
+__mempcpy_chk (dstpp, srcpp, len, dstlen)
+     void *dstpp;
+     const void *srcpp;
+     size_t len;
+     size_t dstlen;
+{
+  if (__builtin_expect (dstlen < len, 0))
+    __chk_fail ();
+
+  unsigned long int dstp = (long int) dstpp;
+  unsigned long int srcp = (long int) srcpp;
+
+  /* Copy from the beginning to the end.  */
+
+  /* If there not too few bytes to copy, use word copy.  */
+  if (len >= OP_T_THRES)
+    {
+      /* Copy just a few bytes to make DSTP aligned.  */
+      len -= (-dstp) % OPSIZ;
+      BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);
+
+      /* Copy whole pages from SRCP to DSTP by virtual address manipulation,
+        as much as possible.  */
+
+      PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);
+
+      /* Copy from SRCP to DSTP taking advantage of the known alignment of
+        DSTP.  Number of bytes remaining is put in the third argument,
+        i.e. in LEN.  This number may vary from machine to machine.  */
+
+      WORD_COPY_FWD (dstp, srcp, len, len);
+
+      /* Fall out and copy the tail.  */
+    }
+
+  /* There are just a few bytes to copy.  Use byte memory operations.  */
+  BYTE_COPY_FWD (dstp, srcp, len);
+
+  return (void *) dstp;
+}
diff --git a/sysdeps/generic/memset_chk.c b/sysdeps/generic/memset_chk.c
new file mode 100644 (file)
index 0000000..c311914
--- /dev/null
@@ -0,0 +1,92 @@
+/* Copyright (C) 1991, 1997, 2003, 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include <memcopy.h>
+
+void *
+__memset_chk (dstpp, c, len, dstlen)
+     void *dstpp;
+     int c;
+     size_t len;
+     size_t dstlen;
+{
+  if (__builtin_expect (dstlen < len, 0))
+    __chk_fail ();
+
+  long int dstp = (long int) dstpp;
+
+  if (len >= 8)
+    {
+      size_t xlen;
+      op_t cccc;
+
+      cccc = (unsigned char) c;
+      cccc |= cccc << 8;
+      cccc |= cccc << 16;
+      if (OPSIZ > 4)
+       /* Do the shift in two steps to avoid warning if long has 32 bits.  */
+       cccc |= (cccc << 16) << 16;
+
+      /* There are at least some bytes to set.
+        No need to test for LEN == 0 in this alignment loop.  */
+      while (dstp % OPSIZ != 0)
+       {
+         ((byte *) dstp)[0] = c;
+         dstp += 1;
+         len -= 1;
+       }
+
+      /* Write 8 `op_t' per iteration until less than 8 `op_t' remain.  */
+      xlen = len / (OPSIZ * 8);
+      while (xlen > 0)
+       {
+         ((op_t *) dstp)[0] = cccc;
+         ((op_t *) dstp)[1] = cccc;
+         ((op_t *) dstp)[2] = cccc;
+         ((op_t *) dstp)[3] = cccc;
+         ((op_t *) dstp)[4] = cccc;
+         ((op_t *) dstp)[5] = cccc;
+         ((op_t *) dstp)[6] = cccc;
+         ((op_t *) dstp)[7] = cccc;
+         dstp += 8 * OPSIZ;
+         xlen -= 1;
+       }
+      len %= OPSIZ * 8;
+
+      /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain.  */
+      xlen = len / OPSIZ;
+      while (xlen > 0)
+       {
+         ((op_t *) dstp)[0] = cccc;
+         dstp += OPSIZ;
+         xlen -= 1;
+       }
+      len %= OPSIZ;
+    }
+
+  /* Write the last few bytes.  */
+  while (len > 0)
+    {
+      ((byte *) dstp)[0] = c;
+      dstp += 1;
+      len -= 1;
+    }
+
+  return dstpp;
+}
diff --git a/sysdeps/generic/readonly-area.c b/sysdeps/generic/readonly-area.c
new file mode 100644 (file)
index 0000000..df5b960
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Return 1 if the whole area PTR .. PTR+SIZE is not writable.
+   Return -1 if it is writable.  */
+
+#include <stdlib.h>
+
+int
+__readonly_str (const void *ptr, size_t size)
+{
+  /* The conservative answer is that all strings are writable.  */
+  return -1;
+}
diff --git a/sysdeps/generic/stpcpy_chk.c b/sysdeps/generic/stpcpy_chk.c
new file mode 100644 (file)
index 0000000..dacda01
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 1992, 1995, 1997, 2002, 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+
+/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST.  */
+char *
+__stpcpy_chk (dest, src, destlen)
+     char *dest;
+     const char *src;
+     size_t destlen;
+{
+  register char *d = dest;
+  register const char *s = src;
+
+  do
+    {
+      if (__builtin_expect (destlen-- == 0, 0))
+       __chk_fail ();
+      *d++ = *s;
+    }
+  while (*s++ != '\0');
+
+  return d - 1;
+}
diff --git a/sysdeps/generic/strcat_chk.c b/sysdeps/generic/strcat_chk.c
new file mode 100644 (file)
index 0000000..b3fb347
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright (C) 1991, 1997, 2003, 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include <memcopy.h>
+
+
+/* Append SRC on the end of DEST.  */
+char *
+__strcat_chk (dest, src, destlen)
+     char *dest;
+     const char *src;
+     size_t destlen;
+{
+  char *s1 = dest;
+  const char *s2 = src;
+  reg_char c;
+
+  /* Find the end of the string.  */
+  do
+    {
+      if (__builtin_expect (destlen-- == 0, 0))
+       __chk_fail ();
+      c = *s1++;
+    }
+  while (c != '\0');
+
+  /* Make S1 point before the next character, so we can increment
+     it while memory is read (wins on pipelined cpus).  */
+  ++destlen;
+  s1 -= 2;
+
+  do
+    {
+      if (__builtin_expect (destlen-- == 0, 0))
+       __chk_fail ();
+      c = *s2++;
+      *++s1 = c;
+    }
+  while (c != '\0');
+
+  return dest;
+}
diff --git a/sysdeps/generic/strcpy_chk.c b/sysdeps/generic/strcpy_chk.c
new file mode 100644 (file)
index 0000000..5c1ae44
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 1991, 1997, 2000, 2003, 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stddef.h>
+#include <string.h>
+#include <memcopy.h>
+
+#undef strcpy
+
+/* Copy SRC to DEST with checking of destination buffer overflow.  */
+char *
+__strcpy_chk (dest, src, destlen)
+     char *dest;
+     const char *src;
+     size_t destlen;
+{
+  reg_char c;
+  char *s = (char *) src;
+  const ptrdiff_t off = dest - s - 1;
+
+  do
+    {
+      if (__builtin_expect (destlen-- == 0, 0))
+       __chk_fail ();
+      c = *s++;
+      s[off] = c;
+    }
+  while (c != '\0');
+
+  return dest;
+}
diff --git a/sysdeps/generic/strncat_chk.c b/sysdeps/generic/strncat_chk.c
new file mode 100644 (file)
index 0000000..953b435
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (C) 1991, 1997, 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+
+#include <memcopy.h>
+
+
+char *
+__strncat_chk (s1, s2, n, s1len)
+     char *s1;
+     const char *s2;
+     size_t n;
+     size_t s1len;
+{
+  reg_char c;
+  char *s = s1;
+
+  /* Find the end of S1.  */
+  do
+    {
+      if (__builtin_expect (s1len-- == 0, 0))
+       __chk_fail ();
+      c = *s1++;
+    }
+  while (c != '\0');
+
+  /* Make S1 point before next character, so we can increment
+     it while memory is read (wins on pipelined cpus).  */
+  ++s1len;
+  s1 -= 2;
+
+  if (n >= 4)
+    {
+      size_t n4 = n >> 2;
+      do
+       {
+         if (__builtin_expect (s1len-- == 0, 0))
+           __chk_fail ();
+         c = *s2++;
+         *++s1 = c;
+         if (c == '\0')
+           return s;
+         if (__builtin_expect (s1len-- == 0, 0))
+           __chk_fail ();
+         c = *s2++;
+         *++s1 = c;
+         if (c == '\0')
+           return s;
+         if (__builtin_expect (s1len-- == 0, 0))
+           __chk_fail ();
+         c = *s2++;
+         *++s1 = c;
+         if (c == '\0')
+           return s;
+         if (__builtin_expect (s1len-- == 0, 0))
+           __chk_fail ();
+         c = *s2++;
+         *++s1 = c;
+         if (c == '\0')
+           return s;
+       } while (--n4 > 0);
+      n &= 3;
+    }
+
+  while (n > 0)
+    {
+      if (__builtin_expect (s1len-- == 0, 0))
+       __chk_fail ();
+      c = *s2++;
+      *++s1 = c;
+      if (c == '\0')
+       return s;
+      n--;
+    }
+
+  if (c != '\0')
+    {
+      if (__builtin_expect (s1len-- == 0, 0))
+       __chk_fail ();
+      *++s1 = '\0';
+    }
+
+  return s;
+}
diff --git a/sysdeps/generic/strncpy_chk.c b/sysdeps/generic/strncpy_chk.c
new file mode 100644 (file)
index 0000000..bdede77
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (C) 1991, 1997, 2003, 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include <memcopy.h>
+
+
+char *
+__strncpy_chk (s1, s2, n, s1len)
+     char *s1;
+     const char *s2;
+     size_t n;
+     size_t s1len;
+{
+  reg_char c;
+  char *s = s1;
+
+  if (__builtin_expect (s1len < n, 0))
+    __chk_fail ();
+
+  --s1;
+
+  if (n >= 4)
+    {
+      size_t n4 = n >> 2;
+
+      for (;;)
+       {
+         c = *s2++;
+         *++s1 = c;
+         if (c == '\0')
+           break;
+         c = *s2++;
+         *++s1 = c;
+         if (c == '\0')
+           break;
+         c = *s2++;
+         *++s1 = c;
+         if (c == '\0')
+           break;
+         c = *s2++;
+         *++s1 = c;
+         if (c == '\0')
+           break;
+         if (--n4 == 0)
+           goto last_chars;
+       }
+      n = n - (s1 - s) - 1;
+      if (n == 0)
+       return s;
+      goto zero_fill;
+    }
+
+ last_chars:
+  n &= 3;
+  if (n == 0)
+    return s;
+
+  do
+    {
+      c = *s2++;
+      *++s1 = c;
+      if (--n == 0)
+       return s;
+    }
+  while (c != '\0');
+
+ zero_fill:
+  do
+    *++s1 = '\0';
+  while (--n > 0);
+
+  return s;
+}
index 865967c..00e84ec 100644 (file)
@@ -1,7 +1,7 @@
 /* Copy memory block and return pointer to beginning of destination block
    For Intel 80x86, x>=6.
    This file is part of the GNU C Library.
-   Copyright (C) 1999, 2000, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
 
    The GNU C Library is free software; you can redistribute it and/or
 #define LEN    SRC+PTR_SIZE
 
        .text
+#if defined PIC && !defined NOT_IN_libc
+ENTRY (__memcpy_chk)
+       movl    12(%esp), %eax
+       cmpl    %eax, 16(%esp)
+       jb      HIDDEN_JUMPTARGET (__chk_fail)
+END (__memcpy_chk)
+#endif
 ENTRY (BP_SYM (memcpy))
        ENTER
 
diff --git a/sysdeps/i386/i686/memcpy_chk.S b/sysdeps/i386/i686/memcpy_chk.S
new file mode 100644 (file)
index 0000000..561263f
--- /dev/null
@@ -0,0 +1,35 @@
+/* Checking memcpy for x86-64.
+   Copyright (C) 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+
+#ifndef PIC
+       /* For libc.so this is defined in memcpy.S.
+          For libc.a, this is a separate source to avoid
+          memcpy bringing in __chk_fail and all routines
+          it calls.  */
+        .text
+ENTRY (__memcpy_chk)
+       movl    12(%esp), %eax
+       cmpl    %eax, 16(%esp)
+       jb      __chk_fail
+       jmp     memcpy
+END (__memcpy_chk)
+#endif
index 421b4ef..951e139 100644 (file)
@@ -1,7 +1,7 @@
 /* Copy memory block and return pointer to beginning of destination block
    For Intel 80x86, x>=6.
    This file is part of the GNU C Library.
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 2003.
 
    The GNU C Library is free software; you can redistribute it and/or
 #define LEN    SRC+PTR_SIZE
 
        .text
+#if defined PIC && !defined NOT_IN_libc
+ENTRY (__memmove_chk)
+       movl    12(%esp), %eax
+       cmpl    %eax, 16(%esp)
+       jb      HIDDEN_JUMPTARGET (__chk_fail)
+END (__memmove_chk)
+#endif
 ENTRY (BP_SYM (memmove))
        ENTER
 
diff --git a/sysdeps/i386/i686/memmove_chk.S b/sysdeps/i386/i686/memmove_chk.S
new file mode 100644 (file)
index 0000000..23382ea
--- /dev/null
@@ -0,0 +1,35 @@
+/* Checking memmove for x86-64.
+   Copyright (C) 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+
+#ifndef PIC
+       /* For libc.so this is defined in memmove.S.
+          For libc.a, this is a separate source to avoid
+          memmove bringing in __chk_fail and all routines
+          it calls.  */
+        .text
+ENTRY (__memmove_chk)
+       movl    12(%esp), %eax
+       cmpl    %eax, 16(%esp)
+       jb      __chk_fail
+       jmp     memmove
+END (__memmove_chk)
+#endif
index 3ea89d4..843a358 100644 (file)
 #define LEN    SRC+PTR_SIZE
 
        .text
+#if defined PIC && !defined NOT_IN_libc
+ENTRY (__mempcpy_chk)
+       movl    12(%esp), %eax
+       cmpl    %eax, 16(%esp)
+       jb      HIDDEN_JUMPTARGET (__chk_fail)
+END (__mempcpy_chk)
+#endif
 ENTRY (BP_SYM (__mempcpy))
        ENTER
 
diff --git a/sysdeps/i386/i686/mempcpy_chk.S b/sysdeps/i386/i686/mempcpy_chk.S
new file mode 100644 (file)
index 0000000..dc9c609
--- /dev/null
@@ -0,0 +1,35 @@
+/* Checking mempcpy for x86-64.
+   Copyright (C) 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+
+#ifndef PIC
+       /* For libc.so this is defined in mempcpy.S.
+          For libc.a, this is a separate source to avoid
+          mempcpy bringing in __chk_fail and all routines
+          it calls.  */
+        .text
+ENTRY (__mempcpy_chk)
+       movl    12(%esp), %eax
+       cmpl    %eax, 16(%esp)
+       jb      __chk_fail
+       jmp     mempcpy
+END (__mempcpy_chk)
+#endif
index 4ddcb39..561188f 100644 (file)
 #endif
 
         .text
+#if defined PIC && !defined NOT_IN_libc && !BZERO_P
+ENTRY (__memset_chk)
+       movl    12(%esp), %eax
+       cmpl    %eax, 16(%esp)
+       jb      HIDDEN_JUMPTARGET (__chk_fail)
+END (__memset_chk)
+#endif
 ENTRY (BP_SYM (memset))
        ENTER
 
diff --git a/sysdeps/i386/i686/memset_chk.S b/sysdeps/i386/i686/memset_chk.S
new file mode 100644 (file)
index 0000000..d178654
--- /dev/null
@@ -0,0 +1,35 @@
+/* Checking memset for x86-64.
+   Copyright (C) 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+
+#ifndef PIC
+       /* For libc.so this is defined in memset.S.
+          For libc.a, this is a separate source to avoid
+          memset bringing in __chk_fail and all routines
+          it calls.  */
+        .text
+ENTRY (__memset_chk)
+       movl    12(%esp), %eax
+       cmpl    %eax, 16(%esp)
+       jb      __chk_fail
+       jmp     memset
+END (__memset_chk)
+#endif
diff --git a/sysdeps/unix/sysv/linux/readonly-area.c b/sysdeps/unix/sysv/linux/readonly-area.c
new file mode 100644 (file)
index 0000000..ce5321b
--- /dev/null
@@ -0,0 +1,90 @@
+/* Copyright (C) 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libio/libioP.h"
+
+/* Return 1 if the whole area PTR .. PTR+SIZE is not writable.
+   Return -1 if it is writable.  */
+
+int
+__readonly_area (const char *ptr, size_t size)
+{
+  const void *ptr_end = ptr + size;
+
+  FILE *fp = fopen ("/proc/self/maps", "rc");
+  if (fp == NULL)
+    return -1;
+
+  /* We need no locking.  */
+  __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+  char *line = NULL;
+  size_t linelen = 0;
+
+  while (! feof_unlocked (fp))
+    {
+      if (_IO_getdelim (&line, &linelen, '\n', fp) <= 0)
+       break;
+
+      char *p;
+      uintptr_t from = strtoul (line, &p, 16);
+
+      if (p == line || *p++ != '-')
+       break;
+
+      char *q;
+      uintptr_t to = strtoul (p, &q, 16);
+
+      if (q == p || *q++ != ' ')
+       break;
+
+      if (from < (uintptr_t) ptr_end && to > (uintptr_t) ptr)
+       {
+         /* Found an entry that at least partially covers the area.  */
+         if (*q++ != 'r' || *q++ != '-')
+           break;
+
+         if (from <= (uintptr_t) ptr && to >= (uintptr_t) ptr_end)
+           {
+             size = 0;
+             break;
+           }
+         else if (from <= (uintptr_t) ptr)
+           size -= to - (uintptr_t) ptr;
+         else if (to >= (uintptr_t) ptr_end)
+           size -= (uintptr_t) ptr_end - from;
+         else
+           size -= to - from;
+
+         if (!size)
+           break;
+       }
+    }
+
+  fclose (fp);
+  free (line);
+
+  /* If the whole area between ptr and ptr_end is covered by read-only
+     VMAs, return 1.  Otherwise return -1.  */
+  return size == 0 ? 1 : -1;
+}
index de47688..5f06198 100644 (file)
 #define MEMPCPY_P (defined memcpy)
 
         .text
+#if defined PIC && !defined NOT_IN_libc
+ENTRY (__memcpy_chk)
+       cmpq    %rdx, %rcx
+       jb      HIDDEN_JUMPTARGET (__chk_fail)
+END (__memcpy_chk)
+#endif
 ENTRY (BP_SYM (memcpy))
        /* Cutoff for the big loop is a size of 32 bytes since otherwise
           the loop will never be entered.  */
diff --git a/sysdeps/x86_64/memcpy_chk.S b/sysdeps/x86_64/memcpy_chk.S
new file mode 100644 (file)
index 0000000..c5251ea
--- /dev/null
@@ -0,0 +1,34 @@
+/* Checking memcpy for x86-64.
+   Copyright (C) 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+
+#ifndef PIC
+       /* For libc.so this is defined in memcpy.S.
+          For libc.a, this is a separate source to avoid
+          memcpy bringing in __chk_fail and all routines
+          it calls.  */
+        .text
+ENTRY (__memcpy_chk)
+       cmpq    %rdx, %rcx
+       jb      __chk_fail
+       jmp     memcpy
+END (__memcpy_chk)
+#endif
index 03aa743..4558a16 100644 (file)
@@ -1,4 +1,5 @@
 #define memcpy __mempcpy
+#define __memcpy_chk __mempcpy_chk
 #include <sysdeps/x86_64/memcpy.S>
 
 libc_hidden_def (BP_SYM (__mempcpy))
diff --git a/sysdeps/x86_64/mempcpy_chk.S b/sysdeps/x86_64/mempcpy_chk.S
new file mode 100644 (file)
index 0000000..c333a4a
--- /dev/null
@@ -0,0 +1,34 @@
+/* Checking mempcpy for x86-64.
+   Copyright (C) 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+
+#ifndef PIC
+       /* For libc.so this is defined in memcpy.S.
+          For libc.a, this is a separate source to avoid
+          mempcpy bringing in __chk_fail and all routines
+          it calls.  */
+        .text
+ENTRY (__mempcpy_chk)
+       cmpq    %rdx, %rcx
+       jb      __chk_fail
+       jmp     mempcpy
+END (__mempcpy_chk)
+#endif
index 29afa63..6c47f4c 100644 (file)
@@ -1,6 +1,6 @@
 /* memset/bzero -- set memory area to CH/0
    Optimized version for x86-64.
-   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Jaeger <aj@suse.de>.
 
 #define LARGE $120000
 
         .text
+#if !BZERO_P && defined PIC && !defined NOT_IN_libc
+ENTRY (__memset_chk)
+       cmpq    %rdx, %rcx
+       jb      HIDDEN_JUMPTARGET (__chk_fail)
+END (__memset_chk)
+#endif
 ENTRY (memset)
 #if BZERO_P
        mov     %rsi,%rdx       /* Adjust parameter.  */
diff --git a/sysdeps/x86_64/memset_chk.S b/sysdeps/x86_64/memset_chk.S
new file mode 100644 (file)
index 0000000..e62cb58
--- /dev/null
@@ -0,0 +1,34 @@
+/* Checking memset for x86-64.
+   Copyright (C) 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+
+#ifndef PIC
+       /* For libc.so this is defined in memset.S.
+          For libc.a, this is a separate source to avoid
+          memset bringing in __chk_fail and all routines
+          it calls.  */
+        .text
+ENTRY (__memset_chk)
+       cmpq    %rdx, %rcx
+       jb      __chk_fail
+       jmp     memset
+END (__memset_chk)
+#endif
diff --git a/sysdeps/x86_64/stpcpy_chk.S b/sysdeps/x86_64/stpcpy_chk.S
new file mode 100644 (file)
index 0000000..905e8d7
--- /dev/null
@@ -0,0 +1,3 @@
+#define USE_AS_STPCPY_CHK
+#define STRCPY_CHK __stpcpy_chk
+#include <sysdeps/x86_64/strcpy_chk.S>
diff --git a/sysdeps/x86_64/strcpy_chk.S b/sysdeps/x86_64/strcpy_chk.S
new file mode 100644 (file)
index 0000000..3643315
--- /dev/null
@@ -0,0 +1,211 @@
+/* strcpy/stpcpy checking implementation for x86-64.
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Andreas Jaeger <aj@suse.de>, 2002.
+   Adopted into checking version by Jakub Jelinek <jakub@redhat.com>.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+#include "bp-sym.h"
+#include "bp-asm.h"
+
+#ifndef USE_AS_STPCPY_CHK
+# define STRCPY_CHK __strcpy_chk
+#endif
+
+       .text
+ENTRY (STRCPY_CHK)
+       movq    %rsi, %rcx      /* Source register. */
+       andl    $7, %ecx        /* mask alignment bits */
+#ifndef USE_AS_STPCPY_CHK
+       movq    %rdi, %r10      /* Duplicate destination pointer.  */
+#endif
+       jz 5f                   /* aligned => start loop */
+
+       cmpq    $8, %rdx        /* Check if only few bytes left in
+                                  destination.  */
+       jb      50f
+
+       subq    $8, %rcx        /* We need to align to 8 bytes.  */
+       addq    %rcx, %rdx      /* Subtract count of stored bytes
+                                  in the cycle below from destlen.  */
+
+       /* Search the first bytes directly.  */
+0:
+       movb    (%rsi), %al     /* Fetch a byte */
+       testb   %al, %al        /* Is it NUL? */
+       movb    %al, (%rdi)     /* Store it */
+       jz      4f              /* If it was NUL, done! */
+       incq    %rsi
+       incq    %rdi
+       incl    %ecx
+       jnz     0b
+
+5:
+       movq $0xfefefefefefefeff,%r8
+       cmpq    $32, %rdx       /* Are there enough bytes in destination
+                                  for the next unrolled round?  */
+       jb      60f             /* If not, avoid the unrolled loop.  */
+
+       /* Now the sources is aligned.  Unfortunatly we cannot force
+          to have both source and destination aligned, so ignore the
+          alignment of the destination.  */
+       .p2align 4
+1:
+       /* 1st unroll.  */
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     3f              /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     3f              /* found NUL => return pointer */
+
+       movq    %rax, (%rdi)    /* Write value to destination.  */
+       addq    $8, %rdi        /* Adjust pointer.  */
+
+       /* 2nd unroll.  */
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     3f              /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     3f              /* found NUL => return pointer */
+
+       movq    %rax, (%rdi)    /* Write value to destination.  */
+       addq    $8, %rdi        /* Adjust pointer.  */
+
+       /* 3rd unroll.  */
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     3f              /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     3f              /* found NUL => return pointer */
+
+       movq    %rax, (%rdi)    /* Write value to destination.  */
+       addq    $8, %rdi        /* Adjust pointer.  */
+
+       /* 4th unroll.  */
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     3f              /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     3f              /* found NUL => return pointer */
+
+       subq    $32, %rdx       /* Adjust destlen.  */
+       movq    %rax, (%rdi)    /* Write value to destination.  */
+       addq    $8, %rdi        /* Adjust pointer.  */
+       cmpq    $32, %rdx       /* Are there enough bytes in destination
+                                  for the next unrolled round?  */
+       jae     1b              /* Next iteration.  */
+
+60:
+       cmpq    $8, %rdx        /* Are there enough bytes in destination
+                                  for the next unrolled round?  */
+       jb      50f             /* Now, copy and check byte by byte.  */
+
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     3f              /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     3f              /* found NUL => return pointer */
+
+       subq    $8, %rdx        /* Adjust destlen.  */
+       movq    %rax, (%rdi)    /* Write value to destination.  */
+       addq    $8, %rdi        /* Adjust pointer.  */
+       jmp     60b             /* Next iteration.  */
+
+       /* Do the last few bytes. %rax contains the value to write.
+          The loop is unrolled twice.  */
+       .p2align 4
+3:
+       /* Note that stpcpy needs to return with the value of the NUL
+          byte.  */
+       movb    %al, (%rdi)     /* 1st byte.  */
+       testb   %al, %al        /* Is it NUL.  */
+       jz      4f              /* yes, finish.  */
+       incq    %rdi            /* Increment destination.  */
+       movb    %ah, (%rdi)     /* 2nd byte.  */
+       testb   %ah, %ah        /* Is it NUL?.  */
+       jz      4f              /* yes, finish.  */
+       incq    %rdi            /* Increment destination.  */
+       shrq    $16, %rax       /* Shift...  */
+       jmp     3b              /* and look at next two bytes in %rax.  */
+
+51:
+       /* Search the bytes directly, checking for overflows.  */
+       incq    %rsi
+       incq    %rdi
+       decq    %rdx
+       jz      HIDDEN_JUMPTARGET (__chk_fail)
+52:
+       movb    (%rsi), %al     /* Fetch a byte */
+       testb   %al, %al        /* Is it NUL? */
+       movb    %al, (%rdi)     /* Store it */
+       jnz     51b             /* If it was NUL, done! */
+4:
+#ifdef USE_AS_STPCPY_CHK
+       movq    %rdi, %rax      /* Destination is return value.  */
+#else
+       movq    %r10, %rax      /* Source is return value.  */
+#endif
+       retq
+
+50:
+       testq   %rdx, %rdx
+       jnz     52b
+       jmp     HIDDEN_JUMPTARGET (__chk_fail)
+
+END (STRCPY_CHK)