This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[RFC][PATCH v3] 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: Fri, 7 Jun 2013 12:21:56 +0200
- Subject: [RFC][PATCH v3] Initial support for C11 Annex K Bounds checking functions
Please find included an updated version of my patch that includes all comments
voiced so far.
I have included comments on all function definitions. Please let me know whether you
like this format (it's simply what I already had). I saw it is also used by libidn.
I'm also a bit confused if
a function comment is better placed in the header or implementation or best
duplicated? I did not find this mentioned in the GNU coding guidelines.
In addition to the notnull attribute I have also removed the pure attribute from
strnlen_s because the runtime-constraint handler might change between function
calls. Thus, it does IMHO not qualify as being tagged with pure.
The patch does not yet detect different definitions of __STDC_WANT_LIB_EXT1__ as
mandated by K.3.1.1 paragraph 4 since we were still discussing it. The best
that I could think of - maybe only as a temporary solution - is something similar
to my original approach in features.h.
Instead of misusing features.h (with global effects) we could create a new header
called e.g. annex_k_protection.h which is included by all Annex K relevant headers.
This header can then check whether __STDC_WANT_LIB_EXT1__ has the same value
for all inclusions of an Annex K header.
Since it is still a matter of discussion whether to include the Annex K functions
when __USE_GNU is defined, I took the conservative approach and have the Annex K
functions only included upon definition of __STDC_WANT_LIB_EXT1__ with a value of 1.
If we were to include the Annex K functions under __USE_GNU I'd propose
the following:
#if ((defined __STDC_WANT_LIB_EXT1__ && __STDC_WANT_LIB_EXT1__ == 1) \
|| (defined __USE_GNU && (!defined __STDC_WANT_LIB_EXT1__ \
|| __STDC_WANT_LIB_EXT1_ != 0)))
This allows explicitly not including the Annex K functions by setting
__STDC_WANT_LIB_EXT1__ to 0.
One thing that I do not particularly like in my solution is that the above
include guard does not allow a user to simply define __STDC_WANT_LIB_EXT1__
with no value for including the Annex K functions. Instead, it will make a
preprocessor error occur. It's also in contrast to current usage where for
example "#define _ISOC99_SOURCE" or "#define __USE_GNU" are used. I don't know
whether you consider this a problem (it is standard-compliant in any case).
I saw no simple solution, checking for empty macros values reliably seems
to be complicated.
--Ulrich
2013-06-07 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/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/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..e6cd0df
--- /dev/null
+++ b/lib_s/Makefile
@@ -0,0 +1,53 @@
+# 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
+
+# All functions emitting runtime-constraint violations may
+# call a user function
+CFLAGS-strnlen_s.c = $(uses-callbacks)
+CFLAGS-wcsnlen_s.c = $(uses-callbacks)
+CFLAGS-strcpy_s.c = $(uses-callbacks)
+CFLAGS-wcscpy_s.c = $(uses-callbacks)
+CFLAGS-constraint_handler_s.c = $(uses-callbacks)
+# abort_handler_s and ignore_handler_s do not cause
+# any runtime-constraint violations
+
+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..a1f4869
--- /dev/null
+++ b/lib_s/abort_handler_s.c
@@ -0,0 +1,46 @@
+/* Implementation of function abort_handler_s as defined by C11 Annex K.
+
+ 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>
+
+
+/* The abort handler prints the string given msg on stderr before
+ it ends the program by calling abort.
+ The value of ptr is implementation-defined. It is currently NULL
+ in glibc.
+ For functions returning an errno_t error gives the error number
+ that the function would have returned. */
+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..5dbeafe
--- /dev/null
+++ b/lib_s/constraint_handler.c
@@ -0,0 +1,99 @@
+/* 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;
+
+/* Internal function that is called when a runtime-constraint violation
+ occurrs.
+ It accepts a message, the function name, source file name, source line
+ number and an error number. */
+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);
+}
+
+
+
+/* The set_constraint_handler function sets a user-specified constraint
+ handler.
+ The constraint handler is called whenever a runtime constraint violation
+ is detected. If, for example, a user calls strcpy_s(NULL, 0, source) the
+ currently set runtime constraint handler will be invoked. The constraint
+ handler is specific to each thread.
+
+ If the application does not set its own constraint handler, the default
+ constraint handler is called. In our implementation the default constraint
+ handler is abort_handler_s.
+
+ @rcs There are no runtime-constraints.
+
+ @param [in] handler a pointer to the new handler function
+
+ @return the previously registered handler
+ @see abort_handler_s, ignore_handler_s */
+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..3d95236
--- /dev/null
+++ b/lib_s/ignore_handler_s.c
@@ -0,0 +1,28 @@
+/* Implementation of function ignore_handler_s as defined by C11 Annex K.
+
+ 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>
+
+/* The ignore_handler_s is used to ignore runtime-constraint violations.
+ It simply returns. */
+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..e325b55
--- /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..12a0a9a
--- /dev/null
+++ b/lib_s/strcpy_s.c
@@ -0,0 +1,78 @@
+/* Implementation of function strcpy_s as defined by C11 Annex K.
+ It implements wcscpy_s when TXT_WIDECHAR is defined.
+
+ 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"
+
+/* The strcpy_s function copies the string s2 to s1.
+
+ Unlike the traditional strcpy, the size of the destination buffer \a s1
+ has to be specified. The function makes sure that it never
+ writes outside the specified bounds.
+
+ The buffer s1 must be large enough for holding s2 plus
+ the terminating null byte.
+
+ @post As long as s1 is not null, the string in s1 will always be
+ null-terminated.
+
+ @rcs A runtime-constraint violation occurs if
+ \li either s1 or s2 is a null pointer.
+ \li s1 (as determined by s1max) is not large enough to hold
+ s2 (including its terminating null byte).
+ \li s1 and s2 overlap.
+
+ @param [out] s1 The destination buffer
+ @param [in] s1max The size of s1
+ @param [in] s2 The source string
+
+ @return 0 if there was no runtime-constraint violation.
+ Otherwise a non-zero value is returned. */
+#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..ab70061
--- /dev/null
+++ b/lib_s/strnlen_s.c
@@ -0,0 +1,54 @@
+/* Implementation of function strnlen_s as defined by C11 Annex K.
+ It implements wcsnlen_s when TXT_WIDECHAR is defined.
+
+ 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>
+
+/* 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.
+
+ @rcs There are no runtime-constraints.
+
+ @param [in] s The string of whose length should be calculated
+ @param [in] maxsize Only maxsize characters should be accessed
+
+ @return Zero if s is a null pointer.
+ maxsize characters if there is no nullbyte in the first maxsize chars
+ of s.
+ Otherwise the number of characters before the nullbyte.
+ @see strlen, strnlen */
+#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..bd285f4
--- /dev/null
+++ b/lib_s/test-lib_s.h
@@ -0,0 +1,61 @@
+/* Internal header file that is included by all libc_s test programs.
+
+ 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..dae6b5b
--- /dev/null
+++ b/lib_s/test-strcpy_s.c
@@ -0,0 +1,90 @@
+/* Tests for strcpy_s and wcscpy_s.
+
+ 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..36b1fed
--- /dev/null
+++ b/lib_s/test-strnlen_s.c
@@ -0,0 +1,59 @@
+/* Tests for strnlen_s and wcsnlen_s.
+
+ 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..a73ec97
--- /dev/null
+++ b/lib_s/txt.h
@@ -0,0 +1,67 @@
+/* This file contains abstract text macros that map to char
+ or wchar equivalent depending on the definition of the macro
+ TXT_WIDECHAR.
+
+ 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..8359b83 100644
--- a/stdlib/errno.h
+++ b/stdlib/errno.h
@@ -46,6 +46,10 @@ __BEGIN_DECLS
extern int errno;
#endif
+#if (defined __STDC_WANT_LIB_EXT1__ && __STDC_WANT_LIB_EXT1__ == 1)
+# 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..13403b7 100644
--- a/stdlib/stdlib.h
+++ b/stdlib/stdlib.h
@@ -962,6 +962,45 @@ extern int getloadavg (double __loadavg[], int __nelem)
# include <bits/stdlib-ldbl.h>
#endif
+/* Include C11 Annex K functions upon request. */
+#if (defined __STDC_WANT_LIB_EXT1__ && __STDC_WANT_LIB_EXT1__ == 1)
+# 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.
+ Invoking set_constraint_handler_s itself cannot cause any
+ runtime-constraint violations. */
+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.
+ This function invokes I/O functions and is therefore not
+ marked with __THROW. */
+void abort_handler_s (const char * __restrict msg,
+ void * __restrict ptr,
+ errno_t error)
+ __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 /* C11 Annex K functions */
+
+
#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..851c5ae 100644
--- a/string/string.h
+++ b/string/string.h
@@ -637,6 +637,29 @@ extern char *basename (const char *__filename) __THROW __nonnull ((1));
# endif
#endif
+/* Include C11 Annex K functions upon request. */
+#if (defined __STDC_WANT_LIB_EXT1__ && __STDC_WANT_LIB_EXT1__ == 1)
+# 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.
+ Not declared as a pure function because the runtime constraint
+ handler might change between two consecutive calls. */
+extern size_t strnlen_s (const char *s, rsize_t maxsize);
+
+
+/* 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);
+#endif /* C11 Annex K functions */
+
__END_DECLS
#endif /* string.h */
diff --git a/sysdeps/generic/stdint.h b/sysdeps/generic/stdint.h
index 94c3203..27bd2ad 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
+#if (defined __STDC_WANT_LIB_EXT1__ && __STDC_WANT_LIB_EXT1__ == 1)
+/* 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..a8ae060 100644
--- a/wcsmbs/wchar.h
+++ b/wcsmbs/wchar.h
@@ -888,6 +888,22 @@ extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize,
# include <bits/wchar-ldbl.h>
#endif
+/* Include C11 Annex K functions upon request. */
+#if (defined __STDC_WANT_LIB_EXT1__ && __STDC_WANT_LIB_EXT1__ == 1)
+# include <bits/errno_t.h>
+# include <bits/rsize_t.h>
+
+/* Copy the wide string s2 to s1 while respecting the maximum length of s1.
+ s1max gives the number of wide string characters that s1 has room for. */
+extern errno_t wcscpy_s (wchar_t * __restrict s1, rsize_t s1max,
+ const wchar_t * __restrict s2);
+
+/* Compute the length of the wide string s while respecting the maximum
+ length of s. */
+extern size_t wcsnlen_s (const wchar_t *s, size_t maxsize);
+
+#endif /* C11 Annex K functions */
+
__END_DECLS
#endif /* _WCHAR_H defined */