aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog119
-rw-r--r--argp/argp-fs-xinl.c4
-rw-r--r--argp/argp-xinl.c4
-rw-r--r--debug/Makefile23
-rw-r--r--debug/Versions8
-rw-r--r--debug/chk_fail.c38
-rw-r--r--debug/fprintf_chk.c45
-rw-r--r--debug/gets_chk.c77
-rw-r--r--debug/printf_chk.c45
-rw-r--r--debug/snprintf_chk.c38
-rw-r--r--debug/sprintf_chk.c35
-rw-r--r--debug/test-stpcpy_chk.c46
-rw-r--r--debug/test-strcpy_chk.c370
-rw-r--r--debug/tst-chk1.c466
-rw-r--r--debug/tst-chk2.c2
-rw-r--r--debug/tst-chk3.c2
-rw-r--r--debug/vfprintf_chk.c42
-rw-r--r--debug/vprintf_chk.c42
-rw-r--r--debug/vsnprintf_chk.c70
-rw-r--r--debug/vsprintf_chk.c91
-rw-r--r--elf/dl-minimal.c7
-rw-r--r--include/bits/string3.h1
-rw-r--r--include/features.h40
-rw-r--r--include/stdio.h14
-rw-r--r--include/string.h28
-rw-r--r--include/sys/cdefs.h8
-rw-r--r--libio/Makefile4
-rw-r--r--libio/bits/stdio2.h78
-rw-r--r--libio/libio.h3
-rw-r--r--libio/stdio.h3
-rw-r--r--libio/strfile.h10
-rw-r--r--libio/vsnprintf.c12
-rw-r--r--libio/vswprintf.c8
-rw-r--r--misc/sys/cdefs.h5
-rw-r--r--stdio-common/vfprintf.c19
-rw-r--r--string/Makefile2
-rw-r--r--string/bits/string3.h167
-rw-r--r--string/string.h5
-rw-r--r--sysdeps/generic/memcpy_chk.c66
-rw-r--r--sysdeps/generic/memmove_chk.c98
-rw-r--r--sysdeps/generic/mempcpy_chk.c67
-rw-r--r--sysdeps/generic/memset_chk.c92
-rw-r--r--sysdeps/generic/readonly-area.c29
-rw-r--r--sysdeps/generic/stpcpy_chk.c45
-rw-r--r--sysdeps/generic/strcat_chk.c58
-rw-r--r--sysdeps/generic/strcpy_chk.c46
-rw-r--r--sysdeps/generic/strncat_chk.c100
-rw-r--r--sysdeps/generic/strncpy_chk.c89
-rw-r--r--sysdeps/i386/i686/memcpy.S9
-rw-r--r--sysdeps/i386/i686/memcpy_chk.S35
-rw-r--r--sysdeps/i386/i686/memmove.S9
-rw-r--r--sysdeps/i386/i686/memmove_chk.S35
-rw-r--r--sysdeps/i386/i686/mempcpy.S7
-rw-r--r--sysdeps/i386/i686/mempcpy_chk.S35
-rw-r--r--sysdeps/i386/i686/memset.S7
-rw-r--r--sysdeps/i386/i686/memset_chk.S35
-rw-r--r--sysdeps/unix/sysv/linux/readonly-area.c90
-rw-r--r--sysdeps/x86_64/memcpy.S6
-rw-r--r--sysdeps/x86_64/memcpy_chk.S34
-rw-r--r--sysdeps/x86_64/mempcpy.S1
-rw-r--r--sysdeps/x86_64/mempcpy_chk.S34
-rw-r--r--sysdeps/x86_64/memset.S8
-rw-r--r--sysdeps/x86_64/memset_chk.S34
-rw-r--r--sysdeps/x86_64/stpcpy_chk.S3
-rw-r--r--sysdeps/x86_64/strcpy_chk.S211
65 files changed, 3220 insertions, 44 deletions
diff --git a/ChangeLog b/ChangeLog
index d610e693d7..4b52d54a0a 100644
--- 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.
diff --git a/argp/argp-fs-xinl.c b/argp/argp-fs-xinl.c
index 21f9bd9f71..3cf1f9827d 100644
--- a/argp/argp-fs-xinl.c
+++ b/argp/argp-fs-xinl.c
@@ -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
diff --git a/argp/argp-xinl.c b/argp/argp-xinl.c
index 2431093ea3..73177585e8 100644
--- a/argp/argp-xinl.c
+++ b/argp/argp-xinl.c
@@ -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. */
diff --git a/debug/Makefile b/debug/Makefile
index aba98926da..fed60d78b5 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -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)
diff --git a/debug/Versions b/debug/Versions
index c2b6396d82..07d6fbb830 100644
--- a/debug/Versions
+++ b/debug/Versions
@@ -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
index 0000000000..48848fbe35
--- /dev/null
+++ b/debug/chk_fail.c
@@ -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
index 0000000000..77508b902e
--- /dev/null
+++ b/debug/fprintf_chk.c
@@ -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
index 0000000000..3715a39672
--- /dev/null
+++ b/debug/gets_chk.c
@@ -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
index 0000000000..d2b387323d
--- /dev/null
+++ b/debug/printf_chk.c
@@ -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
index 0000000000..5a77afef29
--- /dev/null
+++ b/debug/snprintf_chk.c
@@ -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
index 0000000000..d141633b9f
--- /dev/null
+++ b/debug/sprintf_chk.c
@@ -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
index 0000000000..d717ca7363
--- /dev/null
+++ b/debug/test-stpcpy_chk.c
@@ -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
index 0000000000..4c61f4fb43
--- /dev/null
+++ b/debug/test-strcpy_chk.c
@@ -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
index 0000000000..639da3847c
--- /dev/null
+++ b/debug/tst-chk1.c
@@ -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
index 0000000000..be37ce2d22
--- /dev/null
+++ b/debug/tst-chk2.c
@@ -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
index 0000000000..38b8e4fb36
--- /dev/null
+++ b/debug/tst-chk3.c
@@ -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
index 0000000000..a9e107d8e5
--- /dev/null
+++ b/debug/vfprintf_chk.c
@@ -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
index 0000000000..f477f15411
--- /dev/null
+++ b/debug/vprintf_chk.c
@@ -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
index 0000000000..850cd5af5a
--- /dev/null
+++ b/debug/vsnprintf_chk.c
@@ -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
index 0000000000..83383286da
--- /dev/null
+++ b/debug/vsprintf_chk.c
@@ -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)
diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c
index 4ec2ebcbb4..adb85e6753 100644
--- a/elf/dl-minimal.c
+++ b/elf/dl-minimal.c
@@ -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
index 0000000000..1ddd981a90
--- /dev/null
+++ b/include/bits/string3.h
@@ -0,0 +1 @@
+#include <string/bits/string3.h>
diff --git a/include/features.h b/include/features.h
index 59ae3c4d13..8b03e165f9 100644
--- a/include/features.h
+++ b/include/features.h
@@ -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
@@ -101,6 +104,7 @@
#undef __USE_MISC
#undef __USE_GNU
#undef __USE_REENTRANT
+#undef __USE_FORTIFY_LEVEL
#undef __FAVOR_BSD
#undef __KERNEL_STRICT_NAMES
@@ -113,6 +117,20 @@
/* 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 && \
@@ -244,6 +262,14 @@
# 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
@@ -265,20 +291,6 @@
#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))
diff --git a/include/stdio.h b/include/stdio.h
index b871abc15e..05a91b4cb3 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -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\
diff --git a/include/string.h b/include/string.h
index afc6adfbda..738dd8e27c 100644
--- a/include/string.h
+++ b/include/string.h
@@ -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
diff --git a/include/sys/cdefs.h b/include/sys/cdefs.h
index 200abb4f02..8ba980477d 100644
--- a/include/sys/cdefs.h
+++ b/include/sys/cdefs.h
@@ -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
diff --git a/libio/Makefile b/libio/Makefile
index c7253ff571..a9384b55a9 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -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
index 0000000000..acf07ea91b
--- /dev/null
+++ b/libio/bits/stdio2.h
@@ -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)))
diff --git a/libio/libio.h b/libio/libio.h
index 1672f7b54f..645f9fb83c 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -139,6 +139,9 @@
#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
diff --git a/libio/stdio.h b/libio/stdio.h
index 599094296a..e1081c9039 100644
--- a/libio/stdio.h
+++ b/libio/stdio.h
@@ -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
diff --git a/libio/strfile.h b/libio/strfile.h
index bcac784717..b91111a9d6 100644
--- a/libio/strfile.h
+++ b/libio/strfile.h
@@ -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;
diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c
index e2cfb16d8a..4250c2d2de 100644
--- a/libio/vsnprintf.c
+++ b/libio/vsnprintf.c
@@ -28,16 +28,6 @@
#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),
diff --git a/libio/vswprintf.c b/libio/vswprintf.c
index 3cf01e2c84..42168aade4 100644
--- a/libio/vswprintf.c
+++ b/libio/vswprintf.c
@@ -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
diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index 8894d0d5fc..475cf62961 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -127,6 +127,11 @@
#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. */
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index 38da382efa..5e480ad52b 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -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. */
diff --git a/string/Makefile b/string/Makefile
index 5ab487f5ba..66469f586e 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -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
index 0000000000..87cbe35bb1
--- /dev/null
+++ b/string/bits/string3.h
@@ -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));
+}
diff --git a/string/string.h b/string/string.h
index 4ea3a74ca7..1adf925bb0 100644
--- a/string/string.h
+++ b/string/string.h
@@ -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
index 0000000000..638cd0e4fb
--- /dev/null
+++ b/sysdeps/generic/memcpy_chk.c
@@ -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
index 0000000000..f3b74d23d9
--- /dev/null
+++ b/sysdeps/generic/memmove_chk.c
@@ -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
index 0000000000..5297bbab92
--- /dev/null
+++ b/sysdeps/generic/mempcpy_chk.c
@@ -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
index 0000000000..c311914395
--- /dev/null
+++ b/sysdeps/generic/memset_chk.c
@@ -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
index 0000000000..df5b96015c
--- /dev/null
+++ b/sysdeps/generic/readonly-area.c
@@ -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
index 0000000000..dacda0115a
--- /dev/null
+++ b/sysdeps/generic/stpcpy_chk.c
@@ -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
index 0000000000..b3fb3470b7
--- /dev/null
+++ b/sysdeps/generic/strcat_chk.c
@@ -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
index 0000000000..5c1ae44cd0
--- /dev/null
+++ b/sysdeps/generic/strcpy_chk.c
@@ -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
index 0000000000..953b435a4b
--- /dev/null
+++ b/sysdeps/generic/strncat_chk.c
@@ -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
index 0000000000..bdede7738b
--- /dev/null
+++ b/sysdeps/generic/strncpy_chk.c
@@ -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;
+}
diff --git a/sysdeps/i386/i686/memcpy.S b/sysdeps/i386/i686/memcpy.S
index 865967c5c8..00e84ec2e5 100644
--- a/sysdeps/i386/i686/memcpy.S
+++ b/sysdeps/i386/i686/memcpy.S
@@ -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
@@ -31,6 +31,13 @@
#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
index 0000000000..561263f9bf
--- /dev/null
+++ b/sysdeps/i386/i686/memcpy_chk.S
@@ -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
diff --git a/sysdeps/i386/i686/memmove.S b/sysdeps/i386/i686/memmove.S
index 421b4effda..951e139ad4 100644
--- a/sysdeps/i386/i686/memmove.S
+++ b/sysdeps/i386/i686/memmove.S
@@ -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
@@ -31,6 +31,13 @@
#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
index 0000000000..23382ea8bf
--- /dev/null
+++ b/sysdeps/i386/i686/memmove_chk.S
@@ -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
diff --git a/sysdeps/i386/i686/mempcpy.S b/sysdeps/i386/i686/mempcpy.S
index 3ea89d4a17..843a35823a 100644
--- a/sysdeps/i386/i686/mempcpy.S
+++ b/sysdeps/i386/i686/mempcpy.S
@@ -31,6 +31,13 @@
#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
index 0000000000..dc9c6095f0
--- /dev/null
+++ b/sysdeps/i386/i686/mempcpy_chk.S
@@ -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
diff --git a/sysdeps/i386/i686/memset.S b/sysdeps/i386/i686/memset.S
index 4ddcb39731..561188ffec 100644
--- a/sysdeps/i386/i686/memset.S
+++ b/sysdeps/i386/i686/memset.S
@@ -39,6 +39,13 @@
#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
index 0000000000..d178654994
--- /dev/null
+++ b/sysdeps/i386/i686/memset_chk.S
@@ -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
index 0000000000..ce5321bcef
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/readonly-area.c
@@ -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;
+}
diff --git a/sysdeps/x86_64/memcpy.S b/sysdeps/x86_64/memcpy.S
index de47688241..5f06198b5d 100644
--- a/sysdeps/x86_64/memcpy.S
+++ b/sysdeps/x86_64/memcpy.S
@@ -29,6 +29,12 @@
#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
index 0000000000..c5251ea2d4
--- /dev/null
+++ b/sysdeps/x86_64/memcpy_chk.S
@@ -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
diff --git a/sysdeps/x86_64/mempcpy.S b/sysdeps/x86_64/mempcpy.S
index 03aa743fba..4558a1699a 100644
--- a/sysdeps/x86_64/mempcpy.S
+++ b/sysdeps/x86_64/mempcpy.S
@@ -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
index 0000000000..c333a4adb3
--- /dev/null
+++ b/sysdeps/x86_64/mempcpy_chk.S
@@ -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
diff --git a/sysdeps/x86_64/memset.S b/sysdeps/x86_64/memset.S
index 29afa63e7e..6c47f4c863 100644
--- a/sysdeps/x86_64/memset.S
+++ b/sysdeps/x86_64/memset.S
@@ -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>.
@@ -32,6 +32,12 @@
#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
index 0000000000..e62cb58cc0
--- /dev/null
+++ b/sysdeps/x86_64/memset_chk.S
@@ -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
index 0000000000..905e8d7ee3
--- /dev/null
+++ b/sysdeps/x86_64/stpcpy_chk.S
@@ -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
index 0000000000..364331553a
--- /dev/null
+++ b/sysdeps/x86_64/strcpy_chk.S
@@ -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)