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 v2] Initial support for C11 Annex K Bounds checking functions


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


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