From 9fa58be2cc6cd5e220f0e8e5148a69bbcc56513d Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Sat, 7 Sep 2019 21:05:35 +0200
Subject: [PATCH] WIP gets_s().

---
 include/stdint.h                           |   6 +
 include/stdio.h                            |   5 +
 include/stdlib.h                           |  18 +++
 lib/libc/Versions.def                      |   6 +-
 lib/libc/include/libc_private.h            |   2 +
 lib/libc/stdio/Makefile.inc                |   2 +-
 lib/libc/stdio/Symbol.map                  |   4 +
 lib/libc/stdio/fgets.3                     |  39 +++++-
 lib/libc/stdio/gets_s.c                    | 109 +++++++++++++++
 lib/libc/stdlib/Makefile.inc               |   7 +-
 lib/libc/stdlib/Symbol.map                 |   6 +
 lib/libc/stdlib/set_constraint_handler_s.3 | 149 +++++++++++++++++++++
 lib/libc/stdlib/set_constraint_handler_s.c | 100 ++++++++++++++
 sys/sys/cdefs.h                            |  14 ++
 14 files changed, 458 insertions(+), 9 deletions(-)
 create mode 100644 lib/libc/stdio/gets_s.c
 create mode 100644 lib/libc/stdlib/set_constraint_handler_s.3
 create mode 100644 lib/libc/stdlib/set_constraint_handler_s.c

diff --git a/include/stdint.h b/include/stdint.h
index d489f9ffc4..1384306fda 100644
--- a/include/stdint.h
+++ b/include/stdint.h
@@ -77,5 +77,11 @@ typedef __uint_least64_t	uint_least64_t;
 #include <machine/int_limits.h>
 #endif
 
+#if __EXT1_VISIBLE
+/* ISO/IEC 9899:2011 K.3.4.4 */
+#ifndef RSIZE_MAX
+#define RSIZE_MAX (SIZE_MAX >> 1)
 #endif
+#endif /* __EXT1_VISIBLE */
 
+#endif
diff --git a/include/stdio.h b/include/stdio.h
index c03eb013c1..fdaa4199a2 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -48,6 +48,11 @@ typedef	__size_t	size_t;
 #define	_SIZE_T_DECLARED
 #endif
 
+#ifndef _RSIZE_T_DECLARED
+#define _RSIZE_T_DECLARED
+typedef size_t rsize_t;
+#endif
+
 #if __POSIX_VISIBLE >= 200809
 #ifndef _OFF_T_DECLARED
 #define	_OFF_T_DECLARED
diff --git a/include/stdlib.h b/include/stdlib.h
index a2c78d4d53..ae2448dd8e 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -324,6 +324,24 @@ __uint64_t
 
 extern char *suboptarg;			/* getsubopt(3) external variable */
 #endif /* __BSD_VISIBLE */
+
+#if __EXT1_VISIBLE
+#ifndef _ERRNO_T_DEFINED
+#define _ERRNO_T_DEFINED
+typedef int errno_t;
+#endif
+
+/* K.3.6 */
+typedef void (*constraint_handler_t)(const char * __restrict,
+    void * __restrict, errno_t);
+/* K.3.6.1.1 */
+constraint_handler_t set_constraint_handler_s(constraint_handler_t handler);
+/* K.3.6.1.2 */
+_Noreturn void abort_handler_s(const char * __restrict, void * __restrict,
+    errno_t);
+/* K3.6.1.3 */
+void ignore_handler_s(const char * __restrict, void * __restrict, errno_t);
+#endif /* __EXT1_VISIBLE */
 __END_DECLS
 
 #endif /* !_STDLIB_H_ */
diff --git a/lib/libc/Versions.def b/lib/libc/Versions.def
index c97a1b3327..cce3fc43be 100644
--- a/lib/libc/Versions.def
+++ b/lib/libc/Versions.def
@@ -45,6 +45,10 @@ DF504.0 {
 DF506.0 {
 } DF504.0;
 
+# version for DragonFly 5.7
+DF508.0 {
+} DF506.0;
+
 # This is our private namespace.  Any global interfaces that are
 # strictly for use only by other DragonFly applications and libraries
 # are listed here.  We use a separate namespace so we can write
@@ -52,4 +56,4 @@ DF506.0 {
 #
 # Please do NOT increment the version of this namespace.
 DFprivate_1.0 {
-} DF506.0;
+} DF508.0;
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
index c20bcee268..c3459e2a57 100644
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -127,4 +127,6 @@ void _rtld_error(const char *fmt, ...);
  */
 int _once(pthread_once_t *, void (*)(void));
 
+void __throw_constraint_handler_s(const char * restrict msg, int error);
+
 #endif /* _LIBC_PRIVATE_H_ */
diff --git a/lib/libc/stdio/Makefile.inc b/lib/libc/stdio/Makefile.inc
index 3dee232ee5..3fa3d75d13 100644
--- a/lib/libc/stdio/Makefile.inc
+++ b/lib/libc/stdio/Makefile.inc
@@ -15,7 +15,7 @@ SRCS+=	__fpending.c _flock_stub.c \
 	fputc.c fputs.c fputwc.c fputws.c fread.c freopen.c fscanf.c \
 	fseek.c fsetpos.c ftell.c funopen.c fvwrite.c fwalk.c fwide.c \
 	fwprintf.c fwrite.c fwscanf.c getc.c getchar.c \
-	getdelim.c getline.c gets.c getw.c \
+	getdelim.c getline.c gets.c gets_s.c getw.c \
 	getwc.c getwchar.c makebuf.c mktemp.c \
 	open_memstream.c open_wmemstream.c \
 	perror.c printf-pos.c printf.c putc.c \
diff --git a/lib/libc/stdio/Symbol.map b/lib/libc/stdio/Symbol.map
index 2eda0fc579..34e2ff4a2f 100644
--- a/lib/libc/stdio/Symbol.map
+++ b/lib/libc/stdio/Symbol.map
@@ -157,6 +157,10 @@ DF406.0 {
     mkostemps;
 };
 
+DF508.0 {
+    gets_s;
+};
+
 DFprivate_1.0 {
     __fcloseall;
     __fflush;
diff --git a/lib/libc/stdio/fgets.3 b/lib/libc/stdio/fgets.3
index cf85494fbb..85aafcec05 100644
--- a/lib/libc/stdio/fgets.3
+++ b/lib/libc/stdio/fgets.3
@@ -31,14 +31,14 @@
 .\"
 .\"     @(#)fgets.3	8.1 (Berkeley) 6/4/93
 .\" $FreeBSD: src/lib/libc/stdio/fgets.3,v 1.22 2009/02/28 06:00:58 das Exp $
-.\" $DragonFly: src/lib/libc/stdio/fgets.3,v 1.3 2004/06/08 00:29:03 hmp Exp $
 .\"
-.Dd June 4, 1993
+.Dd September 7, 2019
 .Dt FGETS 3
 .Os
 .Sh NAME
 .Nm fgets ,
-.Nm gets
+.Nm gets ,
+.Nm gets_s
 .Nd get a line from a stream
 .Sh LIBRARY
 .Lb libc
@@ -48,6 +48,8 @@
 .Fn fgets "char * restrict str" "int size" "FILE * restrict stream"
 .Ft char *
 .Fn gets "char *str"
+.Ft char *
+.Fn gets_s "char *str" "rsize_t size"
 .Sh DESCRIPTION
 The
 .Fn fgets
@@ -66,6 +68,17 @@ If any characters are read and there is no error, a
 character is appended to end the string.
 .Pp
 The
+.Fn gets_s
+function
+is equivalent to
+.Fn fgets
+with a
+.Fa stream
+of
+.Dv stdin ,
+except that the newline character (if any) is not stored in the string.
+.Pp
+The
 .Fn gets
 function
 is equivalent to
@@ -81,7 +94,8 @@ It is the caller's responsibility to ensure that the input line,
 if any, is sufficiently short to fit in the string.
 .Sh RETURN VALUES
 Upon successful completion,
-.Fn fgets
+.Fn fgets ,
+.Fn gets_s ,
 and
 .Fn gets
 return
@@ -95,7 +109,8 @@ they return
 .Dv NULL
 and the buffer contents are indeterminate.
 The
-.Fn fgets
+.Fn fgets ,
+.Fn gets_s ,
 and
 .Fn gets
 functions
@@ -124,6 +139,13 @@ or
 .Xr malloc 3 .
 .Pp
 The function
+.Fn gets_s
+may also fail and set
+.Va errno
+for any of the errors specified for the routine
+.Xr getchar 3 .
+.Pp
+The function
 .Fn gets
 may also fail and set
 .Va errno
@@ -155,3 +177,10 @@ and
 .Fn gets
 conform to
 .St -isoC-99 .
+.Fn gets_s
+conforms to
+.St -isoC-2011
+K.3.7.4.1.
+.Fn gets
+has been removed from
+.St -isoC-2011 .
diff --git a/lib/libc/stdio/gets_s.c b/lib/libc/stdio/gets_s.c
new file mode 100644
index 0000000000..be6a5bb35c
--- /dev/null
+++ b/lib/libc/stdio/gets_s.c
@@ -0,0 +1,109 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2017, 2018
+ *	Cyril S. E. Schubert
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libc/stdio/gets_s.c 333895 2018-05-19 21:26:07Z cy $
+ */
+
+#include "namespace.h"
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+static inline char *
+_gets_s(char *buf, rsize_t n)
+{
+	int c;
+	char *s;
+
+	ORIENT(stdin, -1);
+	for (s = buf, n--; (c = __sgetc(stdin)) != '\n' && n > 0 ; n--) {
+		if (c == EOF) {
+			if (s == buf) {
+				return (NULL);
+			} else
+				break;
+		} else
+			*s++ = c;
+	}
+
+	/*
+ 	 * If end of buffer reached, discard until \n or eof.
+	 * Then throw an error.
+	 */
+	if (n == 0) {
+		/* discard */
+		while ((c = __sgetc(stdin)) != '\n' && c != EOF);
+		/* throw the error after lock released prior to exit */
+		__throw_constraint_handler_s("gets_s : end of buffer", E2BIG);
+		return (NULL);
+	}
+	*s = 0;
+	return (buf);
+}
+
+/* ISO/IEC 9899:2011 K.3.7.4.1 */
+char *
+gets_s(char *buf, rsize_t n)
+{
+	char *ret;
+	if (buf == NULL) {
+		__throw_constraint_handler_s("gets_s : str is NULL", EINVAL);
+		return(NULL);
+	} else if (n > RSIZE_MAX) {
+		__throw_constraint_handler_s("gets_s : n > RSIZE_MAX",
+			EINVAL);
+		return(NULL);
+	} else if (n == 0) {
+		__throw_constraint_handler_s("gets_s : n == 0", EINVAL);
+		return(NULL);
+	}
+
+#if 0 /* XXX */
+	FLOCKFILE_CANCELSAFE(stdin);
+#else
+	FLOCKFILE(stdin);
+#endif
+	ret = _gets_s(buf, n);
+#if 0 /* XXX */
+	FUNLOCKFILE_CANCELSAFE();
+#else
+	FUNLOCKFILE(stdin);
+#endif
+	return (ret);
+}
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index b6236c6e6f..fa751a1888 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -16,7 +16,7 @@ MISRCS+=a64l.c abort.c abs.c atexit.c \
 	merge.c posix_fadvise.c ptsname.c qsort.c qsort_r.c quick_exit.c \
 	radixsort.c rand.c random.c \
 	reallocarray.c reallocf.c realpath.c recallocarray.c remque.c \
-	strfmon.c strsuftoll.c strtoimax.c \
+	set_constraint_handler_s.c strfmon.c strsuftoll.c strtoimax.c \
 	strtol.c strtoll.c strtonum.c strtoq.c strtoul.c strtoull.c \
 	strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c
 
@@ -45,7 +45,8 @@ MAN+=	a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 \
 	posix_fadvise.3 posix_memalign.3 posix_openpt.3 ptsname.3 \
 	qsort.3 quick_exit.3 \
 	radixsort.3 rand.3 random.3 realpath.3 reallocarray.3 \
-	strfmon.3 strsuftoll.3 strtod.3 strtol.3 strtonum.3 strtoul.3 system.3 \
+	set_constraint_handler_s.3 strfmon.3 strsuftoll.3 strtod.3 \
+	strtol.3 strtonum.3 strtoul.3 system.3 \
 	tsearch.3
 
 MLINKS+=a64l.3 l64a.3 \
@@ -84,6 +85,8 @@ MLINKS+=random.3 initstate.3 \
 	random.3 setstate.3 \
 	random.3 srandom.3 \
 	random.3 srandomdev.3
+MLINKS+=set_constraint_handler_s.3 abort_handler_s.3 \
+	set_constraint_handler_s.3 ignore_handler_s.3
 MLINKS+=strfmon.3 strfmon_l.3
 MLINKS+=strsuftoll.3 strsuftollx.3
 MLINKS+=strtod.3 strtod_l.3 \
diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map
index e93cba1210..6a123112da 100644
--- a/lib/libc/stdlib/Symbol.map
+++ b/lib/libc/stdlib/Symbol.map
@@ -125,6 +125,12 @@ DF506.0 {
     recallocarray;
 };
 
+DF508.0 {
+    	abort_handler_s;
+	ignore_handler_s;
+	set_constraint_handler_s;
+};
+
 /*
  * ignore WEAK:  __pthread_cxa_finalize;
  */
diff --git a/lib/libc/stdlib/set_constraint_handler_s.3 b/lib/libc/stdlib/set_constraint_handler_s.3
new file mode 100644
index 0000000000..5471f315eb
--- /dev/null
+++ b/lib/libc/stdlib/set_constraint_handler_s.3
@@ -0,0 +1,149 @@
+.\" Copyright 2018 Yuri Pankov <yuripv@yuripv.net>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: head/lib/libc/stdlib/set_constraint_handler_s.3 338051 2018-08-19 14:39:57Z kib $
+.\"
+.Dd August 18, 2018
+.Dt SET_CONSTRAINT_HANDLER_S 3
+.Os
+.Sh NAME
+.Nm set_constraint_handler_s ,
+.Nm abort_handler_s ,
+.Nm ignore_handler_s
+.Nd runtime-constraint violation handling
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #define __STDC_WANT_LIB_EXT1__ 1
+.In stdlib.h
+.Ft constraint_handler_t
+.Fo set_constraint_handler_s
+.Fa "constraint_handler_t handler"
+.Fc
+.Ss Handler Prototype
+.Ft typedef void
+.Fo (*constraint_handler_t)
+.Fa "const char * restrict msg"
+.Fa "void * restrict ptr"
+.Fa "errno_t error"
+.Fc
+.Ss Predefined Handlers
+.Ft void
+.Fo abort_handler_s
+.Fa "const char * restrict msg"
+.Fa "void * restrict ptr"
+.Fa "errno_t error"
+.Fc
+.Ft void
+.Fo ignore_handler_s
+.Fa "const char * restrict msg"
+.Fa "void * restrict ptr"
+.Fa "errno_t error"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn set_constraint_handler_s
+function sets the runtime-constraint violation handler to be
+.Fa handler .
+.Pp
+The runtime-constraint handler is the callback function invoked when a library
+function detects a runtime-constraint violation.
+.Pp
+The arguments are as follows:
+.Bl -tag -width "error"
+.It Fa msg
+A pointer to a character string describing the runtime-constraint violation.
+.It Fa ptr
+A
+.Dv NULL
+pointer.
+.It Fa error
+If the function calling the handler has a return type declared as
+.Vt errno_t ,
+the return value of the function is passed.
+Otherwise, a positive value of type
+.Vt errno_t
+is passed.
+.El
+.Pp
+Only the most recent handler registered with
+.Fn set_constraint_handler_s
+is called when a runtime-constraint violation occurs.
+.Pp
+The implementation has a default constraint handler that is used if no calls to
+the
+.Fn set_constraint_handler_s
+function have been made.
+If the
+.Fa handler
+argument to
+.Fn set_constraint_handler_s
+is a
+.Dv NULL
+pointer, the default handler becomes the current constraint handler.
+.Pp
+The
+.Fn abort_handler_s
+and
+.Fn ignore_handler_s
+are the standard-defined runtime-constraint handlers provided by the C library.
+.Pp
+The
+.Fn abort_handler_s
+function writes the error message including the
+.Fa msg
+to
+.Dv stderr
+and calls the
+.Xr abort 3
+function.
+The
+.Fn abort_handler_s
+is currently the default runtime-constraint handler.
+.Pp
+The
+.Fn ignore_handler_s
+simply returns to its caller.
+.Sh RETURN VALUES
+The
+.Fn set_constraint_handler_s
+function returns a pointer to the previously registered handler, or
+.Dv NULL
+if none was previously registered.
+.Pp
+The
+.Fn abort_handler_s
+function does not return to its caller.
+.Pp
+The
+.Fn ignore_handler_s
+function returns no value.
+.Sh STANDARDS
+The
+.Fn set_constraint_handler_s
+function conforms to
+.St -isoC-2011
+K.3.6.1.1.
+.Sh AUTHORS
+This manual page was written by
+.An Yuri Pankov Aq Mt yuripv@yuripv.net .
diff --git a/lib/libc/stdlib/set_constraint_handler_s.c b/lib/libc/stdlib/set_constraint_handler_s.c
new file mode 100644
index 0000000000..a5a604a7b1
--- /dev/null
+++ b/lib/libc/stdlib/set_constraint_handler_s.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2017 Juniper Networks.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libc/stdlib/set_constraint_handler_s.c 322427 2017-08-12 15:18:17Z kib $
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <machine/atomic.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+/*
+ * Rationale recommends allocating new memory each time.
+ */
+static constraint_handler_t *_ch = NULL;
+static pthread_mutex_t ch_lock = PTHREAD_MUTEX_INITIALIZER;
+
+constraint_handler_t
+set_constraint_handler_s(constraint_handler_t handler)
+{
+	constraint_handler_t *new, *old, ret;
+
+	new = malloc(sizeof(constraint_handler_t));
+	if (new == NULL)
+		return (NULL);
+	*new = handler;
+	if (__isthreaded)
+		_pthread_mutex_lock(&ch_lock);
+	old = _ch;
+	_ch = new;
+	if (__isthreaded)
+		_pthread_mutex_unlock(&ch_lock);
+	if (old == NULL) {
+		ret = NULL;
+	} else {
+		ret = *old;
+		free(old);
+	}
+	return (ret);
+}
+
+void
+__throw_constraint_handler_s(const char * restrict msg, errno_t error)
+{
+	constraint_handler_t ch;
+
+	if (__isthreaded)
+		_pthread_mutex_lock(&ch_lock);
+	ch = _ch != NULL ? *_ch : NULL;
+	if (__isthreaded)
+		_pthread_mutex_unlock(&ch_lock);
+	if (ch != NULL)
+		ch(msg, NULL, error);
+}
+
+void
+abort_handler_s(const char * restrict msg, void * restrict ptr __unused,
+    errno_t error __unused)
+{
+	static const char ahs[] = "abort_handler_s : ";
+
+	(void) _write(STDERR_FILENO, ahs, sizeof(ahs) - 1);
+	(void) _write(STDERR_FILENO, msg, strlen(msg));
+	(void) _write(STDERR_FILENO, "\n", 1);
+	abort();
+}
+
+void
+ignore_handler_s(const char * restrict msg __unused,
+    void * restrict ptr __unused, errno_t error __unused)
+{
+}
diff --git a/sys/sys/cdefs.h b/sys/sys/cdefs.h
index e750dff990..fea444908a 100644
--- a/sys/sys/cdefs.h
+++ b/sys/sys/cdefs.h
@@ -661,24 +661,38 @@
 #define	__XSI_VISIBLE		0
 #define	__BSD_VISIBLE		0
 #define	__ISO_C_VISIBLE		1990
+#define	__EXT1_VISIBLE		0
 #elif defined(_C99_SOURCE)	/* Localism to specify strict C99 env. */
 #define	__POSIX_VISIBLE		0
 #define	__XSI_VISIBLE		0
 #define	__BSD_VISIBLE		0
 #define	__ISO_C_VISIBLE		1999
+#define	__EXT1_VISIBLE		0
 #elif defined(_C11_SOURCE)	/* Localism to specify strict C11 env. */
 #define	__POSIX_VISIBLE		0
 #define	__XSI_VISIBLE		0
 #define	__BSD_VISIBLE		0
 #define	__ISO_C_VISIBLE		2011
+#define	__EXT1_VISIBLE		0
 #else				/* Default environment: show everything. */
 #define	__POSIX_VISIBLE		200809
 #define	__XSI_VISIBLE		700
 #define	__BSD_VISIBLE		1
 #define	__ISO_C_VISIBLE		2011
+#define	__EXT1_VISIBLE		1
 #endif
 #endif
 
+/* User override __EXT1_VISIBLE */
+#if defined(__STDC_WANT_LIB_EXT1__)
+#undef	__EXT1_VISIBLE
+#if __STDC_WANT_LIB_EXT1__
+#define	__EXT1_VISIBLE		1
+#else
+#define	__EXT1_VISIBLE		0
+#endif
+#endif /* __STDC_WANT_LIB_EXT1__ */
+
 /*
  * GLOBL macro exists to preserve __start_set_* and __stop_set_* sections
  * of kernel modules which are discarded from binutils 2.17.50+ otherwise.
-- 
2.22.0

