This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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 */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]