This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[RFC][PATCH v2] Initial support for C11 Annex K Bounds checking functions
- From: Ulrich Bayer <ubayer at sba-research dot org>
- To: <libc-alpha at sourceware dot org>
- Cc: "Joseph S. Myers" <joseph at codesourcery dot com>
- Date: Wed, 5 Jun 2013 18:15:02 +0200
- Subject: [RFC][PATCH v2] Initial support for C11 Annex K Bounds checking functions
- References: <5102DBFD dot 4060103 at sba-research dot org> <513DE7A1 dot 8080501 at sba-research dot org> <Pine dot LNX dot 4 dot 64 dot 1305151554100 dot 15900 at digraph dot polyomino dot org dot uk>
On 15.05.2013 18:11, Joseph S. Myers wrote:
> I suggest reposting a patch against current master and
> hopefully we can at least get a discussion going on it, whether or not it
> actually gets in for 2.18.
Thanks for your comments. Please find included in this mail an updated version
of my original patch (<http://sourceware.org/ml/libc-alpha/2013-03/msg00286.html>)
that also fixes the style problems you pointed out.
Btw, I would have preferred to name the subdirectory libc_s (instead of lib_s)
but when linking test executables this causes causes the actual objectname of the test executable
to get omitted when linking. I mainly followed the makefile-recipe of other modules but did
not dig any deeper at this stage.
2013-06-05 Ulrich Bayer <ubayer@sba-research.org>
* Makeconfig: Add new library libc_s.
* Versions.def: Likewise.
* bits/errno_t.h: New file.
* bits/rsize_t.h: New file.
* include/features.h: handle __STDC_WANT_LIB_EXT1__
* include/stdc-predef.h: add macro __STDC_LIB_EXT1__
* lib_s/Makefile: New file.
* lib_s/Versions: New file.
* lib_s/abort_handler_s.c: New file.
* lib_s/constraint_handler.c: New file.
* lib_s/ignore_handler_s.c: New file.
* lib_s/libc_s.h: New file.
* lib_s/strcpy_s.c: New file.
* lib_s/strnlen_s.c: New file.
* lib_s/test-lib_s.h: New file.
* lib_s/test-strcpy_s.c: New file.
* lib_s/test-strnlen_s.c: New file.
* lib_s/test-wcscpy_s.c: New file.
* lib_s/test-wcsnlen_s.c: New file.
* lib_s/txt.h: New file.
* lib_s/wcscpy_s.c: New file.
* lib_s/wcsnlen_s.c: New file.
* stdlib/errno.h: New type errno_t
* stdlib/stdlib.h
(constraint_handler_t): New type.
(set_constraint_handler_s): New prototype.
(abort_handler_s): New prototype.
(ignore_handler_s): New prototype.
* string/string.h
(strnlen_s): New prototype.
(strcpy_s): New prototype.
* sysdeps/generic/stdint.h
(RSIZE_MAX): New macro.
* wcsmbs/wchar.h:
(wcscpy_s): New prototype.
(wcsnlen_s): New prototype.
diff --git a/Makeconfig b/Makeconfig
index a3d3e70..9a54201 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -476,7 +476,7 @@ link-libc = $(link-libc-rpath-link) $(link-libc-before-gnulib) $(gnulib)
link-libc-tests = $(link-libc-tests-rpath-link) \
$(link-libc-before-gnulib) $(gnulib-tests)
# This is how to find at build-time things that will be installed there.
-rpath-dirs = math elf dlfcn nss nis rt resolv crypt
+rpath-dirs = math elf dlfcn nss nis rt resolv crypt lib_s
rpath-link = \
$(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%)))
else
@@ -1025,6 +1025,12 @@ else
libm = $(common-objpfx)math/libm.a
endif
+ifeq ($(build-shared),yes)
+libc_s = $(common-objpfx)lib_s/libc_s.so$(libc_s.so-version)
+else
+libc_s = $(common-objpfx)lib_s/libc_s.a
+endif
+
# These are the subdirectories containing the library source. The order
# is more or less arbitrary. The sorting step will take care of the
# dependencies.
@@ -1033,7 +1039,7 @@ all-subdirs = csu assert ctype locale intl catgets math setjmp signal \
grp pwd posix io termios resource misc socket sysvipc gmon \
gnulib iconv iconvdata wctype manual shadow gshadow po argp \
crypt localedata timezone rt conform debug \
- $(add-on-subdirs) dlfcn elf
+ $(add-on-subdirs) dlfcn elf lib_s
ifndef avoid-generated
# sysd-sorted itself will contain rules making the sysd-sorted target
diff --git a/Versions.def b/Versions.def
index 0462239..ab87f9d 100644
--- a/Versions.def
+++ b/Versions.def
@@ -143,3 +143,6 @@ libanl {
libcidn {
GLIBC_PRIVATE
}
+libc_s {
+ GLIBC_2.18
+}
diff --git a/bits/errno_t.h b/bits/errno_t.h
new file mode 100644
index 0000000..81e7cda
--- /dev/null
+++ b/bits/errno_t.h
@@ -0,0 +1,32 @@
+/* Definition of type errno_t as specified in Annex K of ISO C11.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#if !defined _ERRNO_H && !defined _STRING_H && !defined _STDLIB_H \
+ && !defined _STDIO_H && !defined _WCHAR_H
+# error "Never use <bits/errno_t.h> directly; include <errno.h> instead."
+#endif
+
+#ifndef _ERRNO_T
+#define _ERRNO_T
+
+/* errno_t is the type for communicating error values.
+ It may contain all of the values that might be found in errno. */
+typedef int errno_t;
+
+#endif
diff --git a/bits/rsize_t.h b/bits/rsize_t.h
new file mode 100644
index 0000000..06c3071
--- /dev/null
+++ b/bits/rsize_t.h
@@ -0,0 +1,48 @@
+/* Definition of type rsize_t as specified in Annex K of ISO C11.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#if !defined _STRING_H && !defined _STDLIB_H \
+ && !defined _STDIO_H && !defined _WCHAR_H
+# error "Never use <bits/rsize_t.h> directly; include <stddef.h> instead."
+#endif
+
+#if !defined(_RSIZE_T)
+#define _RSIZE_T
+
+/* rsize_t is a type for communicating realistic object sizes.
+ Often, large object sizes are the result of an integer overflow. To
+ detect these overflow conditions at runtime, the type rsize_t
+ restricts the maximum allowed object size. It does not allow
+ large positive numbers. rsize_t is an unsigned type. It's maximum
+ value is given by the macro RSIZE_MAX. */
+
+/* Get the definition from stddef.h. */
+#define __need_size_t
+#define __need_rsize_t
+#include <stddef.h>
+
+/* Check whether stddef.h really defined rsize_t. */
+#if defined(__GNUC__) && !defined(_GCC_RSIZE_T)
+/* GCC's stddef sets _GCC_RSIZE_T after defining rsize_t.
+ In case we are using a GCC version that does not define
+ rsize_t, we supply our own fall-back definition. */
+typedef size_t rsize_t;
+#endif
+
+#endif
diff --git a/include/features.h b/include/features.h
index ca83da0..f9b805d 100644
--- a/include/features.h
+++ b/include/features.h
@@ -45,7 +45,8 @@
_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.
-
+ __STDC_WANT_LIB_EXT1__ Includes bounds checking functions (with postfix _s)
+ specified in Annex K of ISO C11.
The `-ansi' switch to the GNU C compiler defines __STRICT_ANSI__.
If none of these are defined, the default is to have _SVID_SOURCE,
_BSD_SOURCE, and _POSIX_SOURCE set to one and _POSIX_C_SOURCE set to
@@ -81,6 +82,8 @@
__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.
+ __USE_BOUNDS_CHECKING Define the bounds checking interfaces from
+ C11 Annex K.
The macros `__GNU_LIBRARY__', `__GLIBC__', and `__GLIBC_MINOR__' are
defined by this file unconditionally. `__GNU_LIBRARY__' is provided
@@ -122,6 +125,7 @@
#undef __USE_FORTIFY_LEVEL
#undef __FAVOR_BSD
#undef __KERNEL_STRICT_NAMES
+#undef __USE_BOUNDS_CHECKING
/* Suppress kernel-name space pollution unless user expressedly asks
for it. */
@@ -192,6 +196,12 @@
# define __USE_ISOC11 1
#endif
+/* This is to enable the ISO C11 _s functions from
+ Annex K 'Bounds-checking interfaces '. */
+#if (defined __STDC_WANT_LIB_EXT1__ && __STDC_WANT_LIB_EXT1__ == 1)
+# define __USE_BOUNDS_CHECKING 1
+#endif
+
/* This is to enable the ISO C99 extension. */
#if (defined _ISOC99_SOURCE || defined _ISOC11_SOURCE \
|| (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L))
@@ -386,6 +396,4 @@
<gnu/stubs.h> contains `#define __stub_FUNCTION' when FUNCTION is a stub
that will always return failure (and set errno to ENOSYS). */
#include <gnu/stubs.h>
-
-
#endif /* features.h */
diff --git a/include/stdc-predef.h b/include/stdc-predef.h
index b9c9967..08c69f6 100644
--- a/include/stdc-predef.h
+++ b/include/stdc-predef.h
@@ -37,4 +37,7 @@
/* We do not support C11 <threads.h>. */
#define __STDC_NO_THREADS__ 1
+/* We support the optional bounds-checking interfaces specified in
+ C11 Annex K. */
+#define __STDC_LIB_EXT1__ 1
#endif
diff --git a/lib_s/Makefile b/lib_s/Makefile
new file mode 100644
index 0000000..509a5d2
--- /dev/null
+++ b/lib_s/Makefile
@@ -0,0 +1,43 @@
+# Copyright (C) 2013 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+#
+# Sub-makefile for libc_s portion of the library.
+#
+subdir := lib_s
+
+headers := bits/errno_t.h bits/rsize_t.h
+
+extra-libs := libc_s
+extra-libs-others := $(extra-libs)
+
+libc_s-routines := strnlen_s wcsnlen_s strcpy_s wcscpy_s \
+ constraint_handler abort_handler_s ignore_handler_s
+
+CFLAGS-libc_s := -D__STDC_WANT_LIB_EXT1__=1
+
+tests := test-strcpy_s test-wcscpy_s test-strnlen_s test-wcsnlen_s
+
+include ../Makeconfig
+
+include ../Rules
+
+ifeq (yes,$(build-shared))
+$(addprefix $(objpfx),$(tests)): $(objpfx)libc_s.so
+else
+$(addprefix $(objpfx),$(tests)): $(objpfx)libc_s.a
+endif
diff --git a/lib_s/Versions b/lib_s/Versions
new file mode 100644
index 0000000..04e3cf0
--- /dev/null
+++ b/lib_s/Versions
@@ -0,0 +1,16 @@
+libc_s {
+ GLIBC_2.18 {
+ # additions to stdlib.h
+ abort_handler_s;
+ ignore_handler_s;
+ set_constraint_handler_s;
+
+ # additions to string.h
+ strcpy_s;
+ strnlen_s;
+
+ # additions to wchar.h
+ wcscpy_s;
+ wcsnlen_s;
+ }
+}
diff --git a/lib_s/abort_handler_s.c b/lib_s/abort_handler_s.c
new file mode 100644
index 0000000..75b7fef
--- /dev/null
+++ b/lib_s/abort_handler_s.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <libintl.h>
+
+
+void
+abort_handler_s (const char *restrict msg, void *restrict ptr, errno_t error)
+{
+ fprintf (stderr, _("abort_handler_s was called in response to a "
+ "runtime-constraint violation.\n"));
+
+ if (msg != NULL)
+ fprintf (stderr, "%s\n", msg);
+
+ fprintf (stderr, _("\nNote to end users: This program was terminated as a"
+ "result of a bug present in the software. Please reach "
+ "out to your software's vendor to get more help.\n"));
+
+ fflush (stderr);
+ abort ();
+}
diff --git a/lib_s/constraint_handler.c b/lib_s/constraint_handler.c
new file mode 100644
index 0000000..7ecd750
--- /dev/null
+++ b/lib_s/constraint_handler.c
@@ -0,0 +1,78 @@
+/* Runtime-constraint handler related functions.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* As an exception, this module defines two functions so that
+ we can define the variable __constraint_handler as static. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libintl.h>
+#include "libc_s.h"
+
+#define RUNTIME_CONSTRAINT_MSG_MAX 1024
+
+/* Pointer to the current constraint handler. */
+static constraint_handler_t __constraint_handler = &abort_handler_s;
+
+
+void
+__invoke_constraint_handler (const char *msg,
+ const char *func,
+ const char *file, unsigned line, errno_t error)
+{
+ /* In the worst case, the msg stored in buf is truncated. */
+ char buf[RUNTIME_CONSTRAINT_MSG_MAX];
+
+ /* The C11 standard leaves it undefined whether runtime-constraint
+ violation should update the error variable. */
+ __set_errno (error);
+
+ /* To be on the safe side. */
+ if (msg == NULL)
+ msg = _("(empty message)");
+ if (func == NULL)
+ func = _("(empty functionname)");
+ if (file == NULL)
+ file = _("(empty filename)");
+
+ snprintf (buf, sizeof (buf),
+ _("The runtime-constraint violation was caused "
+ "by the following expression in function "
+ "%s:\n%s (in file %s at line %u)"), func, msg, file, line);
+
+ __constraint_handler (buf, NULL, error);
+}
+
+
+constraint_handler_t
+set_constraint_handler_s (constraint_handler_t handler)
+{
+ constraint_handler_t tmp;
+ tmp = __constraint_handler;
+
+ if (handler == NULL)
+ {
+ /* Set it back to our default handler. */
+ __constraint_handler = &abort_handler_s;
+ }
+ else
+ __constraint_handler = handler;
+
+ return tmp;
+}
diff --git a/lib_s/ignore_handler_s.c b/lib_s/ignore_handler_s.c
new file mode 100644
index 0000000..d6d6314
--- /dev/null
+++ b/lib_s/ignore_handler_s.c
@@ -0,0 +1,24 @@
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+
+void
+ignore_handler_s (const char *restrict msg, void *restrict ptr, errno_t error)
+{
+ /* Do nothing. */
+}
diff --git a/lib_s/libc_s.h b/lib_s/libc_s.h
new file mode 100644
index 0000000..778361f
--- /dev/null
+++ b/lib_s/libc_s.h
@@ -0,0 +1,112 @@
+/* Internal include-file for the functions defined in C11 Annex K
+ Bounds-checking interfaces
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LIBC_S_H
+#define _LIBC_S_H
+
+/* C11 Annex K provides alternative functions for the C library that
+ promote safer, more secure programming. The functions verify that output
+ buffers are large enough for the intended result and return a failure
+ indicator if they are not. Data is never written past the end of an array.
+ All string results are null terminated. */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/* The macro _REGIONS_OVERLAP checks whether two regions overlap. The regions
+ are defined by two base pointers s1 and s2 as well as s1_size and s2_size
+ which specify the size of the respective buffers.
+
+ First, check whether s1 points into the region [s1, s1+s1max).
+ Second, check whether the last byte of s2 is inside the region
+ [s1, s1+s1max). */
+#define _REGIONS_OVERLAP(s1, s1_size, s2, s2_size) \
+ ( ((s2 >= s1) && (s2 < (s1 + s1_size))) \
+ || ((s2 < s1) && (s2 + s2_size -1 >= s1) \
+ && (s2 + s2_size -1 < s1 + s1_size)))
+
+
+/* This function is called in case of a runtime-constraint
+ violation. Normally, instead of calling the function directly, it
+ is called indirectly via one of the _CONSTRAINT_VIOLATION macros.
+ Using the macros makes it unnecessary to provide the function, file
+ and line arguments. */
+void __invoke_constraint_handler (const char *msg,
+ const char *func,
+ const char *file,
+ unsigned line,
+ errno_t errno);
+
+
+/* Trigger a constraint violation unconditionally. */
+#define _CONSTRAINT_VIOLATION(msg, error_code, ret_code) \
+ do \
+ { \
+ __invoke_constraint_handler (msg, \
+ __FUNCTION__, \
+ __FILE__, \
+ __LINE__, \
+ error_code); \
+ return (ret_code); \
+ } \
+ while (0)
+
+/* Trigger a constraint violation in case expr is true. */
+#define _CONSTRAINT_VIOLATION_IF(expr, error_code, ret_code) \
+ do \
+ { \
+ int expr_val = expr; \
+ if (expr_val) \
+ { \
+ __invoke_constraint_handler (#expr, __FUNCTION__, __FILE__, \
+ __LINE__, error_code); \
+ return ret_code; \
+ } \
+ } \
+ while (0)
+
+/* Trigger a constraint violation in case expr is true and execute
+ the specified cleanup code.
+
+ N.B: cleanup_code is only evaluated in case of a
+ constraint violation (i.e., if expr is true). */
+#define _CONSTRAINT_VIOLATION_CLEANUP_IF(expr, cleanup_code, \
+ error_code, ret_code) \
+ do \
+ { \
+ int expr_val = expr; \
+ if (expr_val) \
+ { \
+ do \
+ { \
+ cleanup_code; /* Execute. */ \
+ } \
+ while (0); \
+ __invoke_constraint_handler (#expr, __FUNCTION__, __FILE__, \
+ __LINE__, error_code); \
+ return ret_code; \
+ } \
+ } \
+ while (0)
+
+
+
+#endif
diff --git a/lib_s/strcpy_s.c b/lib_s/strcpy_s.c
new file mode 100644
index 0000000..f7da42a
--- /dev/null
+++ b/lib_s/strcpy_s.c
@@ -0,0 +1,51 @@
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <string.h>
+#include <txt.h>
+#include "libc_s.h"
+
+#ifdef TXT_WIDECHAR
+errno_t
+wcscpy_s (wchar_t * restrict s1, rsize_t s1max, const wchar_t * restrict s2)
+#else
+errno_t
+strcpy_s (char * restrict s1, rsize_t s1max, const char * restrict s2)
+#endif
+{
+ _CONSTRAINT_VIOLATION_IF ((s1 == NULL), EINVAL, EINVAL);
+ _CONSTRAINT_VIOLATION_IF ((s1max == 0), EINVAL, EINVAL);
+ _CONSTRAINT_VIOLATION_IF ((s1max > RSIZE_MAX), EINVAL, EINVAL);
+
+ _CONSTRAINT_VIOLATION_CLEANUP_IF (s2 == NULL,
+ s1[0] = L_('\0'),
+ EINVAL, EINVAL);
+ rsize_t s2_len = STRNLEN_S (s2, s1max);
+ _CONSTRAINT_VIOLATION_CLEANUP_IF (s1max <= s2_len,
+ s1[0] = L_('\0'),
+ EINVAL, EINVAL);
+ _CONSTRAINT_VIOLATION_CLEANUP_IF (_REGIONS_OVERLAP (s1, s1max,
+ s2, s2_len + 1),
+ s1[0] = L_('\0'),
+ EINVAL, EINVAL);
+
+
+ STRNCPY (s1, s2, s1max - 1);
+ s1[s1max - 1] = L_('\0');
+
+ return 0;
+}
diff --git a/lib_s/strnlen_s.c b/lib_s/strnlen_s.c
new file mode 100644
index 0000000..54762ac
--- /dev/null
+++ b/lib_s/strnlen_s.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "libc_s.h"
+#include <string.h>
+#include <txt.h>
+
+#ifdef TXT_WIDECHAR
+size_t
+wcsnlen_s (const wchar_t * s, size_t maxsize)
+#else
+size_t
+strnlen_s (const char *s, size_t maxsize)
+#endif
+{
+ if (s == NULL)
+ return 0;
+
+ return STRNLEN (s, maxsize);
+}
diff --git a/lib_s/test-lib_s.h b/lib_s/test-lib_s.h
new file mode 100644
index 0000000..8573f12
--- /dev/null
+++ b/lib_s/test-lib_s.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _TEST_LIB_S_H
+#define _TEST_LIB_S_H
+
+#define __STDC_WANT_LIB_EXT1__ 1
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "txt.h"
+
+
+#define ASSERT_EQUAL(expected, actual) \
+ if (expected != actual) \
+ { \
+ printf("Test failure at location '%s:%d': " \
+ "%s != %s.\n", \
+ __FILE__, __LINE__, #expected, #actual); \
+ return 1; \
+ }
+
+#define ASSERT_CONSTRAINT_VIOLATION(expr) \
+ expr; \
+ if (constraint_counter == 0) \
+ { \
+ printf("Test failure at location '%s:%d': %s has not " \
+ "caused a runtime-constraint violation.\n", \
+ __FILE__, __LINE__, #expr); \
+ return 1; \
+ } \
+ constraint_counter = 0; /* reset */
+
+
+static unsigned constraint_counter = 0;
+
+static void
+test_constraint_handler (const char *restrict msg,
+ void *restrict ptr, errno_t error)
+{
+ constraint_counter++;
+}
+
+
+#endif
diff --git a/lib_s/test-strcpy_s.c b/lib_s/test-strcpy_s.c
new file mode 100644
index 0000000..aff6224
--- /dev/null
+++ b/lib_s/test-strcpy_s.c
@@ -0,0 +1,88 @@
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "test-lib_s.h"
+
+#ifdef TXT_WIDECHAR
+# define test_strcpy_s_should_copy_correct test_wcscpy_s_should_copy_correct
+# define test_strcpy_s_should_fail test_wcspy_s_should_fail
+#endif
+
+static int
+test_strcpy_s_should_copy_correct (void)
+{
+ CHAR_T s1[5];
+ const CHAR_T *s2 = L_("1234");
+
+
+ ASSERT_EQUAL (0, STRCPY_S (s1, 5, s2));
+ ASSERT_EQUAL (0, STRCMP (s1, s2));
+
+ return 0;
+}
+
+
+static int
+test_strcpy_s_should_fail (void)
+{
+ enum {LEN_S1 = 5};
+ CHAR_T s1[LEN_S1];
+ const CHAR_T *s2 = L_("1234");
+
+ /* Neither s1 nor s2 shall be a null pointer. */
+ ASSERT_CONSTRAINT_VIOLATION (STRCPY_S (NULL, LEN_S1, s2));
+ ASSERT_CONSTRAINT_VIOLATION (STRCPY_S (s1, LEN_S1, NULL));
+ /* s1max shall not equal zero. */
+ ASSERT_CONSTRAINT_VIOLATION (STRCPY_S (s1, 0, s2));
+ /* s1max shall be greater than strnlen_s(s2, s1max). */
+ ASSERT_CONSTRAINT_VIOLATION (STRCPY_S (s1, STRNLEN_S (s2, STRLEN (s2)), s2));
+
+ /* Copying shall not take place between objects that overlap. */
+ ASSERT_CONSTRAINT_VIOLATION (STRCPY_S (s1, LEN_S1, s1));
+ /* ... then strcpy_s sets s1[0] to the null character. */
+ ASSERT_EQUAL (L_('\0'), (int)s1[0]);
+
+ STRCPY_S (s1, LEN_S1, L_("ABCD"));
+ ASSERT_CONSTRAINT_VIOLATION (STRCPY_S (s1, LEN_S1, s1+2));
+ ASSERT_EQUAL (L_('\0'), (int)s1[0]);
+
+ STRCPY_S (s1, LEN_S1, L_("ABCD"));
+ ASSERT_CONSTRAINT_VIOLATION (STRCPY_S (s1+2, LEN_S1-2, s1));
+
+ return 0;
+}
+
+
+static int
+do_test (void)
+{
+ int result = 0;
+
+ set_constraint_handler_s (test_constraint_handler);
+
+ if (test_strcpy_s_should_copy_correct ())
+ return 1;
+ if (test_strcpy_s_should_fail ())
+ return 1;
+
+ /* Return != 0 in case of an error. */
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/lib_s/test-strnlen_s.c b/lib_s/test-strnlen_s.c
new file mode 100644
index 0000000..53aa145
--- /dev/null
+++ b/lib_s/test-strnlen_s.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "test-lib_s.h"
+
+#ifdef TXT_WIDECHAR
+# define test_strnlen_s_correct test_wcsnlen_s_correct
+#endif
+
+static int
+test_strnlen_s_correct (void)
+{
+ const CHAR_T *s1 = L_("123");
+
+ /* If s is a NULL pointer, then the strnlen_s function returns zero. */
+ ASSERT_EQUAL ((size_t) 0, STRNLEN_S (NULL, 2));
+
+ ASSERT_EQUAL ((size_t) 2, STRNLEN_S (s1, 2));
+ ASSERT_EQUAL ((size_t) 3, STRNLEN_S (s1, 4));
+ ASSERT_EQUAL ((size_t) 3, STRNLEN_S (s1, 3));
+
+ return 0;
+}
+
+
+static int
+do_test (void)
+{
+ int result = 0;
+
+ set_constraint_handler_s (test_constraint_handler);
+
+ if (test_strnlen_s_correct ())
+ return 1;
+
+
+ /* Return != 0 in case of an error. */
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/lib_s/test-wcscpy_s.c b/lib_s/test-wcscpy_s.c
new file mode 100644
index 0000000..06e7f07
--- /dev/null
+++ b/lib_s/test-wcscpy_s.c
@@ -0,0 +1,2 @@
+#define TXT_WIDECHAR 1
+#include "test-strcpy_s.c"
diff --git a/lib_s/test-wcsnlen_s.c b/lib_s/test-wcsnlen_s.c
new file mode 100644
index 0000000..b3888f6
--- /dev/null
+++ b/lib_s/test-wcsnlen_s.c
@@ -0,0 +1,2 @@
+#define TXT_WIDECHAR 1
+#include "test-strnlen_s.c"
diff --git a/lib_s/txt.h b/lib_s/txt.h
new file mode 100644
index 0000000..ab90964
--- /dev/null
+++ b/lib_s/txt.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _TXT_H
+#define _TXT_H
+
+#ifdef TXT_WIDECHAR
+# include <wchar.h>
+
+# define L_(Str) L##Str
+# define CHAR_T wchar_t
+# define UCHAR_T unsigned int
+# define WINT_T wint_t
+# undef EOF
+# define EOF WEOF
+
+# define FPRINTF fwprintf
+# define STRLEN wcslen
+# define STRCPY_S wcscpy_s
+# define STRNLEN_S wcsnlen_s
+# define STRNLEN wcsnlen
+# define STRNCPY wcsncpy
+# define VFSCANF_S vfwscanf_s
+# define FSCANF_S fwscanf_s
+# define STRCMP wcscmp
+# define STRNCMP wcsncmp
+
+
+#else /* WIDECHARS */
+
+# define L_(Str) Str
+# define CHAR_T char
+# define UCHAR_T unsigned char
+# define WINT_T int
+
+# define FPRINTF fprintf
+# define STRLEN strlen
+# define STRCPY_S strcpy_s
+# define STRNLEN_S strnlen_s
+# define STRNLEN strnlen
+# define STRNCPY strncpy
+# define VFSCANF_S vfscanf_s
+# define FSCANF_S fscanf_s
+# define STRCMP strcmp
+# define STRNCMP strncmp
+#endif /* WIDECHARS */
+
+
+#endif
diff --git a/lib_s/wcscpy_s.c b/lib_s/wcscpy_s.c
new file mode 100644
index 0000000..4b0e9a8
--- /dev/null
+++ b/lib_s/wcscpy_s.c
@@ -0,0 +1,2 @@
+#define TXT_WIDECHAR
+#include "strcpy_s.c"
diff --git a/lib_s/wcsnlen_s.c b/lib_s/wcsnlen_s.c
new file mode 100644
index 0000000..c44dd83
--- /dev/null
+++ b/lib_s/wcsnlen_s.c
@@ -0,0 +1,2 @@
+#define TXT_WIDECHAR
+#include "strnlen_s.c"
diff --git a/stdlib/errno.h b/stdlib/errno.h
index 6843cbf..b94e41a 100644
--- a/stdlib/errno.h
+++ b/stdlib/errno.h
@@ -46,6 +46,10 @@ __BEGIN_DECLS
extern int errno;
#endif
+#ifdef __USE_BOUNDS_CHECKING
+# include <bits/errno_t.h>
+#endif
+
#ifdef __USE_GNU
/* The full and simple forms of the name with which the program was
diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h
index 99a830d..0508808 100644
--- a/stdlib/stdlib.h
+++ b/stdlib/stdlib.h
@@ -962,6 +962,40 @@ extern int getloadavg (double __loadavg[], int __nelem)
# include <bits/stdlib-ldbl.h>
#endif
+#ifdef __USE_BOUNDS_CHECKING
+# include <bits/errno_t.h>
+# include <bits/rsize_t.h>
+
+/* All _s-functions invoke the constraint handler in case of a
+ runtime-constraint violation. */
+typedef void (*constraint_handler_t) (const char * __restrict msg,
+ void * __restrict ptr,
+ errno_t error);
+
+/* This function sets a user-specified constraint handler.
+
+ The constraint handler is called whenever a runtime constraint violation
+ is detected by one of the _s functions . If, for example, a user calls
+ strcpy_s(NULL, 0, source) the currently set runtime constraint handler will
+ be invoked. */
+constraint_handler_t set_constraint_handler_s (constraint_handler_t handler)
+ __THROW;
+
+/* The abort handler prints an errormessage on stderr before
+ it ends the program with the function abort. */
+void abort_handler_s (const char * __restrict msg,
+ void * __restrict ptr,
+ errno_t error)
+ __THROW __nonnull(1) __attribute__ ((__noreturn__));
+
+/* The ignore_handler_s is used to ignore constraint violations.
+ It does nothing. */
+void ignore_handler_s (const char * __restrict msg,
+ void * __restrict ptr,
+ errno_t error) __THROW __attribute_pure__ ;
+#endif /* __USE_BOUNDS_CHECKING */
+
+
#endif /* don't just need malloc and calloc */
#undef __need_malloc_and_calloc
diff --git a/string/string.h b/string/string.h
index ecc3fef..9f1d3cf 100644
--- a/string/string.h
+++ b/string/string.h
@@ -637,6 +637,29 @@ extern char *basename (const char *__filename) __THROW __nonnull ((1));
# endif
#endif
+#ifdef __USE_BOUNDS_CHECKING
+# include <bits/errno_t.h>
+# include <bits/rsize_t.h>
+
+/* The strnlen_s function determines the length of s.
+ At most maxsize characters are accessed and maxsize is returned. Otherwise
+ the number of characters before the nullbyte are returned.
+ The only difference to strnlen is that in case of s being a
+ null pointer this function gracefully returns 0. */
+extern size_t strnlen_s (const char *s, rsize_t maxsize)
+ __THROW __attribute_pure__ __nonnull((1));
+
+
+/* The strcpy_s function copies the string s2 to s1.
+ Unlike the traditional strcpy, the size of the destination buffer s1
+ has to be specified. The function makes sure that it never
+ writes outside the specified bounds.
+*/
+extern errno_t strcpy_s (char * __restrict__ s1, rsize_t s1max,
+ const char * __restrict__ s2)
+ __THROW __nonnull ((1,3));
+#endif /* __USE_BOUNDS_CHECKING */
+
__END_DECLS
#endif /* string.h */
diff --git a/sysdeps/generic/stdint.h b/sysdeps/generic/stdint.h
index 94c3203..1c0d830 100644
--- a/sysdeps/generic/stdint.h
+++ b/sysdeps/generic/stdint.h
@@ -263,6 +263,20 @@ typedef unsigned long long int uintmax_t;
# define SIZE_MAX (4294967295U)
# endif
+# ifdef __USE_BOUNDS_CHECKING
+/* RSIZE_MAX defines the highest number that a value of type rsize_t may
+ contain.
+ Functions that have a parameter of rsize_t will report a runtime
+ constraint violation if its value exceeds RSIZE_MAX.
+ The C11 standard recommends:
+ "For implementations targeting machines with large address spaces,
+ it is recommended that RSIZE_MAX be defined as the smaller of the
+ size of the largest object supported or(SIZE_MAX >> 1), even if this
+ limit is smaller than the size of some legitimate, but very large,
+ objects." */
+# define RSIZE_MAX (SIZE_MAX >> 1)
+# endif
+
/* Limits of `wchar_t'. */
# ifndef WCHAR_MIN
/* These constants might also be defined in <wchar.h>. */
diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h
index e915586..0f4c011 100644
--- a/wcsmbs/wchar.h
+++ b/wcsmbs/wchar.h
@@ -888,6 +888,19 @@ extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize,
# include <bits/wchar-ldbl.h>
#endif
+#ifdef __USE_BOUNDS_CHECKING
+# include <bits/errno_t.h>
+# include <bits/rsize_t.h>
+
+extern errno_t wcscpy_s (wchar_t * __restrict s1, rsize_t s1max,
+ const wchar_t * __restrict s2)
+ __THROW __nonnull ((1,3));
+
+extern size_t wcsnlen_s (const wchar_t *s, size_t maxsize)
+ __THROW __attribute_pure__ __nonnull((1));
+
+#endif /* __USE_BOUNDS_CHECKING */
+
__END_DECLS
#endif /* _WCHAR_H defined */