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


This patch adds the infrastructure for a potential addition of the C11 Annex K functions to glibc. 
As discussed before in http://sourceware.org/ml/libc-alpha/2012-10/msg00928.html, there
are advantages to implementing the Annex K functions inside glibc as opposed  to an external 
wrapper library.
The proposed implementation minimizes impact on existing glibc code. To use the new functions,
users will have to define  __STDC_WANT_LIB_EXT1__ with a value of 1 before including the 
standard C headers and link their application with -lc_s.

Although I have carefully prepared the attached patch, I'm new to glibc and there will certainly 
be several weak points which need your diligent review. I'd be happy to improve the patch.

This patch only adds the basic infrastructure for supporting the C11 Annex K
bounds-checking interfaces in glibc and provides an implementation of a couple 
of _s functions. 

Please let me know what you think. 

--Ulrich

2013-01-25  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.


 Makeconfig                 |   10 ++++-
 Versions.def               |    3 ++
 bits/errno_t.h             |   33 ++++++++++++++
 bits/rsize_t.h             |   48 ++++++++++++++++++++
 include/features.h         |   27 ++++++++++--
 include/stdc-predef.h      |    3 ++
 lib_s/Makefile             |   53 ++++++++++++++++++++++
 lib_s/Versions             |   16 +++++++
 lib_s/abort_handler_s.c    |   39 ++++++++++++++++
 lib_s/constraint_handler.c |   83 ++++++++++++++++++++++++++++++++++
 lib_s/ignore_handler_s.c   |   27 ++++++++++++
 lib_s/libc_s.h             |  105 ++++++++++++++++++++++++++++++++++++++++++++
 lib_s/strcpy_s.c           |   51 +++++++++++++++++++++
 lib_s/strnlen_s.c          |   31 +++++++++++++
 lib_s/test-lib_s.h         |   59 +++++++++++++++++++++++++
 lib_s/test-strcpy_s.c      |   85 +++++++++++++++++++++++++++++++++++
 lib_s/test-strnlen_s.c     |   56 +++++++++++++++++++++++
 lib_s/test-wcscpy_s.c      |    2 +
 lib_s/test-wcsnlen_s.c     |    2 +
 lib_s/txt.h                |   63 ++++++++++++++++++++++++++
 lib_s/wcscpy_s.c           |    2 +
 lib_s/wcsnlen_s.c          |    2 +
 stdlib/errno.h             |    4 ++
 stdlib/stdlib.h            |   34 ++++++++++++++
 string/string.h            |   23 ++++++++++
 sysdeps/generic/stdint.h   |   15 +++++++
 wcsmbs/wchar.h             |   13 ++++++
 27 files changed, 884 insertions(+), 5 deletions(-)



diff --git a/Makeconfig b/Makeconfig
index 8da4ad3..83bc595 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -478,7 +478,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
@@ -1034,6 +1034,12 @@ else
 libm = $(common-objpfx)math/libm.a
 endif
 
+ifeq ($(build-shared),yes)
+libc_s = $(common-objpfx)libc_s/libc_s.so$(libc_s.so-version)
+else
+libc_s = $(common-objpfx)libc_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.
@@ -1042,7 +1048,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 nss localedata timezone rt conform debug		    \
-	      $(add-on-subdirs) dlfcn elf
+	      $(add-on-subdirs) dlfcn elf lib_s
 
 ifndef avoid-generated
 all-Depend-files := $(wildcard $(foreach dir,$(all-subdirs),\
diff --git a/Versions.def b/Versions.def
index 3c9e0ae..04a6f16 100644
--- a/Versions.def
+++ b/Versions.def
@@ -140,3 +140,6 @@ libanl {
 libcidn {
   GLIBC_PRIVATE
 }
+libc_s {
+  GLIBC_2.18
+}
\ No newline at end of file
diff --git a/bits/errno_t.h b/bits/errno_t.h
new file mode 100644
index 0000000..4c7e5a4
--- /dev/null
+++ b/bits/errno_t.h
@@ -0,0 +1,33 @@
+/* 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..58ddd03
--- /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..9e109b8 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__ if == 1 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,7 @@
    __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 +124,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 +195,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))
@@ -387,5 +396,17 @@
    that will always return failure (and set errno to ENOSYS).  */
 #include <gnu/stubs.h>
 
-
-#endif	/* features.h  */
+#else  /* _FEATURES_H */
+/* Since every header file includes this one we can - as mandated by
+   ISO C11 Annex K -  check whether __STDC_WANT_LIB_EXT1__ was defined 
+   identically for all inclusions of a GLIBC header. 
+   Only stddef.h (which is part of GCC) does not include features.h. We accept that for now.
+*/
+#if ( (!defined(__USE_BOUNDS_CHECKING ) && \
+       (defined(__STDC_WANT_LIB_EXT1__) && (__STDC_WANT_LIB_EXT1__ == 1))) || \
+      (defined(__USE_BOUNDS_CHECKING ) && \
+       (!defined(__STDC_WANT_LIB_EXT1__) || (__STDC_WANT_LIB_EXT1__ != 1))))
+#error "__STDC_WANT_LIB_EXT1__ was not defined identically for all inclusions\
+   of a GLIBC header."
+#endif
+#endif	/* FEATURES_H  */
diff --git a/include/stdc-predef.h b/include/stdc-predef.h
index b9c9967..e42f68a 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..d72a152
--- /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
+
+tests := test-strcpy_s test-wcscpy_s test-strnlen_s test-wcsnlen_s 
+
+include ../Makeconfig
+
+#aux:= 
+
+include ../Rules
+
+ifeq (yes,$(build-shared))
+$(addprefix $(objpfx),$(tests)): $(objpfx)libc_s.so
+else
+$(addprefix $(objpfx),$(tests)): $(objpfx)libc_s.a
+endif
+ifeq (yes,$(build-bounded))
+$(tests:%=$(objpfx)%-bp): $(objpfx)libc_s_b.a
+endif
+
+# Depend on libc.so so a DT_NEEDED is generated in the shared objects.
+# This ensures they will load libc.so for needed symbols if loaded by
+# a statically-linked program that hasn't already loaded it.
+$(objpfx)libc_s.so: $(common-objpfx)libc.so $(common-objpfx)libc_nonshared.a
diff --git a/lib_s/Versions b/lib_s/Versions
new file mode 100644
index 0000000..ca55292
--- /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..115ca15
--- /dev/null
+++ b/lib_s/abort_handler_s.c
@@ -0,0 +1,39 @@
+/* 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)
+    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..75a149d
--- /dev/null
+++ b/lib_s/constraint_handler.c
@@ -0,0 +1,83 @@
+/* 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 a static
+   variable.
+ */
+#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)
+    msg = _("(empty message)");
+  if (!func)
+    func = _("(empty functionname)");
+  if (!file)
+    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)
+    {
+      /* 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..899508f
--- /dev/null
+++ b/lib_s/ignore_handler_s.c
@@ -0,0 +1,27 @@
+/* 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..fb88910
--- /dev/null
+++ b/lib_s/libc_s.h
@@ -0,0 +1,105 @@
+/* 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..df1693b
--- /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);
+
+  rsize_t s2_len = 0;
+  _CONSTRAINT_VIOLATION_CLEANUP_IF (s2 == NULL,
+				   s1[0] = L_('\0'), 
+				   EINVAL, EINVAL);
+  _CONSTRAINT_VIOLATION_CLEANUP_IF ((s1max <= (s2_len=STRNLEN_S(s2, s1max)) ),
+				   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');
+
+  // on success
+  return 0;
+}
diff --git a/lib_s/strnlen_s.c b/lib_s/strnlen_s.c
new file mode 100644
index 0000000..5832a89
--- /dev/null
+++ b/lib_s/strnlen_s.c
@@ -0,0 +1,31 @@
+/* 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) 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..cdc4504
--- /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)					\
+    {								\
+      fprintf(stdout, "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)						\
+    {									\
+      fprintf(stdout, "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..49c7e1a
--- /dev/null
+++ b/lib_s/test-strcpy_s.c
@@ -0,0 +1,85 @@
+/* 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_ShouldCopyCorrect ())
+    return 1;
+  if (test_strcpy_s_ShouldFail ())
+    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..081a823
--- /dev/null
+++ b/lib_s/test-strnlen_s.c
@@ -0,0 +1,56 @@
+/* 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 b49a41c..2222c0d 100644
--- a/stdlib/stdlib.h
+++ b/stdlib/stdlib.h
@@ -959,6 +959,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);
+
+/* The set_constraint_handler 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..eebb724 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 15f7508..617b648 100644
--- a/sysdeps/generic/stdint.h
+++ b/sysdeps/generic/stdint.h
@@ -267,6 +267,21 @@ 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..a6c645d 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]