diff options
Diffstat (limited to 'lib/libc/stdlib')
128 files changed, 20260 insertions, 0 deletions
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc new file mode 100644 index 000000000000..e7b9955b9646 --- /dev/null +++ b/lib/libc/stdlib/Makefile.inc @@ -0,0 +1,93 @@ +# machine-independent stdlib sources +.PATH: ${LIBC_SRCTOP}/${LIBC_ARCH}/stdlib ${LIBC_SRCTOP}/stdlib + +MISRCS+=C99_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \ + bsearch.c bsearch_b.c \ + cxa_thread_atexit.c cxa_thread_atexit_impl.c \ + div.c exit.c getenv.c getopt.c getopt_long.c \ + getsubopt.c hcreate.c hcreate_r.c hdestroy_r.c heapsort.c heapsort_b.c \ + hsearch_r.c imaxabs.c imaxdiv.c \ + insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c \ + merge.c mergesort_b.c ptsname.c qsort.c qsort_r.c qsort_r_compat.c \ + qsort_s.c quick_exit.c radixsort.c rand.c \ + random.c reallocarray.c reallocf.c realpath.c recallocarray.c remque.c \ + set_constraint_handler_s.c strfmon.c strtoimax.c \ + strtol.c strtold.c strtoll.c strtoq.c strtoul.c strtonum.c strtoull.c \ + strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c + +CFLAGS.qsort.c+= -Wsign-compare + +# Work around an issue on case-insensitive file systems. +# libc has both _Exit.c and _exit.s and they both yield +# _exit.o (case insensitively speaking). +CLEANFILES+=C99_Exit.c +C99_Exit.c: ${LIBC_SRCTOP}/stdlib/_Exit.c .NOMETA + ln -sf ${.ALLSRC} ${.TARGET} + +SYM_MAPS+= ${LIBC_SRCTOP}/stdlib/Symbol.map + +.include "${LIBC_SRCTOP}/stdlib/malloc/Makefile.inc" + +# machine-dependent stdlib sources +.sinclude "${LIBC_SRCTOP}/${LIBC_ARCH}/stdlib/Makefile.inc" + +MAN+= a64l.3 abort.3 abs.3 atexit.3 atof.3 \ + atoi.3 atol.3 at_quick_exit.3 bsearch.3 \ + div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 \ + hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 lldiv.3 \ + lsearch.3 memory.3 ptsname.3 qsort.3 \ + quick_exit.3 \ + radixsort.3 rand.3 random.3 reallocarray.3 reallocf.3 realpath.3 \ + set_constraint_handler_s.3 \ + strfmon.3 strtod.3 strtol.3 strtonum.3 strtoul.3 system.3 \ + tsearch.3 + +MLINKS+=a64l.3 l64a.3 \ + a64l.3 l64a_r.3 +MLINKS+=atol.3 atoll.3 +MLINKS+=exit.3 _Exit.3 +MLINKS+=getenv.3 clearenv.3 \ + getenv.3 putenv.3 \ + getenv.3 secure_getenv.3 \ + getenv.3 setenv.3 \ + getenv.3 unsetenv.3 +MLINKS+=getopt_long.3 getopt_long_only.3 +MLINKS+=hcreate.3 hdestroy.3 \ + hcreate.3 hsearch.3 +MLINKS+=hcreate.3 hcreate_r.3 \ + hcreate.3 hdestroy_r.3 \ + hcreate.3 hsearch_r.3 +MLINKS+=insque.3 remque.3 +MLINKS+=lsearch.3 lfind.3 +MLINKS+=ptsname.3 grantpt.3 \ + ptsname.3 ptsname_r.3 \ + ptsname.3 unlockpt.3 +MLINKS+=qsort.3 heapsort.3 \ + qsort.3 heapsort_b.3 \ + qsort.3 mergesort.3 \ + qsort.3 mergesort_b.3 \ + qsort.3 qsort_b.3 \ + qsort.3 qsort_r.3 \ + qsort.3 qsort_s.3 +MLINKS+=rand.3 rand_r.3 \ + rand.3 srand.3 +MLINKS+=random.3 initstate.3 \ + random.3 setstate.3 \ + random.3 srandom.3 \ + random.3 srandomdev.3 +MLINKS+=radixsort.3 sradixsort.3 +MLINKS+=reallocarray.3 recallocarray.3 +MLINKS+=set_constraint_handler_s.3 abort_handler_s.3 +MLINKS+=set_constraint_handler_s.3 ignore_handler_s.3 +MLINKS+=strfmon.3 strfmon_l.3 +MLINKS+=strtod.3 strtof.3 \ + strtod.3 strtold.3 +MLINKS+=strtol.3 strtoll.3 \ + strtol.3 strtoq.3 \ + strtol.3 strtoimax.3 +MLINKS+=strtoul.3 strtoull.3 \ + strtoul.3 strtouq.3 \ + strtoul.3 strtoumax.3 +MLINKS+=tsearch.3 tdelete.3 \ + tsearch.3 tfind.3 \ + tsearch.3 twalk.3 diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map new file mode 100644 index 000000000000..53d71bcafb7d --- /dev/null +++ b/lib/libc/stdlib/Symbol.map @@ -0,0 +1,144 @@ +FBSD_1.0 { + _Exit; + a64l; + abort; + abs; + atexit; + __cxa_atexit; + __cxa_finalize; + atof; + atoi; + atol; + atoll; + bsearch; + div; + __isthreaded; + exit; + getenv; + opterr; + optind; + optopt; + optreset; + optarg; + getopt; + getopt_long; + getopt_long_only; + suboptarg; + getsubopt; + grantpt; + ptsname; + unlockpt; + hcreate; + hdestroy; + hsearch; + heapsort; + imaxabs; + imaxdiv; + insque; + l64a; + l64a_r; + labs; + ldiv; + llabs; + lldiv; + lsearch; + lfind; + mergesort; + putenv; + qsort; + radixsort; + sradixsort; + rand_r; + srandom; + srandomdev; + initstate; + setstate; + random; + reallocf; + realpath; + remque; + setenv; + unsetenv; + strfmon; + strtoimax; + strtol; + strtoll; + strtonum; + strtoq; + strtoul; + strtoull; + strtoumax; + strtouq; + system; + tdelete; + tfind; + tsearch; + twalk; +}; + +FBSD_1.3 { + at_quick_exit; + atof_l; + atoi_l; + atol_l; + atoll_l; + quick_exit; + strtod_l; + strtof_l; + strtoimax_l; + strtol_l; + strtold_l; + strtoll_l; + strtoul_l; + strtoull_l; + strtoumax_l; +}; + +FBSD_1.4 { + atexit_b; + bsearch_b; + heapsort_b; + mergesort_b; + qsort_b; + hcreate_r; + hdestroy_r; + hsearch_r; + reallocarray; +}; + +FBSD_1.5 { + __cxa_thread_atexit; + __cxa_thread_atexit_impl; + abort_handler_s; + ignore_handler_s; + set_constraint_handler_s; +}; + +FBSD_1.6 { + ptsname_r; + qsort_s; + rand; + srand; +}; + +FBSD_1.7 { + clearenv; + qsort_r; + secure_getenv; +}; + +FBSD_1.8 { + getenv_r; +}; + +FBSD_1.9 { + recallocarray; +}; + +FBSDprivate_1.0 { + __system; + _system; + __libc_system; + __cxa_thread_call_dtors; + __libc_atexit; +}; diff --git a/lib/libc/stdlib/_Exit.c b/lib/libc/stdlib/_Exit.c new file mode 100644 index 000000000000..a7af0c9efe80 --- /dev/null +++ b/lib/libc/stdlib/_Exit.c @@ -0,0 +1,20 @@ +/* + * This file is in the public domain. Written by Garrett A. Wollman, + * 2002-09-07. + */ + +#include <stdlib.h> +#include <unistd.h> + +/* + * ISO C99 added this function to provide for Standard C applications + * which needed something like POSIX _exit(). A new interface was created + * in case it turned out that _exit() was insufficient to meet the + * requirements of ISO C. (That's probably not the case, but here + * is where you would put the extra code if it were.) + */ +void +_Exit(int code) +{ + _exit(code); +} diff --git a/lib/libc/stdlib/a64l.3 b/lib/libc/stdlib/a64l.3 new file mode 100644 index 000000000000..517243ddaaed --- /dev/null +++ b/lib/libc/stdlib/a64l.3 @@ -0,0 +1,185 @@ +.\" Copyright (c) 2005 Tom Rhodes +.\" 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 AUTHOR 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 AUTHOR 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. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd November 20, 2005 +.Dt A64L 3 +.Os +.Sh NAME +.Nm a64l , +.Nm l64a , +.Nm l64a_r +.Nd "convert between a long integer and a base-64 ASCII string" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft long +.Fn a64l "const char *s" +.Ft char * +.Fn l64a "long int l" +.Ft int +.Fn l64a_r "long int l" "char *buffer" "int buflen" +.Sh DESCRIPTION +These functions are used to maintain numbers stored in radix-64 +.Tn ASCII +characters. +This is a notation by which 32-bit integers can be represented by +up to six characters; each character represents a digit in +radix-64 notation. +If the type long contains more than 32 bits, only the low-order +32 bits are used for these operations. +.Pp +The characters used to represent +.Dq digits +are +.Ql .\& +for 0, +.Ql / +for 1, +.Ql 0 +- +.Ql 9 +for 2 - 11, +.Ql A +- +.Ql Z +for 12 - 37, and +.Ql a +- +.Ql z +for 38 - 63. +.Pp +The +.Fn a64l +function takes a pointer to a radix-64 representation, in which the first +digit is the least significant, and returns a corresponding +.Vt long +value. +If the string pointed to by +.Fa s +contains more than six characters, +.Fn a64l +uses the first six. +If the first six characters of the string contain a null terminator, +.Fn a64l +uses only characters preceding the null terminator. +The +.Fn a64l +function scans the character string from left to right with the least +significant digit on the left, decoding each character as a 6-bit +radix-64 number. +If the type long contains more than 32 bits, the resulting value is +sign-extended. +The behavior of +.Fn a64l +is unspecified if +.Fa s +is a null pointer or the string pointed to by +.Fa s +was not generated by a previous call to +.Fn l64a . +.Pp +The +.Fn l64a +function takes a +.Vt long +argument and returns a pointer to the corresponding +radix-64 representation. +The behavior of +.Fn l64a +is unspecified if value is negative. +.Pp +The value returned by +.Fn l64a +is a pointer into a static buffer. +Subsequent calls to +.Fn l64a +may overwrite the buffer. +.Pp +The +.Fn l64a_r +function performs a conversion identical to that of +.Fn l64a +and stores the resulting representation in the memory area pointed to by +.Fa buffer , +consuming at most +.Fa buflen +characters including the terminating +.Dv NUL +character. +.Sh RETURN VALUES +On successful completion, +.Fn a64l +returns the +.Vt long +value resulting from conversion of the input string. +If a string pointed to by +.Fa s +is an empty string, +.Fn a64l +returns 0. +.Pp +The +.Fn l64a +function returns a pointer to the radix-64 representation. +If value is 0, +.Fn l64a +returns a pointer to an empty string. +.Sh SEE ALSO +.Xr strtoul 3 +.Sh HISTORY +The +.Fn a64l , +.Fn l64a , +and +.Fn l64a_r +functions are derived from +.Nx +with modifications. +They appeared in +.Fx 6.1 . +.Sh AUTHORS +The +.Fn a64l , +.Fn l64a , +and +.Fn l64a_r +functions +were added to +.Fx +by +.An Tom Rhodes Aq Mt trhodes@FreeBSD.org . +Almost all of this manual page came from the +.Tn POSIX +standard. diff --git a/lib/libc/stdlib/a64l.c b/lib/libc/stdlib/a64l.c new file mode 100644 index 000000000000..71514c502d69 --- /dev/null +++ b/lib/libc/stdlib/a64l.c @@ -0,0 +1,44 @@ +/*- + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + */ + +#if 0 +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: a64l.c,v 1.8 2000/01/22 22:19:19 mycroft Exp $"); +#endif /* not lint */ +#endif + +#include <sys/cdefs.h> +#include <stdlib.h> +#include <inttypes.h> + +#define ADOT 46 /* ASCII '.' */ +#define ASLASH 47 /* ASCII '/' */ +#define A0 48 /* ASCII '0' */ +#define AA 65 /* ASCII 'A' */ +#define Aa 97 /* ASCII 'a' */ + +long +a64l(const char *s) +{ + long shift; + int digit, i, value; + + value = 0; + shift = 0; + for (i = 0; *s != '\0' && i < 6; i++, s++) { + if (*s <= ASLASH) + digit = *s - ASLASH + 1; + else if (*s <= A0 + 9) + digit = *s - A0 + 2; + else if (*s <= AA + 25) + digit = *s - AA + 12; + else + digit = *s - Aa + 38; + + value |= digit << shift; + shift += 6; + } + return (value); +} diff --git a/lib/libc/stdlib/abort.3 b/lib/libc/stdlib/abort.3 new file mode 100644 index 000000000000..2a14eb44c5a7 --- /dev/null +++ b/lib/libc/stdlib/abort.3 @@ -0,0 +1,77 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd May 28, 2018 +.Dt ABORT 3 +.Os +.Sh NAME +.Nm abort +.Nd cause abnormal program termination +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft void +.Fn abort void +.Sh DESCRIPTION +The +.Fn abort +function causes abnormal program termination to occur, unless the +signal +.Dv SIGABRT +is being caught and the signal handler does not return. +.Pp +Any open streams are flushed and closed. +.Sh IMPLEMENTATION NOTES +The +.Fn abort +function is thread-safe. +It is unknown if it is async-cancel-safe. +.Sh RETURN VALUES +The +.Fn abort +function +never returns. +.Sh SEE ALSO +.Xr abort2 2 , +.Xr sigaction 2 , +.Xr exit 3 +.Sh STANDARDS +The +.Fn abort +function +conforms to +.St -p1003.1-90 . +The +.Fn abort +function also conforms to +.St -isoC-99 +with the implementation specific details as noted above. diff --git a/lib/libc/stdlib/abort.c b/lib/libc/stdlib/abort.c new file mode 100644 index 000000000000..02b01cb3db66 --- /dev/null +++ b/lib/libc/stdlib/abort.c @@ -0,0 +1,75 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1985, 1993 + * The Regents of the University of California. 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. + * 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. + */ + +#include "namespace.h" +#include <signal.h> +#include <stdlib.h> +#include <stddef.h> +#include <unistd.h> +#include <pthread.h> +#include "un-namespace.h" + +#include "libc_private.h" + +void +abort(void) +{ + struct sigaction act; + + /* + * POSIX requires we flush stdio buffers on abort. + * XXX ISO C requires that abort() be async-signal-safe. + */ + if (__cleanup) + (*__cleanup)(); + + sigfillset(&act.sa_mask); + /* + * Don't block SIGABRT to give any handler a chance; we ignore + * any errors -- ISO C doesn't allow abort to return anyway. + */ + sigdelset(&act.sa_mask, SIGABRT); + (void)__libc_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL); + (void)raise(SIGABRT); + + /* + * If SIGABRT was ignored, or caught and the handler returns, do + * it again, only harder. + */ + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigfillset(&act.sa_mask); + (void)__libc_sigaction(SIGABRT, &act, NULL); + sigdelset(&act.sa_mask, SIGABRT); + (void)__libc_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL); + (void)raise(SIGABRT); + exit(1); +} diff --git a/lib/libc/stdlib/abs.3 b/lib/libc/stdlib/abs.3 new file mode 100644 index 000000000000..d47f83ea0f73 --- /dev/null +++ b/lib/libc/stdlib/abs.3 @@ -0,0 +1,77 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd April 3, 2022 +.Dt ABS 3 +.Os +.Sh NAME +.Nm abs +.Nd integer absolute value function +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft int +.Fn abs "int j" +.Sh DESCRIPTION +The +.Fn abs +function +computes +the absolute value of the integer +.Fa j . +.Sh RETURN VALUES +The +.Fn abs +function +returns +the absolute value. +.Sh SEE ALSO +.Xr cabs 3 , +.Xr fabs 3 , +.Xr floor 3 , +.Xr hypot 3 , +.Xr imaxabs 3 , +.Xr labs 3 , +.Xr llabs 3 , +.Xr math 3 +.Sh STANDARDS +The +.Fn abs +function conforms to +.St -isoC-99 . +.Sh HISTORY +The +.Fn abs +function first appeared in +.At v6 . +.Sh BUGS +The absolute value of the most negative integer remains negative. diff --git a/lib/libc/stdlib/abs.c b/lib/libc/stdlib/abs.c new file mode 100644 index 000000000000..baed3795bf5e --- /dev/null +++ b/lib/libc/stdlib/abs.c @@ -0,0 +1,38 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. + * 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. + */ + +#include <stdlib.h> + +int +abs(int j) +{ + return(j < 0 ? -j : j); +} diff --git a/lib/libc/stdlib/at_quick_exit.3 b/lib/libc/stdlib/at_quick_exit.3 new file mode 100644 index 000000000000..d92e58fd0433 --- /dev/null +++ b/lib/libc/stdlib/at_quick_exit.3 @@ -0,0 +1,60 @@ +.\" Copyright (c) 2011 David Chisnall +.\" 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 AUTHOR 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 AUTHOR 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. +.\" +.Dd December 7, 2011 +.Dt AT_QUICK_EXIT 3 +.Os +.Sh NAME +.Nm at_quick_exit +.Nd registers a cleanup function to run on quick exit +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft int +.Fn at_quick_exit "void (*func)(void)" +.Sh DESCRIPTION +The +.Fn at_quick_exit +function registers a cleanup function to be called when the program exits as a +result of calling +.Xr quick_exit 3 . +The cleanup functions are called in the reverse order and will not be called if +the program exits by calling +.Xr exit 3 , +.Xr _Exit 3 , +or +.Xr abort 3 . +.Sh RETURN VALUES +The +.Fn at_quick_exit +function returns the value 0 if successful and a non-zero value on failure. +.Sh SEE ALSO +.Xr exit 3 , +.Xr quick_exit 3 +.Sh STANDARDS +The +.Fn at_quick_exit +function conforms to +.St -isoC-2011 . diff --git a/lib/libc/stdlib/atexit.3 b/lib/libc/stdlib/atexit.3 new file mode 100644 index 000000000000..4ff384813550 --- /dev/null +++ b/lib/libc/stdlib/atexit.3 @@ -0,0 +1,100 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Chris Torek and the American National Standards Committee X3, +.\" on Information Processing Systems. +.\" +.\" 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. +.\" +.Dd September 6, 2002 +.Dt ATEXIT 3 +.Os +.Sh NAME +.Nm atexit +.Nd register a function to be called on exit +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft int +.Fn atexit "void (*function)(void)" +.Ft int +.Fn atexit_b "void (^function)(void)" +.Sh DESCRIPTION +The +.Fn atexit +function +registers the given +.Fa function +to be called at program exit, whether via +.Xr exit 3 +or via return from the program's +.Fn main . +Functions so registered are called in reverse order; +no arguments are passed. +.Pp +These functions must not call +.Fn exit ; +if it should be necessary to terminate the process while in such a +function, the +.Xr _exit 2 +function should be used. +(Alternatively, the function may cause abnormal +process termination, for example by calling +.Xr abort 3 . ) +.Pp +At least 32 functions can always be registered, +and more are allowed as long as sufficient memory can be allocated. +.Pp +The +.Fn atexit_b +function behaves identically to +.Fn atexit , +except that it takes a block, rather than a function pointer. +.\" XXX {ATEXIT_MAX} is not implemented yet +.Sh RETURN VALUES +.Rv -std atexit +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er ENOMEM +No memory was available to add the function to the list. +The existing list of functions is unmodified. +.It Bq Er ENOSYS +The +.Fn atexit_b +function was called by a program that did not supply a +.Fn _Block_copy +implementation. +.El +.Sh SEE ALSO +.Xr at_quick_exit 3 , +.Xr exit 3 +.Sh STANDARDS +The +.Fn atexit +function +conforms to +.St -isoC . diff --git a/lib/libc/stdlib/atexit.c b/lib/libc/stdlib/atexit.c new file mode 100644 index 000000000000..6e4a12f9e530 --- /dev/null +++ b/lib/libc/stdlib/atexit.c @@ -0,0 +1,255 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#include "namespace.h" +#include <errno.h> +#include <link.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthread.h> +#include "atexit.h" +#include "un-namespace.h" +#include "block_abi.h" + +#include "libc_private.h" + +/** + * The _Block_copy() function is provided by the block runtime. + */ +__attribute__((weak)) void* +_Block_copy(void*); + +#define ATEXIT_FN_EMPTY 0 +#define ATEXIT_FN_STD 1 +#define ATEXIT_FN_CXA 2 + +static pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER; +static void *current_finalize_dso = NULL; +static bool call_finalize_again = false; + +#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) +#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) +#define _MUTEX_DESTROY(x) if (__isthreaded) _pthread_mutex_destroy(x) + +struct atexit { + struct atexit *next; /* next in list */ + int ind; /* next index in this table */ + struct atexit_fn { + int fn_type; /* ATEXIT_? from above */ + union { + void (*std_func)(void); + void (*cxa_func)(void *); + } fn_ptr; /* function pointer */ + void *fn_arg; /* argument for CXA callback */ + void *fn_dso; /* shared module handle */ + } fns[ATEXIT_SIZE]; /* the table itself */ +}; + +static struct atexit *__atexit; /* points to head of LIFO stack */ +typedef DECLARE_BLOCK(void, atexit_block, void); + +int atexit_b(atexit_block); +int __cxa_atexit(void (*)(void *), void *, void *); + +/* + * Register the function described by 'fptr' to be called at application + * exit or owning shared object unload time. This is a helper function + * for atexit and __cxa_atexit. + */ +static int +atexit_register(struct atexit_fn *fptr) +{ + static struct atexit __atexit0; /* one guaranteed table */ + struct atexit *p; + + _MUTEX_LOCK(&atexit_mutex); + if ((p = __atexit) == NULL) + __atexit = p = &__atexit0; + else while (p->ind >= ATEXIT_SIZE) { + struct atexit *old__atexit; + old__atexit = __atexit; + _MUTEX_UNLOCK(&atexit_mutex); + if ((p = (struct atexit *)malloc(sizeof(*p))) == NULL) + return (-1); + _MUTEX_LOCK(&atexit_mutex); + if (old__atexit != __atexit) { + /* Lost race, retry operation */ + _MUTEX_UNLOCK(&atexit_mutex); + free(p); + _MUTEX_LOCK(&atexit_mutex); + p = __atexit; + continue; + } + p->ind = 0; + p->next = __atexit; + __atexit = p; + } + p->fns[p->ind++] = *fptr; + if (current_finalize_dso != NULL && + current_finalize_dso == fptr->fn_dso) + call_finalize_again = true; + _MUTEX_UNLOCK(&atexit_mutex); + return 0; +} + +/* + * Register a function to be performed at exit. + */ +int +atexit(void (*func)(void)) +{ + struct atexit_fn fn; + int error; + + fn.fn_type = ATEXIT_FN_STD; + fn.fn_ptr.std_func = func; + fn.fn_arg = NULL; + fn.fn_dso = NULL; + + error = atexit_register(&fn); + return (error); +} +__weak_reference(atexit, __libc_atexit); + +/** + * Register a block to be performed at exit. + */ +int +atexit_b(atexit_block func) +{ + struct atexit_fn fn; + int error; + if (_Block_copy == 0) { + errno = ENOSYS; + return -1; + } + func = _Block_copy(func); + + // Blocks are not C++ destructors, but they have the same signature (a + // single void* parameter), so we can pretend that they are. + fn.fn_type = ATEXIT_FN_CXA; + fn.fn_ptr.cxa_func = (void(*)(void*))GET_BLOCK_FUNCTION(func); + fn.fn_arg = func; + fn.fn_dso = NULL; + + error = atexit_register(&fn); + return (error); +} + +/* + * Register a function to be performed at exit or when an shared object + * with given dso handle is unloaded dynamically. + */ +int +__cxa_atexit(void (*func)(void *), void *arg, void *dso) +{ + struct atexit_fn fn; + int error; + + fn.fn_type = ATEXIT_FN_CXA; + fn.fn_ptr.cxa_func = func; + fn.fn_arg = arg; + fn.fn_dso = dso; + + error = atexit_register(&fn); + return (error); +} + +#pragma weak __pthread_cxa_finalize +void __pthread_cxa_finalize(const struct dl_phdr_info *); + +static int global_exit; + +/* + * Call all handlers registered with __cxa_atexit for the shared + * object owning 'dso'. Note: if 'dso' is NULL, then all remaining + * handlers are called. + */ +void +__cxa_finalize(void *dso) +{ + struct dl_phdr_info phdr_info; + struct atexit *p; + struct atexit_fn fn; + int n, has_phdr; + + if (dso != NULL) { + has_phdr = _rtld_addr_phdr(dso, &phdr_info); + } else { + has_phdr = 0; + global_exit = 1; + } + + _MUTEX_LOCK(&atexit_mutex); + current_finalize_dso = dso; + do { + call_finalize_again = false; + for (p = __atexit; p; p = p->next) { + for (n = p->ind; --n >= 0;) { + if (p->fns[n].fn_type == ATEXIT_FN_EMPTY) + continue; /* already been called */ + fn = p->fns[n]; + if (dso != NULL && dso != fn.fn_dso) { + /* wrong DSO ? */ + if (!has_phdr || global_exit || + !__elf_phdr_match_addr(&phdr_info, + fn.fn_ptr.cxa_func)) + continue; + } + /* + Mark entry to indicate that this particular + handler has already been called. + */ + p->fns[n].fn_type = ATEXIT_FN_EMPTY; + _MUTEX_UNLOCK(&atexit_mutex); + + /* Call the function of correct type. */ + if (fn.fn_type == ATEXIT_FN_CXA) + fn.fn_ptr.cxa_func(fn.fn_arg); + else if (fn.fn_type == ATEXIT_FN_STD) + fn.fn_ptr.std_func(); + _MUTEX_LOCK(&atexit_mutex); + } + } + } while (call_finalize_again); + current_finalize_dso = NULL; + _MUTEX_UNLOCK(&atexit_mutex); + if (dso == NULL) + _MUTEX_DESTROY(&atexit_mutex); + + if (has_phdr && !global_exit && &__pthread_cxa_finalize != NULL) + __pthread_cxa_finalize(&phdr_info); +} diff --git a/lib/libc/stdlib/atexit.h b/lib/libc/stdlib/atexit.h new file mode 100644 index 000000000000..3cfe5d3df36d --- /dev/null +++ b/lib/libc/stdlib/atexit.h @@ -0,0 +1,35 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. + * 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. + */ + +/* must be at least 32 to guarantee ANSI conformance */ +#define ATEXIT_SIZE 32 + +void __cxa_finalize(void *dso); diff --git a/lib/libc/stdlib/atof.3 b/lib/libc/stdlib/atof.3 new file mode 100644 index 000000000000..8129d4b77c7f --- /dev/null +++ b/lib/libc/stdlib/atof.3 @@ -0,0 +1,97 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd April 1, 2020 +.Dt ATOF 3 +.Os +.Sh NAME +.Nm atof +.Nd convert +.Tn ASCII +string to double +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft double +.Fn atof "const char *nptr" +.Sh DESCRIPTION +The +.Fn atof +function converts the initial portion of the string pointed to by +.Fa nptr +to +.Vt double +representation. +.Pp +It is equivalent to: +.Bd -literal -offset indent +strtod(nptr, (char **)NULL); +.Ed +.Pp +The decimal point +character is defined in the program's locale (category +.Dv LC_NUMERIC ) . +.Sh IMPLEMENTATION NOTES +The +.Fn atof +function is not thread-safe and also not async-cancel-safe. +.Pp +The +.Fn atof +function has been deprecated by +.Fn strtod +and should not be used in new code. +.Sh ERRORS +The function +.Fn atof +need not affect the value of +.Va errno +on an error. +.Sh SEE ALSO +.Xr atoi 3 , +.Xr atol 3 , +.Xr strtod 3 , +.Xr strtol 3 , +.Xr strtoul 3 +.Sh STANDARDS +The +.Fn atof +function conforms to +.St -p1003.1-90 , +.St -isoC , +and +.St -isoC-99 . +.Sh HISTORY +The +.Fn atof +function appeared in +.At v1 . diff --git a/lib/libc/stdlib/atof.c b/lib/libc/stdlib/atof.c new file mode 100644 index 000000000000..2376249dc65f --- /dev/null +++ b/lib/libc/stdlib/atof.c @@ -0,0 +1,50 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * 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. + */ + +#include <stdlib.h> +#include <xlocale.h> + +double +atof(const char *ascii) +{ + return strtod(ascii, (char **)NULL); +} + +double +atof_l(const char *ascii, locale_t locale) +{ + return strtod_l(ascii, (char **)NULL, locale); +} diff --git a/lib/libc/stdlib/atoi.3 b/lib/libc/stdlib/atoi.3 new file mode 100644 index 000000000000..da03e91de747 --- /dev/null +++ b/lib/libc/stdlib/atoi.3 @@ -0,0 +1,89 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd April 1, 2020 +.Dt ATOI 3 +.Os +.Sh NAME +.Nm atoi +.Nd convert +.Tn ASCII +string to integer +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft int +.Fn atoi "const char *nptr" +.Sh DESCRIPTION +The +.Fn atoi +function converts the initial portion of the string pointed to by +.Fa nptr +to +.Vt int +representation. +.Pp +It is equivalent to: +.Bd -literal -offset indent +(int)strtol(nptr, NULL, 10); +.Ed +.Pp +The +.Fn atoi +function has been deprecated by +.Fn strtol +and should not be used in new code. +.Sh ERRORS +The function +.Fn atoi +need not affect the value of +.Va errno +on an error. +.Sh SEE ALSO +.Xr atof 3 , +.Xr atol 3 , +.Xr strtod 3 , +.Xr strtol 3 , +.Xr strtoul 3 +.Sh STANDARDS +The +.Fn atoi +function conforms to +.St -p1003.1-90 , +.St -isoC , +and +.St -isoC-99 . +.Sh HISTORY +The +.Fn atoi +function appeared in +.At v1 . diff --git a/lib/libc/stdlib/atoi.c b/lib/libc/stdlib/atoi.c new file mode 100644 index 000000000000..7dd888d9b6e7 --- /dev/null +++ b/lib/libc/stdlib/atoi.c @@ -0,0 +1,50 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * 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. + */ + +#include <stdlib.h> +#include <xlocale.h> + +int +atoi(const char *str) +{ + return (int)strtol(str, NULL, 10); +} + +int +atoi_l(const char *str, locale_t locale) +{ + return (int)strtol_l(str, NULL, 10, locale); +} diff --git a/lib/libc/stdlib/atol.3 b/lib/libc/stdlib/atol.3 new file mode 100644 index 000000000000..714c3ac65cfa --- /dev/null +++ b/lib/libc/stdlib/atol.3 @@ -0,0 +1,132 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd May 14, 2013 +.Dt ATOL 3 +.Os +.Sh NAME +.Nm atol , atoll +.Nd convert +.Tn ASCII +string to +.Vt long +or +.Vt "long long" +integer +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft long +.Fn atol "const char *nptr" +.Ft "long long" +.Fn atoll "const char *nptr" +.Sh DESCRIPTION +The +.Fn atol +function converts the initial portion of the string pointed to by +.Fa nptr +to +.Vt long +integer +representation. +.Pp +It is equivalent to: +.Pp +.Dl "strtol(nptr, (char **)NULL, 10);" +.Pp +The +.Fn atoll +function converts the initial portion of the string pointed to by +.Fa nptr +to +.Vt "long long" +integer +representation. +.Pp +It is equivalent to: +.Pp +.Dl "strtoll(nptr, (char **)NULL, 10);" +.Sh COMPATIBILITY +The +.Fx +implementations of the +.Fn atol +and +.Fn atoll +functions are thin wrappers around +.Fn strtol +and +.Fn strtoll +respectively, so these functions will affect the value of +.Va errno +in the same way that the +.Fn strtol +and +.Fn strtoll +functions are able to. +This behavior of +.Fn atol +and +.Fn atoll +is not required by +.St -isoC +or +.St -isoC-99 , +but it is allowed by all of +.St -isoC , St -isoC-99 +and +.St -p1003.1-2001 . +.Sh ERRORS +The functions +.Fn atol +and +.Fn atoll +may affect the value of +.Va errno +on an error. +.Sh SEE ALSO +.Xr atof 3 , +.Xr atoi 3 , +.Xr strtod 3 , +.Xr strtol 3 , +.Xr strtoul 3 +.Sh STANDARDS +The +.Fn atol +function +conforms to +.St -isoC . +The +.Fn atoll +function +conforms to +.St -isoC-99 . diff --git a/lib/libc/stdlib/atol.c b/lib/libc/stdlib/atol.c new file mode 100644 index 000000000000..356efbc99aef --- /dev/null +++ b/lib/libc/stdlib/atol.c @@ -0,0 +1,50 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * 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. + */ + +#include <stdlib.h> +#include <xlocale.h> + +long +atol(const char *str) +{ + return strtol(str, (char **)NULL, 10); +} + +long +atol_l(const char *str, locale_t locale) +{ + return strtol_l(str, (char **)NULL, 10, locale); +} diff --git a/lib/libc/stdlib/atoll.c b/lib/libc/stdlib/atoll.c new file mode 100644 index 000000000000..4819c3f56150 --- /dev/null +++ b/lib/libc/stdlib/atoll.c @@ -0,0 +1,50 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * 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. + */ + +#include <stdlib.h> +#include <xlocale.h> + +long long +atoll(const char *str) +{ + return strtoll(str, (char **)NULL, 10); +} + +long long +atoll_l(const char *str, locale_t locale) +{ + return strtoll_l(str, (char **)NULL, 10, locale); +} diff --git a/lib/libc/stdlib/bsearch.3 b/lib/libc/stdlib/bsearch.3 new file mode 100644 index 000000000000..712be0f98381 --- /dev/null +++ b/lib/libc/stdlib/bsearch.3 @@ -0,0 +1,156 @@ +.\" Copyright (c) 1990, 1991, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd July 17, 2019 +.Dt BSEARCH 3 +.Os +.Sh NAME +.Nm bsearch +.Nd binary search of a sorted table +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft void * +.Fn bsearch "const void *key" "const void *base" "size_t nmemb" "size_t size" "int (*compar) (const void *, const void *)" +.Sh DESCRIPTION +The +.Fn bsearch +function searches an array of +.Fa nmemb +objects, the initial member of which is +pointed to by +.Fa base , +for a member that matches the object pointed to by +.Fa key . +The size of each member of the array is specified by +.Fa size . +.Pp +The contents of the array should be in ascending sorted order according +to the comparison function referenced by +.Fa compar . +The +.Fa compar +routine +is expected to have +two arguments which point to the +.Fa key +object and to an array member, in that order, and should return an integer +less than, equal to, or greater than zero if the +.Fa key +object is found, respectively, to be less than, to match, or be +greater than the array member. +See the +.Fa int_compare +sample function in +.Xr qsort 3 +for a comparison function that is also compatible with +.Fn bsearch . +.Sh RETURN VALUES +The +.Fn bsearch +function returns a pointer to a matching member of the array, or a null +pointer if no match is found. +If two members compare as equal, which member is matched is unspecified. +.Sh EXAMPLES +A sample program that searches people by age in a sorted array: +.Bd -literal +#include <assert.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct person { + const char *name; + int age; +}; + +static int +compare(const void *a, const void *b) +{ + const int *age; + const struct person *person; + + age = a; + person = b; + + return (*age - person->age); +} + +int +main(void) +{ + struct person *friend; + int age; + /* Sorted array */ + const struct person friends[] = { + { "paul", 22 }, + { "anne", 25 }, + { "fred", 25 }, + { "mary", 27 }, + { "mark", 35 }, + { "bill", 50 } + }; + const size_t len = sizeof(friends) / sizeof(friends[0]); + + age = 22; + friend = bsearch(&age, friends, len, sizeof(friends[0]), compare); + assert(strcmp(friend->name, "paul") == 0); + printf("name: %s\enage: %d\en", friend->name, friend->age); + + age = 25; + friend = bsearch(&age, friends, len, sizeof(friends[0]), compare); + + /* + * For multiple elements with the same key, it is implementation + * defined which will be returned + */ + assert(strcmp(friend->name, "fred") == 0 || + strcmp(friend->name, "anne") == 0); + printf("name: %s\enage: %d\en", friend->name, friend->age); + + age = 30; + friend = bsearch(&age, friends, len, sizeof(friends[0]), compare); + assert(friend == NULL); + printf("friend aged 30 not found\en"); +} +.Ed +.Sh SEE ALSO +.Xr db 3 , +.Xr lsearch 3 , +.Xr qsort 3 +.\" .Xr tsearch 3 +.Sh STANDARDS +The +.Fn bsearch +function conforms to +.St -isoC . diff --git a/lib/libc/stdlib/bsearch.c b/lib/libc/stdlib/bsearch.c new file mode 100644 index 000000000000..96c728e1c997 --- /dev/null +++ b/lib/libc/stdlib/bsearch.c @@ -0,0 +1,85 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. + * 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. + */ + +#include <stddef.h> +#include <stdlib.h> + +#ifdef I_AM_BSEARCH_B +#include "block_abi.h" +#define COMPAR(x,y) CALL_BLOCK(compar, x, y) +typedef DECLARE_BLOCK(int, compar_block, const void *, const void *); +#else +#define COMPAR(x,y) compar(x, y) +#endif + +/* + * Perform a binary search. + * + * The code below is a bit sneaky. After a comparison fails, we + * divide the work in half by moving either left or right. If lim + * is odd, moving left simply involves halving lim: e.g., when lim + * is 5 we look at item 2, so we change lim to 2 so that we will + * look at items 0 & 1. If lim is even, the same applies. If lim + * is odd, moving right again involves halving lim, this time moving + * the base up one item past p: e.g., when lim is 5 we change base + * to item 3 and make lim 2 so that we will look at items 3 and 4. + * If lim is even, however, we have to shrink it by one before + * halving: e.g., when lim is 4, we still looked at item 2, so we + * have to make lim 3, then halve, obtaining 1, so that we will only + * look at item 3. + */ +#ifdef I_AM_BSEARCH_B +void * +bsearch_b(const void *key, const void *base0, size_t nmemb, size_t size, + compar_block compar) +#else +void * +bsearch(const void *key, const void *base0, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) +#endif +{ + const char *base = base0; + size_t lim; + int cmp; + const void *p; + + for (lim = nmemb; lim != 0; lim >>= 1) { + p = base + (lim >> 1) * size; + cmp = COMPAR(key, p); + if (cmp == 0) + return ((void *)p); + if (cmp > 0) { /* key > p: move right */ + base = (char *)p + size; + lim--; + } /* else move left */ + } + return (NULL); +} diff --git a/lib/libc/stdlib/bsearch_b.c b/lib/libc/stdlib/bsearch_b.c new file mode 100644 index 000000000000..c60f8cdc8305 --- /dev/null +++ b/lib/libc/stdlib/bsearch_b.c @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2014 David Chisnall + * 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 AUTHOR 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 AUTHOR 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. + */ +#define I_AM_BSEARCH_B +#include "bsearch.c" diff --git a/lib/libc/stdlib/cxa_thread_atexit.c b/lib/libc/stdlib/cxa_thread_atexit.c new file mode 100644 index 000000000000..1715bc6d125c --- /dev/null +++ b/lib/libc/stdlib/cxa_thread_atexit.c @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2017 The FreeBSD Foundation + * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include "libc_private.h" + +int +__cxa_thread_atexit(void (*dtor_func)(void *), void *obj, void *dso_symbol) +{ + + return (__cxa_thread_atexit_hidden(dtor_func, obj, dso_symbol)); +} diff --git a/lib/libc/stdlib/cxa_thread_atexit_impl.c b/lib/libc/stdlib/cxa_thread_atexit_impl.c new file mode 100644 index 000000000000..3123bd12dca8 --- /dev/null +++ b/lib/libc/stdlib/cxa_thread_atexit_impl.c @@ -0,0 +1,151 @@ +/*- + * Copyright (c) 2016 Mahdi Mokhtari <mokhi64@gmail.com> + * Copyright (c) 2016, 2017 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/queue.h> +#include "namespace.h" +#include <errno.h> +#include <link.h> +#include <pthread.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include "un-namespace.h" +#include "libc_private.h" + +/* + * C++11 introduces the thread_local scope (like __thread with some + * additions). As a key-feature it should support non-trivial + * destructors, registered with __cxa_thread_atexit() to be executed + * at the thread termination. + * + * The implemention keeps a _Thread_local list of destructors per each + * thread, and calls __cxa_thread_call_dtors() on each thread's exit + * to do cleanup. For a thread calling exit(3), in particular, for + * the initial thread returning from main(), we call + * __cxa_thread_call_dtors() inside exit(). + * + * It could be possible that a dynamically loaded library, use + * thread_local variable but is dlclose()'d before thread exit. The + * destructor of this variable will then try to access the address, + * for calling it but it's unloaded, so it'll crash. We're using + * __elf_phdr_match_addr() to detect and prevent such cases and so + * prevent the crash. + */ + +#define CXA_DTORS_ITERATIONS 4 + +struct cxa_thread_dtor { + void *obj; + void (*func)(void *); + void *dso; + LIST_ENTRY(cxa_thread_dtor) entry; +}; +static _Thread_local LIST_HEAD(dtor_list, cxa_thread_dtor) dtors = + LIST_HEAD_INITIALIZER(dtors); + +int +__cxa_thread_atexit_impl(void (*dtor_func)(void *), void *obj, + void *dso_symbol) +{ + + return (__cxa_thread_atexit_hidden(dtor_func, obj, dso_symbol)); +} + +int +__cxa_thread_atexit_hidden(void (*dtor_func)(void *), void *obj, + void *dso_symbol) +{ + struct cxa_thread_dtor *new_dtor; + + new_dtor = malloc(sizeof(*new_dtor)); + if (new_dtor == NULL) { + errno = ENOMEM; /* forcibly override malloc(3) error */ + return (-1); + } + + new_dtor->obj = obj; + new_dtor->func = dtor_func; + new_dtor->dso = dso_symbol; + LIST_INSERT_HEAD(&dtors, new_dtor, entry); + return (0); +} + +static void +walk_cb_call(struct cxa_thread_dtor *dtor) +{ + struct dl_phdr_info phdr_info; + + if (_rtld_addr_phdr(dtor->func, &phdr_info) && + __elf_phdr_match_addr(&phdr_info, dtor->func)) + dtor->func(dtor->obj); + else + fprintf(stderr, + "__cxa_thread_call_dtors: dtr %p from unloaded dso, skipping\n", + (void *)(dtor->func)); +} + +static void +walk_cb_nocall(struct cxa_thread_dtor *dtor __unused) +{ +} + +static void +cxa_thread_walk(void (*cb)(struct cxa_thread_dtor *)) +{ + struct cxa_thread_dtor *dtor, *tdtor; + + LIST_FOREACH_SAFE(dtor, &dtors, entry, tdtor) { + LIST_REMOVE(dtor, entry); + cb(dtor); + free(dtor); + } +} + +/* + * This is the callback function we use to call destructors, once for + * each thread. It is called in exit(3) in libc/stdlib/exit.c and + * before exit_thread() in libthr/thread/thr_exit.c. + */ +void +__cxa_thread_call_dtors(void) +{ + int i; + + for (i = 0; i < CXA_DTORS_ITERATIONS && !LIST_EMPTY(&dtors); i++) + cxa_thread_walk(walk_cb_call); + + if (!LIST_EMPTY(&dtors)) { + fprintf(stderr, "Thread %p is exiting with more " + "thread-specific dtors created after %d iterations " + "of destructor calls\n", + _pthread_self(), i); + cxa_thread_walk(walk_cb_nocall); + } +} diff --git a/lib/libc/stdlib/div.3 b/lib/libc/stdlib/div.3 new file mode 100644 index 000000000000..55c1bd107cb7 --- /dev/null +++ b/lib/libc/stdlib/div.3 @@ -0,0 +1,65 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" 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. +.\" +.Dd November 14, 2001 +.Dt DIV 3 +.Os +.Sh NAME +.Nm div +.Nd return quotient and remainder from division +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft div_t +.Fn div "int num" "int denom" +.Sh DESCRIPTION +The +.Fn div +function +computes the value +.Fa num/denom +and returns the quotient and remainder in a structure named +.Fa div_t +that contains two +.Vt int +members named +.Va quot +and +.Va rem . +.Sh SEE ALSO +.Xr imaxdiv 3 , +.Xr ldiv 3 , +.Xr lldiv 3 +.Sh STANDARDS +The +.Fn div +function +conforms to +.St -isoC-99 . diff --git a/lib/libc/stdlib/div.c b/lib/libc/stdlib/div.c new file mode 100644 index 000000000000..351dca870553 --- /dev/null +++ b/lib/libc/stdlib/div.c @@ -0,0 +1,46 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#include <stdlib.h> /* div_t */ + +div_t +div(int num, int denom) +{ + div_t r; + + r.quot = num / denom; + r.rem = num % denom; + + return (r); +} diff --git a/lib/libc/stdlib/exit.3 b/lib/libc/stdlib/exit.3 new file mode 100644 index 000000000000..bfb14c5c9f83 --- /dev/null +++ b/lib/libc/stdlib/exit.3 @@ -0,0 +1,174 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd July 24, 2024 +.Dt EXIT 3 +.Os +.Sh NAME +.Nm exit , _Exit +.Nd perform normal program termination +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft void +.Fn exit "int status" +.Ft void +.Fn _Exit "int status" +.Sh DESCRIPTION +The +.Fn exit +and +.Fn _Exit +functions terminate a process. +.Pp +Before termination, +.Fn exit +performs the following functions in the order listed: +.Bl -enum -offset indent +.It +Call all functions registered with the +.Xr __cxa_atexit 3 +function +(which are typically destructors from the loaded dynamic objects), +and the functions registered with the +.Xr atexit 3 +function, in the reverse order of their registration. +.It +Flush all open output streams. +.It +Close all open streams. +.El +.Pp +The +.Fn _Exit +function terminates without calling the functions registered with the +.Xr atexit 3 +function, and may or may not perform the other actions listed. +The +.Fx +implementation of the +.Fn _Exit +function does not call destructors registered with +.Xr __cxa_atexit 3 , +does not flush buffers, and does not close streams. +.Pp +Both functions make the low-order eight bits of the +.Fa status +argument available to a parent process which has called a +.Xr wait 2 Ns -family +function. +.Pp +The C Standard +.Pq St -isoC-99 +defines the values +.Li 0 , +.Dv EXIT_SUCCESS , +and +.Dv EXIT_FAILURE +as possible values of +.Fa status . +Cooperating processes may use other values; +in a program which might be called by a mail transfer agent, the +values described in +.Xr sysexits 3 +may be used to provide more information to the parent process. +.Pp +The complete +.Fa status +value is avaliable as +.Va si_status +member of the +.Vt siginfo_t +structure, to the +.Xr wait6 2 +and +.Xr sigwaitinfo 2 +callers, and +.Va SIGCHLD +signal handlers. +.Pp +Calls to the +.Fn exit +function are serialized. +All functions registered by +.Xr atexit 3 +are executed in the first thread that called +.Nm exit . +If any other thread of the process calls +.Nm exit +before all registered functions have completed or before the process +terminates, the thread is blocked until the process terminates. +The exit status of the process is the +.Fa status +argument of the first +.Nm exit +call which thread proceeds the atexit handlers. +.Pp +Note that +.Fn exit +does nothing to prevent bottomless recursion should a function registered +using +.Xr atexit 3 +itself call +.Fn exit . +Such functions must call +.Fn _Exit +instead (although this has other effects as well which may not be desired). +.Sh RETURN VALUES +The +.Fn exit +and +.Fn _Exit +functions +never return. +.Sh SEE ALSO +.Xr _exit 2 , +.Xr abort2 2 , +.Xr wait 2 , +.Xr at_quick_exit 3 , +.Xr atexit 3 , +.Xr intro 3 , +.Xr quick_exit 3 , +.Xr sysexits 3 , +.Xr tmpfile 3 +.Sh STANDARDS +The +.Fn exit +and +.Fn _Exit +functions conform to +.St -isoC-99 . +.Sh HISTORY +The +.Fn exit +function appeared in +.At v1 . diff --git a/lib/libc/stdlib/exit.c b/lib/libc/stdlib/exit.c new file mode 100644 index 000000000000..16631fad5b90 --- /dev/null +++ b/lib/libc/stdlib/exit.c @@ -0,0 +1,93 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. + * 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. + */ + +#include "namespace.h" +#include <stdlib.h> +#include <pthread.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "atexit.h" +#include "libc_private.h" + +void (*__cleanup)(void); + +/* + * This variable is zero until a process has created a thread. + * It is used to avoid calling locking functions in libc when they + * are not required. By default, libc is intended to be(come) + * thread-safe, but without a (significant) penalty to non-threaded + * processes. + */ +int __isthreaded = 0; + +static pthread_mutex_t exit_mutex; +static pthread_once_t exit_mutex_once = PTHREAD_ONCE_INIT; + +static void +exit_mutex_init_once(void) +{ + pthread_mutexattr_t ma; + + _pthread_mutexattr_init(&ma); + _pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE); + _pthread_mutex_init(&exit_mutex, &ma); + _pthread_mutexattr_destroy(&ma); +} + +/* + * Exit, flushing stdio buffers if necessary. + */ +void +exit(int status) +{ + /* Ensure that the auto-initialization routine is linked in: */ + extern int _thread_autoinit_dummy_decl; + + _thread_autoinit_dummy_decl = 1; + + /* Make exit(3) thread-safe */ + if (__isthreaded) { + _once(&exit_mutex_once, exit_mutex_init_once); + _pthread_mutex_lock(&exit_mutex); + } + + /* + * We're dealing with cleaning up thread_local destructors in the case of + * the process termination through main() exit. + * Other cases are handled elsewhere. + */ + __cxa_thread_call_dtors(); + __cxa_finalize(NULL); + if (__cleanup) + (*__cleanup)(); + _exit(status); +} diff --git a/lib/libc/stdlib/getenv.3 b/lib/libc/stdlib/getenv.3 new file mode 100644 index 000000000000..045a1831dfdc --- /dev/null +++ b/lib/libc/stdlib/getenv.3 @@ -0,0 +1,302 @@ +.\" Copyright (c) 1988, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd April 22, 2025 +.Dt GETENV 3 +.Os +.Sh NAME +.Nm clearenv , +.Nm getenv , +.Nm getenv_r , +.Nm putenv , +.Nm secure_getenv , +.Nm setenv , +.Nm unsetenv +.Nd environment variable functions +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft int +.Fn clearenv "void" +.Ft char * +.Fn getenv "const char *name" +.Ft int +.Fn getenv_r "const char *name" "char *buf" "size_t len" +.Ft char * +.Fn secure_getenv "const char *name" +.Ft int +.Fn setenv "const char *name" "const char *value" "int overwrite" +.Ft int +.Fn putenv "char *string" +.Ft int +.Fn unsetenv "const char *name" +.Sh DESCRIPTION +These functions set, unset and fetch environment variables from the +host +.Em environment list . +.Pp +The +.Fn clearenv +function clears all environment variables. +New variables can be added using +.Fn setenv +and +.Fn putenv . +.Pp +The +.Fn getenv +function obtains the current value of the environment variable +designated by +.Fa name . +The application should not modify the string pointed +to by the +.Fn getenv +function. +.Pp +The +.Fn getenv_r +function obtains the current value of the environment variable +designated by +.Fa name +and copies it into the buffer +.Fa buf +of length +.Fa len . +.Pp +The +.Fn secure_getenv +returns +.Va NULL +when the environment cannot be trusted, otherwise it acts like +.Fn getenv . +The environment currently is not trusted when +.Xr issetugid 2 +returns a non-zero value, but other conditions may be added +in the future. +.Pp +The +.Fn setenv +function inserts or resets the environment variable +.Fa name +in the current environment list. +If the variable +.Fa name +does not exist in the list, +it is inserted with the given +.Fa value . +If the variable does exist, the argument +.Fa overwrite +is tested; if +.Fa overwrite +is zero, the +variable is not reset, otherwise it is reset +to the given +.Fa value . +.Pp +The +.Fn putenv +function takes an argument of the form ``name=value'' and +puts it directly into the current environment, +so altering the argument shall change the environment. +If the variable +.Fa name +does not exist in the list, +it is inserted with the given +.Fa value . +If the variable +.Fa name +does exist, it is reset to the given +.Fa value . +.Pp +The +.Fn unsetenv +function +deletes all instances of the variable name pointed to by +.Fa name +from the list. +.Pp +If corruption (e.g., a name without a value) is detected while making a copy of +environ for internal usage, then +.Fn setenv , +.Fn unsetenv +and +.Fn putenv +will output a warning to stderr about the issue, drop the corrupt entry and +complete the task without error. +.Sh RETURN VALUES +The +.Fn getenv +function returns the value of the environment variable as a +.Dv NUL Ns +-terminated string. +If the variable +.Fa name +is not in the current environment, +.Dv NULL +is returned. +.Pp +The +.Fn secure_getenv +function returns +.Dv NULL +if the process is in "secure execution," otherwise it will call +.Fn getenv . +.Pp +.Rv -std clearenv getenv_r setenv putenv unsetenv +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er EINVAL +The function +.Fn getenv , +.Fn getenv_r , +.Fn setenv +or +.Fn unsetenv +failed because the +.Fa name +is a +.Dv NULL +pointer, points to an empty string, or points to a string containing an +.Dq Li \&= +character. +.Pp +The function +.Fn putenv +failed because +.Fa string +is a +.Dv NULL +pointer, +.Fa string +is without an +.Dq Li \&= +character or +.Dq Li \&= +is the first character in +.Fa string . +This does not follow the +.Tn POSIX +specification. +.It Bq Er ENOENT +The function +.Fn getenv_r +failed because the requested variable was not found in the +environment. +.It Bq Er ENOMEM +The function +.Fn setenv , +.Fn unsetenv +or +.Fn putenv +failed because they were unable to allocate memory for the environment. +.It Bq Er ERANGE +The function +.Fn getenv_r +failed because the value of the requested variable was too long to fit +in the provided buffer. +.El +.Sh SEE ALSO +.Xr csh 1 , +.Xr sh 1 , +.Xr execve 2 , +.Xr environ 7 +.Sh STANDARDS +The +.Fn getenv +function conforms to +.St -isoC . +The +.Fn setenv , +.Fn putenv +and +.Fn unsetenv +functions conforms to +.St -p1003.1-2001 . +The +.Fn secure_getenv +function conforms to +.St -p1003.1-2024 . +.Sh HISTORY +The functions +.Fn setenv +and +.Fn unsetenv +appeared in +.At v7 . +The +.Fn putenv +function appeared in +.Bx 4.3 Reno . +.Pp +Until +.Fx 7.0 , +.Fn putenv +would make a copy of +.Fa string +and insert it into the environment using +.Fn setenv . +This was changed to use +.Fa string +as the memory location of the ``name=value'' pair to follow the +.Tn POSIX +specification. +.Pp +The +.Fn clearenv +and +.Fn secure_getenv +functions were added in +.Fx 14 . +.Pp +The +.Fn getenv_r +function first appeared in +.Nx 4.0 +and was added in +.Fx 15 . +.Sh BUGS +Successive calls to +.Fn setenv +that assign a larger-sized +.Fa value +than any previous value to the same +.Fa name +will result in a memory leak. +The +.Fx +semantics for this function +(namely, that the contents of +.Fa value +are copied and that old values remain accessible indefinitely) make this +bug unavoidable. +Future versions may eliminate one or both of these +semantic guarantees in order to fix the bug. diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c new file mode 100644 index 000000000000..c1d0b7a559d5 --- /dev/null +++ b/lib/libc/stdlib/getenv.c @@ -0,0 +1,761 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2007-2009 Sean C. Farley <scf@FreeBSD.org> + * 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, + * without modification, immediately at the beginning of the file. + * 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 AUTHOR ``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 AUTHOR 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. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <ssp/ssp.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" +#include "libc_private.h" + +static const char CorruptEnvFindMsg[] = "environment corrupt; unable to find "; +static const char CorruptEnvValueMsg[] = + "environment corrupt; missing value for "; + + +/* + * Standard environ. environ variable is exposed to entire process. + * + * origEnviron: Upon cleanup on unloading of library or failure, this + * allows environ to return to as it was before. + * environSize: Number of variables environ can hold. Can only + * increase. + * intEnviron: Internally-built environ. Exposed via environ during + * (re)builds of the environment. + */ +static char **origEnviron; +static char **intEnviron = NULL; +static int environSize = 0; + +/* + * Array of environment variables built from environ. Each element records: + * name: Pointer to name=value string + * name length: Length of name not counting '=' character + * value: Pointer to value within same string as name + * value size: Size (not length) of space for value not counting the + * nul character + * active state: true/false value to signify whether variable is active. + * Useful since multiple variables with the same name can + * co-exist. At most, one variable can be active at any + * one time. + * putenv: Created from putenv() call. This memory must not be + * reused. + */ +static struct envVars { + size_t nameLen; + size_t valueSize; + char *name; + char *value; + bool active; + bool putenv; +} *envVars = NULL; + +/* + * Environment array information. + * + * envActive: Number of active variables in array. + * envVarsSize: Size of array. + * envVarsTotal: Number of total variables in array (active or not). + */ +static int envActive = 0; +static int envVarsSize = 0; +static int envVarsTotal = 0; + + +/* Deinitialization of new environment. */ +static void __attribute__ ((destructor)) __clean_env_destructor(void); + + +/* + * A simple version of warnx() to avoid the bloat of including stdio in static + * binaries. + */ +static void +__env_warnx(const char *msg, const char *name, size_t nameLen) +{ + static const char nl[] = "\n"; + static const char progSep[] = ": "; + + _write(STDERR_FILENO, _getprogname(), strlen(_getprogname())); + _write(STDERR_FILENO, progSep, sizeof(progSep) - 1); + _write(STDERR_FILENO, msg, strlen(msg)); + _write(STDERR_FILENO, name, nameLen); + _write(STDERR_FILENO, nl, sizeof(nl) - 1); + + return; +} + + +/* + * Inline strlen() for performance. Also, perform check for an equals sign. + * Cheaper here than performing a strchr() later. + */ +static inline size_t +__strleneq(const char *str) +{ + const char *s; + + for (s = str; *s != '\0'; ++s) + if (*s == '=') + return (0); + + return (s - str); +} + + +/* + * Comparison of an environment name=value to a name. + */ +static inline bool +strncmpeq(const char *nameValue, const char *name, size_t nameLen) +{ + if (strncmp(nameValue, name, nameLen) == 0 && nameValue[nameLen] == '=') + return (true); + + return (false); +} + + +/* + * Using environment, returns pointer to value associated with name, if any, + * else NULL. If the onlyActive flag is set to true, only variables that are + * active are returned else all are. + */ +static inline char * +__findenv(const char *name, size_t nameLen, int *envNdx, bool onlyActive) +{ + int ndx; + + /* + * Find environment variable from end of array (more likely to be + * active). A variable created by putenv is always active, or it is not + * tracked in the array. + */ + for (ndx = *envNdx; ndx >= 0; ndx--) + if (envVars[ndx].putenv) { + if (strncmpeq(envVars[ndx].name, name, nameLen)) { + *envNdx = ndx; + return (envVars[ndx].name + nameLen + + sizeof ("=") - 1); + } + } else if ((!onlyActive || envVars[ndx].active) && + (envVars[ndx].nameLen == nameLen && + strncmpeq(envVars[ndx].name, name, nameLen))) { + *envNdx = ndx; + return (envVars[ndx].value); + } + + return (NULL); +} + + +/* + * Using environ, returns pointer to value associated with name, if any, else + * NULL. Used on the original environ passed into the program. + */ +static char * +__findenv_environ(const char *name, size_t nameLen) +{ + int envNdx; + + /* Find variable within environ. */ + for (envNdx = 0; environ[envNdx] != NULL; envNdx++) + if (strncmpeq(environ[envNdx], name, nameLen)) + return (&(environ[envNdx][nameLen + sizeof("=") - 1])); + + return (NULL); +} + + +/* + * Remove variable added by putenv() from variable tracking array. + */ +static void +__remove_putenv(int envNdx) +{ + envVarsTotal--; + if (envVarsTotal > envNdx) + memmove(&(envVars[envNdx]), &(envVars[envNdx + 1]), + (envVarsTotal - envNdx) * sizeof (*envVars)); + memset(&(envVars[envVarsTotal]), 0, sizeof (*envVars)); + + return; +} + + +/* + * Deallocate the environment built from environ as well as environ then set + * both to NULL. Eases debugging of memory leaks. + */ +static void +__clean_env(bool freeVars) +{ + int envNdx; + + /* Deallocate environment and environ if created by *env(). */ + if (envVars != NULL) { + for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--) + /* Free variables or deactivate them. */ + if (envVars[envNdx].putenv) { + if (!freeVars) + __remove_putenv(envNdx); + } else { + if (freeVars) + free(envVars[envNdx].name); + else + envVars[envNdx].active = false; + } + if (freeVars) { + free(envVars); + envVars = NULL; + } else + envActive = 0; + + /* Restore original environ if it has not updated by program. */ + if (origEnviron != NULL) { + if (environ == intEnviron) + environ = origEnviron; + free(intEnviron); + intEnviron = NULL; + environSize = 0; + } + } + + return; +} + + +/* + * Using the environment, rebuild the environ array for use by other C library + * calls that depend upon it. + */ +static int +__rebuild_environ(int newEnvironSize) +{ + char **tmpEnviron; + int envNdx; + int environNdx; + int tmpEnvironSize; + + /* Resize environ. */ + if (newEnvironSize > environSize) { + tmpEnvironSize = newEnvironSize * 2; + tmpEnviron = reallocarray(intEnviron, tmpEnvironSize + 1, + sizeof(*intEnviron)); + if (tmpEnviron == NULL) + return (-1); + environSize = tmpEnvironSize; + intEnviron = tmpEnviron; + } + envActive = newEnvironSize; + + /* Assign active variables to environ. */ + for (envNdx = envVarsTotal - 1, environNdx = 0; envNdx >= 0; envNdx--) + if (envVars[envNdx].active) + intEnviron[environNdx++] = envVars[envNdx].name; + intEnviron[environNdx] = NULL; + + /* Always set environ which may have been replaced by program. */ + environ = intEnviron; + + return (0); +} + + +/* + * Enlarge new environment. + */ +static inline bool +__enlarge_env(void) +{ + int newEnvVarsSize; + struct envVars *tmpEnvVars; + + envVarsTotal++; + if (envVarsTotal > envVarsSize) { + newEnvVarsSize = envVarsTotal * 2; + tmpEnvVars = reallocarray(envVars, newEnvVarsSize, + sizeof(*envVars)); + if (tmpEnvVars == NULL) { + envVarsTotal--; + return (false); + } + envVarsSize = newEnvVarsSize; + envVars = tmpEnvVars; + } + + return (true); +} + + +/* + * Using environ, build an environment for use by standard C library calls. + */ +static int +__build_env(void) +{ + char **env; + int activeNdx; + int envNdx; + int savedErrno; + size_t nameLen; + + /* Check for non-existant environment. */ + if (environ == NULL || environ[0] == NULL) + return (0); + + /* Count environment variables. */ + for (env = environ, envVarsTotal = 0; *env != NULL; env++) + envVarsTotal++; + envVarsSize = envVarsTotal * 2; + + /* Create new environment. */ + envVars = calloc(envVarsSize, sizeof(*envVars)); + if (envVars == NULL) + goto Failure; + + /* Copy environ values and keep track of them. */ + for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--) { + envVars[envNdx].putenv = false; + envVars[envNdx].name = + strdup(environ[envVarsTotal - envNdx - 1]); + if (envVars[envNdx].name == NULL) + goto Failure; + envVars[envNdx].value = strchr(envVars[envNdx].name, '='); + if (envVars[envNdx].value != NULL) { + envVars[envNdx].value++; + envVars[envNdx].valueSize = + strlen(envVars[envNdx].value); + } else { + __env_warnx(CorruptEnvValueMsg, envVars[envNdx].name, + strlen(envVars[envNdx].name)); + errno = EFAULT; + goto Failure; + } + + /* + * Find most current version of variable to make active. This + * will prevent multiple active variables from being created + * during this initialization phase. + */ + nameLen = envVars[envNdx].value - envVars[envNdx].name - 1; + envVars[envNdx].nameLen = nameLen; + activeNdx = envVarsTotal - 1; + if (__findenv(envVars[envNdx].name, nameLen, &activeNdx, + false) == NULL) { + __env_warnx(CorruptEnvFindMsg, envVars[envNdx].name, + nameLen); + errno = EFAULT; + goto Failure; + } + envVars[activeNdx].active = true; + } + + /* Create a new environ. */ + origEnviron = environ; + environ = NULL; + if (__rebuild_environ(envVarsTotal) == 0) + return (0); + +Failure: + savedErrno = errno; + __clean_env(true); + errno = savedErrno; + + return (-1); +} + + +/* + * Destructor function with default argument to __clean_env(). + */ +static void +__clean_env_destructor(void) +{ + __clean_env(true); + + return; +} + + +/* + * Returns the value of a variable or NULL if none are found. + */ +char * +getenv(const char *name) +{ + int envNdx; + size_t nameLen; + + /* Check for malformed name. */ + if (name == NULL || (nameLen = __strleneq(name)) == 0) { + errno = EINVAL; + return (NULL); + } + + /* + * Variable search order: + * 1. Check for an empty environ. This allows an application to clear + * the environment. + * 2. Search the external environ array. + * 3. Search the internal environment. + * + * Since malloc() depends upon getenv(), getenv() must never cause the + * internal environment storage to be generated. + */ + if (environ == NULL || environ[0] == NULL) + return (NULL); + else if (envVars == NULL || environ != intEnviron) + return (__findenv_environ(name, nameLen)); + else { + envNdx = envVarsTotal - 1; + return (__findenv(name, nameLen, &envNdx, true)); + } +} + + +/* + * Like getenv(), but copies the value into the provided buffer. + */ +int +__ssp_real(getenv_r)(const char *name, char *buf, size_t len) +{ + const char *val; + size_t nameLen; + int envNdx; + + if (name == NULL || (nameLen = __strleneq(name)) == 0) { + errno = EINVAL; + return (-1); + } + + if (environ == NULL || environ[0] == NULL) { + val = NULL; + } else if (envVars == NULL || environ != intEnviron) { + val = __findenv_environ(name, nameLen); + } else { + envNdx = envVarsTotal - 1; + val = __findenv(name, nameLen, &envNdx, true); + } + if (val == NULL) { + errno = ENOENT; + return (-1); + } + if (strlcpy(buf, val, len) >= len) { + errno = ERANGE; + return (-1); + } + return (0); +} + + +/* + * Runs getenv() unless the current process is tainted by uid or gid changes, in + * which case it will return NULL. + */ +char * +secure_getenv(const char *name) +{ + if (issetugid()) + return (NULL); + return (getenv(name)); +} + +/* + * Set the value of a variable. Older settings are labeled as inactive. If an + * older setting has enough room to store the new value, it will be reused. No + * previous variables are ever freed here to avoid causing a segmentation fault + * in a user's code. + * + * The variables nameLen and valueLen are passed into here to allow the caller + * to calculate the length by means besides just strlen(). + */ +static int +__setenv(const char *name, size_t nameLen, const char *value, int overwrite) +{ + bool reuse; + char *env; + int envNdx; + int newEnvActive; + size_t valueLen; + + /* Find existing environment variable large enough to use. */ + envNdx = envVarsTotal - 1; + newEnvActive = envActive; + valueLen = strlen(value); + reuse = false; + if (__findenv(name, nameLen, &envNdx, false) != NULL) { + /* Deactivate entry if overwrite is allowed. */ + if (envVars[envNdx].active) { + if (overwrite == 0) + return (0); + envVars[envNdx].active = false; + newEnvActive--; + } + + /* putenv() created variable cannot be reused. */ + if (envVars[envNdx].putenv) + __remove_putenv(envNdx); + + /* Entry is large enough to reuse. */ + else if (envVars[envNdx].valueSize >= valueLen) + reuse = true; + } + + /* Create new variable if none was found of sufficient size. */ + if (! reuse) { + /* Enlarge environment. */ + envNdx = envVarsTotal; + if (!__enlarge_env()) + return (-1); + + /* Create environment entry. */ + envVars[envNdx].name = malloc(nameLen + sizeof ("=") + + valueLen); + if (envVars[envNdx].name == NULL) { + envVarsTotal--; + return (-1); + } + envVars[envNdx].nameLen = nameLen; + envVars[envNdx].valueSize = valueLen; + + /* Save name of name/value pair. */ + env = stpncpy(envVars[envNdx].name, name, nameLen); + *env++ = '='; + } + else + env = envVars[envNdx].value; + + /* Save value of name/value pair. */ + strcpy(env, value); + envVars[envNdx].value = env; + envVars[envNdx].active = true; + newEnvActive++; + + /* No need to rebuild environ if an active variable was reused. */ + if (reuse && newEnvActive == envActive) + return (0); + else + return (__rebuild_environ(newEnvActive)); +} + + +/* + * If the program attempts to replace the array of environment variables + * (environ) environ or sets the first varible to NULL, then deactivate all + * variables and merge in the new list from environ. + */ +static int +__merge_environ(void) +{ + char **env; + char *equals; + + /* + * Internally-built environ has been replaced or cleared (detected by + * using the count of active variables against a NULL as the first value + * in environ). Clean up everything. + */ + if (intEnviron != NULL && (environ != intEnviron || (envActive > 0 && + environ[0] == NULL))) { + /* Deactivate all environment variables. */ + if (envActive > 0) { + origEnviron = NULL; + __clean_env(false); + } + + /* + * Insert new environ into existing, yet deactivated, + * environment array. + */ + origEnviron = environ; + if (origEnviron != NULL) + for (env = origEnviron; *env != NULL; env++) { + if ((equals = strchr(*env, '=')) == NULL) { + __env_warnx(CorruptEnvValueMsg, *env, + strlen(*env)); + errno = EFAULT; + return (-1); + } + if (__setenv(*env, equals - *env, equals + 1, + 1) == -1) + return (-1); + } + } + + return (0); +} + + +/* + * The exposed setenv() that performs a few tests before calling the function + * (__setenv()) that does the actual work of inserting a variable into the + * environment. + */ +int +setenv(const char *name, const char *value, int overwrite) +{ + size_t nameLen; + + /* Check for malformed name. */ + if (name == NULL || (nameLen = __strleneq(name)) == 0) { + errno = EINVAL; + return (-1); + } + + /* Initialize environment. */ + if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) + return (-1); + + return (__setenv(name, nameLen, value, overwrite)); +} + + +/* + * Insert a "name=value" string into the environment. Special settings must be + * made to keep setenv() from reusing this memory block and unsetenv() from + * allowing it to be tracked. + */ +int +putenv(char *string) +{ + char *equals; + int envNdx; + int newEnvActive; + size_t nameLen; + + /* Check for malformed argument. */ + if (string == NULL || (equals = strchr(string, '=')) == NULL || + (nameLen = equals - string) == 0) { + errno = EINVAL; + return (-1); + } + + /* Initialize environment. */ + if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) + return (-1); + + /* Deactivate previous environment variable. */ + envNdx = envVarsTotal - 1; + newEnvActive = envActive; + if (__findenv(string, nameLen, &envNdx, true) != NULL) { + /* Reuse previous putenv slot. */ + if (envVars[envNdx].putenv) { + envVars[envNdx].name = string; + return (__rebuild_environ(envActive)); + } else { + newEnvActive--; + envVars[envNdx].active = false; + } + } + + /* Enlarge environment. */ + envNdx = envVarsTotal; + if (!__enlarge_env()) + return (-1); + + /* Create environment entry. */ + envVars[envNdx].name = string; + envVars[envNdx].nameLen = -1; + envVars[envNdx].value = NULL; + envVars[envNdx].valueSize = -1; + envVars[envNdx].putenv = true; + envVars[envNdx].active = true; + newEnvActive++; + + return (__rebuild_environ(newEnvActive)); +} + + +/* + * Unset variable with the same name by flagging it as inactive. No variable is + * ever freed. + */ +int +unsetenv(const char *name) +{ + int envNdx; + size_t nameLen; + int newEnvActive; + + /* Check for malformed name. */ + if (name == NULL || (nameLen = __strleneq(name)) == 0) { + errno = EINVAL; + return (-1); + } + + /* Initialize environment. */ + if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) + return (-1); + + /* Deactivate specified variable. */ + /* Remove all occurrences. */ + envNdx = envVarsTotal - 1; + newEnvActive = envActive; + while (__findenv(name, nameLen, &envNdx, true) != NULL) { + envVars[envNdx].active = false; + if (envVars[envNdx].putenv) + __remove_putenv(envNdx); + envNdx--; + newEnvActive--; + } + if (newEnvActive != envActive) + __rebuild_environ(newEnvActive); + + return (0); +} + +/* + * Unset all variable by flagging them as inactive. No variable is + * ever freed. + */ +int +clearenv(void) +{ + int ndx; + + /* Initialize environment. */ + if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1)) + return (-1); + + /* Remove from the end to not shuffle memory too much. */ + for (ndx = envVarsTotal - 1; ndx >= 0; ndx--) { + envVars[ndx].active = false; + if (envVars[ndx].putenv) + __remove_putenv(ndx); + } + + __rebuild_environ(0); + + return (0); +} diff --git a/lib/libc/stdlib/getopt.3 b/lib/libc/stdlib/getopt.3 new file mode 100644 index 000000000000..a5b5bff9d1a7 --- /dev/null +++ b/lib/libc/stdlib/getopt.3 @@ -0,0 +1,314 @@ +.\" $NetBSD: getopt.3,v 1.34 2014/06/05 22:09:50 wiz Exp $ +.\" +.\" Copyright (c) 1988, 1991, 1993 +.\" The Regents of the University of California. 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. +.\" 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. +.\" +.Dd June 5, 2014 +.Dt GETOPT 3 +.Os +.Sh NAME +.Nm getopt +.Nd get option character from command line argument list +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Vt extern char *optarg ; +.Vt extern int optind ; +.Vt extern int optopt ; +.Vt extern int opterr ; +.Vt extern int optreset ; +.Ft int +.Fn getopt "int argc" "char * const argv[]" "const char *optstring" +.Sh DESCRIPTION +The +.Fn getopt +function incrementally parses a command line argument list +.Fa argv +and returns the next +.Em known +option character. +An option character is +.Em known +if it has been specified in the string of accepted option characters, +.Fa optstring . +.Pp +The option string +.Fa optstring +may contain the following elements: individual characters, and +characters followed by a colon to indicate an option argument +is to follow. +If an individual character is followed by two colons, then the +option argument is optional; +.Va optarg +is set to the rest of the current +.Va argv +word, or +.Dv NULL +if there were no more characters in the current word. +This is a +.Tn GNU +extension. +For example, an option string +.Li \&"x" +recognizes an option +.Dq Fl x , +and an option string +.Li \&"x:" +recognizes an option and argument +.Dq Fl x Ar argument . +It does not matter to +.Fn getopt +if a following argument has leading white space. +.Pp +On return from +.Fn getopt , +.Va optarg +points to an option argument, if it is anticipated, +and the variable +.Va optind +contains the index to the next +.Fa argv +argument for a subsequent call +to +.Fn getopt . +The variable +.Va optopt +saves the last +.Em known +option character returned by +.Fn getopt . +.Pp +The variables +.Va opterr +and +.Va optind +are both initialized to 1. +The +.Va optind +variable may be set to another value before a set of calls to +.Fn getopt +in order to skip over more or less argv entries. +.Pp +In order to use +.Fn getopt +to evaluate multiple sets of arguments, or to evaluate a single set of +arguments multiple times, +the variable +.Va optreset +must be set to 1 before the second and each additional set of calls to +.Fn getopt , +and the variable +.Va optind +must be reinitialized. +.Pp +The +.Fn getopt +function returns \-1 when the argument list is exhausted. +The interpretation of options in the argument list may be cancelled +by the option +.Ql -- +(double dash) which causes +.Fn getopt +to signal the end of argument processing and return \-1. +When all options have been processed (i.e., up to the first non-option +argument), +.Fn getopt +returns \-1. +.Sh RETURN VALUES +The +.Fn getopt +function returns the next known option character in +.Fa optstring . +If +.Fn getopt +encounters a character not found in +.Fa optstring +or if it detects a missing option argument, +it returns +.Ql \&? +(question mark). +If +.Fa optstring +has a leading +.Ql \&: +then a missing option argument causes +.Ql \&: +to be returned instead of +.Ql \&? . +In either case, the variable +.Va optopt +is set to the character that caused the error. +The +.Fn getopt +function returns \-1 when the argument list is exhausted. +.Sh EXAMPLES +.Bd -literal -compact +#include <unistd.h> +int bflag, ch, fd; + +bflag = 0; +while ((ch = getopt(argc, argv, "bf:")) != -1) { + switch (ch) { + case 'b': + bflag = 1; + break; + case 'f': + if ((fd = open(optarg, O_RDONLY, 0)) \*[Lt] 0) { + (void)fprintf(stderr, + "myname: %s: %s\en", optarg, strerror(errno)); + exit(1); + } + break; + case '?': + default: + usage(); + } +} +argc -= optind; +argv += optind; +.Ed +.Sh DIAGNOSTICS +If the +.Fn getopt +function encounters a character not found in the string +.Fa optstring +or detects +a missing option argument it writes an error message to the +.Dv stderr +and returns +.Ql \&? . +Setting +.Va opterr +to a zero will disable these error messages. +If +.Fa optstring +has a leading +.Ql \&: +then a missing option argument causes a +.Ql \&: +to be returned in addition to suppressing any error messages. +.Pp +Option arguments are allowed to begin with +.Dq Li \- ; +this is reasonable but reduces the amount of error checking possible. +.Sh SEE ALSO +.Xr getopt 1 , +.Xr getopt_long 3 , +.Xr getsubopt 3 +.Sh STANDARDS +The +.Va optreset +variable was added to make it possible to call the +.Fn getopt +function multiple times. +This is an extension to the +.St -p1003.2 +specification. +.Sh HISTORY +The +.Fn getopt +function appeared in +.Bx 4.3 . +.Sh BUGS +The +.Fn getopt +function was once specified to return +.Dv EOF +instead of \-1. +This was changed by +.St -p1003.2-92 +to decouple +.Fn getopt +from +.In stdio.h . +.Pp +A single dash +.Dq Li - +may be specified as a character in +.Fa optstring , +however it should +.Em never +have an argument associated with it. +This allows +.Fn getopt +to be used with programs that expect +.Dq Li - +as an option flag. +This practice is wrong, and should not be used in any current development. +It is provided for backward compatibility +.Em only . +Care should be taken not to use +.Ql \&- +as the first character in +.Fa optstring +to avoid a semantic conflict with +.Tn GNU +.Fn getopt , +which assigns different meaning to an +.Fa optstring +that begins with a +.Ql \&- . +By default, a single dash causes +.Fn getopt +to return \-1. +.Pp +It is also possible to handle digits as option letters. +This allows +.Fn getopt +to be used with programs that expect a number +.Pq Dq Li \&-\&3 +as an option. +This practice is wrong, and should not be used in any current development. +It is provided for backward compatibility +.Em only . +The following code fragment works in most cases. +.Bd -literal -offset indent +int ch; +long length; +char *p, *ep; + +while ((ch = getopt(argc, argv, "0123456789")) != -1) + switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + p = argv[optind - 1]; + if (p[0] == '-' \*[Am]\*[Am] p[1] == ch \*[Am]\*[Am] !p[2]) { + length = ch - '0'; + ep = ""; + } else if (argv[optind] \*[Am]\*[Am] argv[optind][1] == ch) { + length = strtol((p = argv[optind] + 1), + \*[Am]ep, 10); + optind++; + optreset = 1; + } else + usage(); + if (*ep != '\e0') + errx(EX_USAGE, "illegal number -- %s", p); + break; + } +.Ed diff --git a/lib/libc/stdlib/getopt.c b/lib/libc/stdlib/getopt.c new file mode 100644 index 000000000000..2b5e3fa69032 --- /dev/null +++ b/lib/libc/stdlib/getopt.c @@ -0,0 +1,133 @@ +/* $NetBSD: getopt.c,v 1.29 2014/06/05 22:00:22 christos Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. 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. + * 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. + */ + +#include "namespace.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "libc_private.h" + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +static char EMSG[] = ""; +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(int nargc, char * const nargv[], const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || *place == 0) { /* update scanning pointer */ + optreset = 0; + place = nargv[optind]; + if (optind >= nargc || *place++ != '-') { + /* Argument is absent or is not an option */ + place = EMSG; + return (-1); + } + optopt = *place++; + if (optopt == '-' && *place == 0) { + /* "--" => end of options */ + ++optind; + place = EMSG; + return (-1); + } + if (optopt == 0) { + /* Solitary '-', treat as a '-' option + if the program (eg su) is looking for it. */ + place = EMSG; + if (strchr(ostr, '-') == NULL) + return (-1); + optopt = '-'; + } + } else + optopt = *place++; + + /* See if option letter is one the caller wanted... */ + if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) { + if (*place == 0) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", _getprogname(), + optopt); + return (BADCH); + } + + /* Does this option need an argument? */ + if (oli[1] != ':') { + /* don't need argument */ + optarg = NULL; + if (*place == 0) + ++optind; + } else { + /* Option-argument is either the rest of this argument or the + entire next argument. */ + if (*place) + optarg = place; + else if (oli[2] == ':') + /* + * GNU Extension, for optional arguments if the rest of + * the argument is empty, we return NULL + */ + optarg = NULL; + else if (nargc > ++optind) + optarg = nargv[optind]; + else { + /* option-argument absent */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + _getprogname(), optopt); + return (BADCH); + } + place = EMSG; + ++optind; + } + return (optopt); /* return option letter */ +} diff --git a/lib/libc/stdlib/getopt_long.3 b/lib/libc/stdlib/getopt_long.3 new file mode 100644 index 000000000000..d6998d13822a --- /dev/null +++ b/lib/libc/stdlib/getopt_long.3 @@ -0,0 +1,561 @@ +.\" $OpenBSD: getopt_long.3,v 1.10 2004/01/06 23:44:28 fgsch Exp $ +.\" $NetBSD: getopt_long.3,v 1.14 2003/08/07 16:43:40 agc Exp $ +.\" +.\" Copyright (c) 1988, 1991, 1993 +.\" The Regents of the University of California. 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. +.\" 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. +.\" +.Dd December 24, 2022 +.Dt GETOPT_LONG 3 +.Os +.Sh NAME +.Nm getopt_long , +.Nm getopt_long_only +.Nd get long options from command line argument list +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In getopt.h +.Vt extern char *optarg ; +.Vt extern int optind ; +.Vt extern int optopt ; +.Vt extern int opterr ; +.Vt extern int optreset ; +.Ft int +.Fo getopt_long +.Fa "int argc" "char * const *argv" "const char *optstring" +.Fa "const struct option *longopts" "int *longindex" +.Fc +.Ft int +.Fo getopt_long_only +.Fa "int argc" "char * const *argv" "const char *optstring" +.Fa "const struct option *longopts" "int *longindex" +.Fc +.Sh DESCRIPTION +The +.Fn getopt_long +function is similar to +.Xr getopt 3 +but it accepts options in two forms: words and characters. +The +.Fn getopt_long +function provides a superset of the functionality of +.Xr getopt 3 . +The +.Fn getopt_long +function +can be used in two ways. +In the first way, every long option understood +by the program has a corresponding short option, and the option +structure is only used to translate from long options to short +options. +When used in this fashion, +.Fn getopt_long +behaves identically to +.Xr getopt 3 . +This is a good way to add long option processing to an existing program +with the minimum of rewriting. +.Pp +In the second mechanism, a long option sets a flag in the +.Vt option +structure passed, or will store a pointer to the command line argument +in the +.Vt option +structure passed to it for options that take arguments. +Additionally, +the long option's argument may be specified as a single argument with +an equal sign, e.g., +.Pp +.Dl "myprogram --myoption=somevalue" +.Pp +When a long option is processed, the call to +.Fn getopt_long +will return 0. +For this reason, long option processing without +shortcuts is not backwards compatible with +.Xr getopt 3 . +.Pp +It is possible to combine these methods, providing for long options +processing with short option equivalents for some options. +Less +frequently used options would be processed as long options only. +.Pp +The +.Fn getopt_long +call requires a structure to be initialized describing the long +options. +The structure is: +.Bd -literal -offset indent +struct option { + char *name; + int has_arg; + int *flag; + int val; +}; +.Ed +.Pp +The +.Va name +field should contain the option name without the leading double dash. +.Pp +The +.Va has_arg +field should be one of: +.Pp +.Bl -tag -width ".Dv optional_argument" -offset indent -compact +.It Dv no_argument +no argument to the option is expected +.It Dv required_argument +an argument to the option is required +.It Dv optional_argument +an argument to the option may be presented +.El +.Pp +If +.Va flag +is not +.Dv NULL , +then the integer pointed to by it will be set to the +value in the +.Va val +field. +If the +.Va flag +field is +.Dv NULL , +then the +.Va val +field will be returned. +Setting +.Va flag +to +.Dv NULL +and setting +.Va val +to the corresponding short option will make this function act just +like +.Xr getopt 3 . +.Pp +If the +.Fa longindex +field is not +.Dv NULL , +then the integer pointed to by it will be set to the index of the long +option relative to +.Fa longopts . +.Pp +The last element of the +.Fa longopts +array has to be filled with zeroes. +.Pp +The +.Fn getopt_long_only +function behaves identically to +.Fn getopt_long +with the exception that long options may start with +.Ql - +in addition to +.Ql -- . +If an option starting with +.Ql - +does not match a long option but does match a single-character option, +the single-character option is returned. +.Sh RETURN VALUES +If the +.Fa flag +field in +.Vt "struct option" +is +.Dv NULL , +.Fn getopt_long +and +.Fn getopt_long_only +return the value specified in the +.Fa val +field, which is usually just the corresponding short option. +If +.Fa flag +is not +.Dv NULL , +these functions return 0 and store +.Fa val +in the location pointed to by +.Fa flag . +.Pp +These functions return +.Ql \&: +if there was a missing option argument and error messages are suppressed, +.Ql \&? +if the user specified an unknown or ambiguous option, and +\-1 when the argument list has been exhausted. +The default behavior when a missing option argument is encountered is to write +an error and return +.Ql \&? . +Specifying +.Ql \&: +in +.Fa optstring +will cause the error message to be suppressed and +.Ql \&: +to be returned instead. +.Pp +In addition to +.Ql \&: , +a leading +.Ql \&+ +or +.Ql \&- +in +.Fa optstring +also has special meaning. +If either of these are specified, they must appear before +.Ql \&: . +.Pp +A leading +.Ql \&+ +indicates that processing should be halted at the first non-option argument, +matching the default behavior of +.Xr getopt 3 . +The default behavior without +.Ql \&+ +is to permute non-option arguments to the end of +.Fa argv . +.Pp +A leading +.Ql \&- +indicates that all non-option arguments should be treated as if they are +arguments to a literal +.Ql \&1 +flag (i.e., the function call will return the value 1, rather than the char +literal '1'). +.Sh ENVIRONMENT +.Bl -tag -width ".Ev POSIXLY_CORRECT" +.It Ev POSIXLY_CORRECT +If set, option processing stops when the first non-option is found and +a leading +.Ql - +or +.Ql + +in the +.Fa optstring +is ignored. +.El +.Sh EXAMPLES +.Bd -literal -compact +int bflag, ch, fd; +int daggerset; + +/* options descriptor */ +static struct option longopts[] = { + { "buffy", no_argument, NULL, 'b' }, + { "fluoride", required_argument, NULL, 'f' }, + { "daggerset", no_argument, \*[Am]daggerset, 1 }, + { NULL, 0, NULL, 0 } +}; + +bflag = 0; +while ((ch = getopt_long(argc, argv, "bf:", longopts, NULL)) != -1) { + switch (ch) { + case 'b': + bflag = 1; + break; + case 'f': + if ((fd = open(optarg, O_RDONLY, 0)) == -1) + err(1, "unable to open %s", optarg); + break; + case 0: + if (daggerset) { + fprintf(stderr,"Buffy will use her dagger to " + "apply fluoride to dracula's teeth\en"); + } + break; + default: + usage(); + } +} +argc -= optind; +argv += optind; +.Ed +.Sh IMPLEMENTATION DIFFERENCES +This section describes differences to the +.Tn GNU +implementation +found in glibc-2.1.3: +.Bl -bullet +.\" .It +.\" Handling of +.\" .Ql - +.\" as first char of option string in presence of +.\" environment variable +.\" .Ev POSIXLY_CORRECT : +.\" .Bl -tag -width ".Bx" +.\" .It Tn GNU +.\" ignores +.\" .Ev POSIXLY_CORRECT +.\" and returns non-options as +.\" arguments to option '\e1'. +.\" .It Bx +.\" honors +.\" .Ev POSIXLY_CORRECT +.\" and stops at the first non-option. +.\" .El +.\" .It +.\" Handling of +.\" .Ql - +.\" within the option string (not the first character): +.\" .Bl -tag -width ".Bx" +.\" .It Tn GNU +.\" treats a +.\" .Ql - +.\" on the command line as a non-argument. +.\" .It Bx +.\" a +.\" .Ql - +.\" within the option string matches a +.\" .Ql - +.\" (single dash) on the command line. +.\" This functionality is provided for backward compatibility with +.\" programs, such as +.\" .Xr su 1 , +.\" that use +.\" .Ql - +.\" as an option flag. +.\" This practice is wrong, and should not be used in any current development. +.\" .El +.\" .It +.\" Handling of +.\" .Ql :: +.\" in options string in presence of +.\" .Ev POSIXLY_CORRECT : +.\" .Bl -tag -width ".Bx" +.\" .It Both +.\" .Tn GNU +.\" and +.\" .Bx +.\" ignore +.\" .Ev POSIXLY_CORRECT +.\" here and take +.\" .Ql :: +.\" to +.\" mean the preceding option takes an optional argument. +.\" .El +.\" .It +.\" Return value in case of missing argument if first character +.\" (after +.\" .Ql + +.\" or +.\" .Ql - ) +.\" in option string is not +.\" .Ql \&: : +.\" .Bl -tag -width ".Bx" +.\" .It Tn GNU +.\" returns +.\" .Ql \&? +.\" .It Bx +.\" returns +.\" .Ql \&: +.\" (since +.\" .Bx Ns 's +.\" .Fn getopt +.\" does). +.\" .El +.\" .It +.\" Handling of +.\" .Ql --a +.\" in getopt: +.\" .Bl -tag -width ".Bx" +.\" .It Tn GNU +.\" parses this as option +.\" .Ql - , +.\" option +.\" .Ql a . +.\" .It Bx +.\" parses this as +.\" .Ql -- , +.\" and returns \-1 (ignoring the +.\" .Ql a ) . +.\" (Because the original +.\" .Fn getopt +.\" does.) +.\" .El +.It +Setting of +.Va optopt +for long options with +.Va flag +!= +.Dv NULL : +.Bl -tag -width ".Bx" +.It Tn GNU +sets +.Va optopt +to +.Va val . +.It Bx +sets +.Va optopt +to 0 (since +.Va val +would never be returned). +.El +.\" .It +.\" Handling of +.\" .Ql -W +.\" with +.\" .Ql W; +.\" in option string in +.\" .Fn getopt +.\" (not +.\" .Fn getopt_long ) : +.\" .Bl -tag -width ".Bx" +.\" .It Tn GNU +.\" causes a segfault. +.\" .It Bx +.\" no special handling is done; +.\" .Ql W; +.\" is interpreted as two separate options, neither of which take an argument. +.\" .El +.It +Setting of +.Va optarg +for long options without an argument that are +invoked via +.Ql -W +.Ql ( W; +in option string): +.Bl -tag -width ".Bx" +.It Tn GNU +sets +.Va optarg +to the option name (the argument of +.Ql -W ) . +.It Bx +sets +.Va optarg +to +.Dv NULL +(the argument of the long option). +.El +.It +Handling of +.Ql -W +with an argument that is not (a prefix to) a known +long option +.Ql ( W; +in option string): +.Bl -tag -width ".Bx" +.It Tn GNU +returns +.Ql -W +with +.Va optarg +set to the unknown option. +.It Bx +treats this as an error (unknown option) and returns +.Ql \&? +with +.Va optopt +set to 0 and +.Va optarg +set to +.Dv NULL +(as +.Tn GNU Ns 's +man page documents). +.El +.\" .It +.\" The error messages are different. +.It +.Bx +does not permute the argument vector at the same points in +the calling sequence as +.Tn GNU +does. +The aspects normally used by +the caller (ordering after \-1 is returned, value of +.Va optind +relative +to current positions) are the same, though. +(We do fewer variable swaps.) +.El +.Sh SEE ALSO +.Xr getopt 3 +.Sh HISTORY +The +.Fn getopt_long +and +.Fn getopt_long_only +functions first appeared in the +.Tn GNU +libiberty library. +The first +.Bx +implementation of +.Fn getopt_long +appeared in +.Nx 1.5 , +the first +.Bx +implementation of +.Fn getopt_long_only +in +.Ox 3.3 . +.Fx +first included +.Fn getopt_long +in +.Fx 5.0 , +.Fn getopt_long_only +in +.Fx 5.2 . +.Sh BUGS +The +.Fa argv +argument is not really +.Vt const +as its elements may be permuted (unless +.Ev POSIXLY_CORRECT +is set). +.Pp +The implementation can completely replace +.Xr getopt 3 , +but right now we are using separate code. +.Pp +.Nm +makes the assumption that the first argument should always be skipped because +it's typically the program name. +As a result, setting +.Va optind +to 0 will indicate that +.Nm +should reset, and +.Va optind +will be set to 1 in the process. +This behavior differs from +.Xr getopt 3 , +which will handle an +.Va optind +value of 0 as expected and process the first element. diff --git a/lib/libc/stdlib/getopt_long.c b/lib/libc/stdlib/getopt_long.c new file mode 100644 index 000000000000..5cf6a55649bd --- /dev/null +++ b/lib/libc/stdlib/getopt_long.c @@ -0,0 +1,606 @@ +/* $OpenBSD: getopt_long.c,v 1.26 2013/06/08 22:47:56 millert Exp $ */ +/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ + +/* + * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <err.h> +#include <errno.h> +#include <getopt.h> +#include <stdlib.h> +#include <string.h> + +#define GNU_COMPATIBLE /* Be more compatible, configure's use us! */ + +#if 0 /* we prefer to keep our getopt(3) */ +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ +#endif + +#ifdef REPLACE_GETOPT +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ +#endif + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +static char EMSG[] = ""; + +#ifdef GNU_COMPATIBLE +#define NO_PREFIX (-1) +#define D_PREFIX 0 +#define DD_PREFIX 1 +#define W_PREFIX 2 +#endif + +static int getopt_internal(int, char * const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char * const *, const char *, + const struct option *, int *, int, int); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char illoptchar[] = "illegal option -- %c"; /* From P1003.2 */ +#ifdef GNU_COMPATIBLE +static int dash_prefix = NO_PREFIX; +static const char gnuoptchar[] = "invalid option -- %c"; + +static const char recargstring[] = "option `%s%s' requires an argument"; +static const char ambig[] = "option `%s%.*s' is ambiguous"; +static const char noarg[] = "option `%s%.*s' doesn't allow an argument"; +static const char illoptstring[] = "unrecognized option `%s%s'"; +#else +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptstring[] = "unknown option -- %s"; +#endif + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +/* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +parse_long_options(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int short_too, int flags) +{ + char *current_argv, *has_equal; +#ifdef GNU_COMPATIBLE + const char *current_dash; +#endif + size_t current_argv_len; + int i, match, exact_match, second_partial_match; + + current_argv = place; +#ifdef GNU_COMPATIBLE + switch (dash_prefix) { + case D_PREFIX: + current_dash = "-"; + break; + case DD_PREFIX: + current_dash = "--"; + break; + case W_PREFIX: + current_dash = "-W "; + break; + default: + current_dash = ""; + break; + } +#endif + match = -1; + exact_match = 0; + second_partial_match = 0; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + exact_match = 1; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* first partial match */ + match = i; + else if ((flags & FLAG_LONGONLY) || + long_options[i].has_arg != + long_options[match].has_arg || + long_options[i].flag != long_options[match].flag || + long_options[i].val != long_options[match].val) + second_partial_match = 1; + } + if (!exact_match && second_partial_match) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, +#ifdef GNU_COMPATIBLE + current_dash, +#endif + (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, +#ifdef GNU_COMPATIBLE + current_dash, +#endif + (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; +#ifdef GNU_COMPATIBLE + return (BADCH); +#else + return (BADARG); +#endif + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, +#ifdef GNU_COMPATIBLE + current_dash, +#endif + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, +#ifdef GNU_COMPATIBLE + current_dash, +#endif + current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +getopt_internal(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + */ + if (posixly_correct == -1 || optreset) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (*options == '-') + flags |= FLAG_ALLARGS; + else if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + if (*options == '+' || *options == '-') + options++; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || +#ifdef GNU_COMPATIBLE + place[1] == '\0') { +#else + (place[1] == '\0' && strchr(options, '-') == NULL)) { +#endif + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; +#ifdef GNU_COMPATIBLE + dash_prefix = D_PREFIX; +#endif + if (*place == '-') { + place++; /* --foo long option */ + if (*place == '\0') + return (BADARG); /* malformed option */ +#ifdef GNU_COMPATIBLE + dash_prefix = DD_PREFIX; +#endif + } else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too, flags); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; +#ifdef GNU_COMPATIBLE + if (PRINT_ERROR) + warnx(posixly_correct ? illoptchar : gnuoptchar, + optchar); +#else + if (PRINT_ERROR) + warnx(illoptchar, optchar); +#endif + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; +#ifdef GNU_COMPATIBLE + dash_prefix = W_PREFIX; +#endif + optchar = parse_long_options(nargv, options, long_options, + idx, 0, flags); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); +} + +#ifdef REPLACE_GETOPT +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the BSD getopt] + */ +int +getopt(int nargc, char * const *nargv, const char *options) +{ + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +} +#endif /* REPLACE_GETOPT */ + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int +getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); +} diff --git a/lib/libc/stdlib/getsubopt.3 b/lib/libc/stdlib/getsubopt.3 new file mode 100644 index 000000000000..cd2845aefdcb --- /dev/null +++ b/lib/libc/stdlib/getsubopt.3 @@ -0,0 +1,144 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. 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. +.\" 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. +.\" +.Dd December 25, 2011 +.Dt GETSUBOPT 3 +.Os +.Sh NAME +.Nm getsubopt +.Nd get sub options from an argument +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Vt extern char *suboptarg ; +.Ft int +.Fn getsubopt "char **optionp" "char * const *tokens" "char **valuep" +.Sh DESCRIPTION +The +.Fn getsubopt +function +parses a string containing tokens delimited by one or more tab, space or +comma +.Pq Ql \&, +characters. +It is intended for use in parsing groups of option arguments provided +as part of a utility command line. +.Pp +The argument +.Fa optionp +is a pointer to a pointer to the string. +The argument +.Fa tokens +is a pointer to a +.Dv NULL Ns -terminated +array of pointers to strings. +.Pp +The +.Fn getsubopt +function +returns the zero-based offset of the pointer in the +.Fa tokens +array referencing a string which matches the first token +in the string, or, \-1 if the string contains no tokens or +.Fa tokens +does not contain a matching string. +.Pp +If the token is of the form ``name=value'', the location referenced by +.Fa valuep +will be set to point to the start of the ``value'' portion of the token. +.Pp +On return from +.Fn getsubopt , +.Fa optionp +will be set to point to the start of the next token in the string, +or the null at the end of the string if no more tokens are present. +The external variable +.Fa suboptarg +will be set to point to the start of the current token, or +.Dv NULL +if no +tokens were present. +The argument +.Fa valuep +will be set to point to the ``value'' portion of the token, or +.Dv NULL +if no ``value'' portion was present. +.Sh EXAMPLES +.Bd -literal -compact +char *tokens[] = { + #define ONE 0 + "one", + #define TWO 1 + "two", + NULL +}; + +\&... + +extern char *optarg, *suboptarg; +char *options, *value; + +while ((ch = getopt(argc, argv, "ab:")) != \-1) { + switch(ch) { + case 'a': + /* process ``a'' option */ + break; + case 'b': + options = optarg; + while (*options) { + switch(getsubopt(&options, tokens, &value)) { + case ONE: + /* process ``one'' sub option */ + break; + case TWO: + /* process ``two'' sub option */ + if (!value) + error("no value for two"); + i = atoi(value); + break; + case \-1: + if (suboptarg) + error("illegal sub option %s", + suboptarg); + else + error("missing sub option"); + break; + } + } + break; + } +} +.Ed +.Sh SEE ALSO +.Xr getopt 3 , +.Xr strsep 3 +.Sh HISTORY +The +.Fn getsubopt +function first appeared in +.Bx 4.4 . diff --git a/lib/libc/stdlib/getsubopt.c b/lib/libc/stdlib/getsubopt.c new file mode 100644 index 000000000000..8ff0f13655e1 --- /dev/null +++ b/lib/libc/stdlib/getsubopt.c @@ -0,0 +1,91 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. + * 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. + */ + +#include <stdlib.h> +#include <string.h> + +/* + * The SVID interface to getsubopt provides no way of figuring out which + * part of the suboptions list wasn't matched. This makes error messages + * tricky... The extern variable suboptarg is a pointer to the token + * which didn't match. + */ +char *suboptarg; + +int +getsubopt(char **optionp, char * const *tokens, char **valuep) +{ + int cnt; + char *p; + + suboptarg = *valuep = NULL; + + if (!optionp || !*optionp) + return(-1); + + /* skip leading white-space, commas */ + for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); + + if (!*p) { + *optionp = p; + return(-1); + } + + /* save the start of the token, and skip the rest of the token. */ + for (suboptarg = p; + *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';); + + if (*p) { + /* + * If there's an equals sign, set the value pointer, and + * skip over the value part of the token. Terminate the + * token. + */ + if (*p == '=') { + *p = '\0'; + for (*valuep = ++p; + *p && *p != ',' && *p != ' ' && *p != '\t'; ++p); + if (*p) + *p++ = '\0'; + } else + *p++ = '\0'; + /* Skip any whitespace or commas after this token. */ + for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); + } + + /* set optionp for next round. */ + *optionp = p; + + for (cnt = 0; *tokens; ++tokens, ++cnt) + if (!strcmp(suboptarg, *tokens)) + return(cnt); + return(-1); +} diff --git a/lib/libc/stdlib/hcreate.3 b/lib/libc/stdlib/hcreate.3 new file mode 100644 index 000000000000..4621850d4661 --- /dev/null +++ b/lib/libc/stdlib/hcreate.3 @@ -0,0 +1,323 @@ +.\"- +.\" Copyright (c) 1999 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Klaus Klein. +.\" +.\" 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd February 6, 2017 +.Dt HCREATE 3 +.Os +.Sh NAME +.Nm hcreate , +.Nm hcreate_r , +.Nm hdestroy , +.Nm hdestroy_r , +.Nm hsearch , +.Nm hsearch_r +.Nd manage hash search table +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In search.h +.Ft int +.Fn hcreate "size_t nel" +.Ft int +.Fn hcreate_r "size_t nel" "struct hsearch_data *table" +.Ft void +.Fn hdestroy "void" +.Ft void +.Fn hdestroy_r "struct hsearch_data *table" +.Ft ENTRY * +.Fn hsearch "ENTRY item" "ACTION action" +.Ft int +.Fn hsearch_r "ENTRY item" "ACTION action" "ENTRY ** itemp" "struct hsearch_data *table" +.Sh DESCRIPTION +The +.Fn hcreate , +.Fn hcreate_r , +.Fn hdestroy , +.Fn hdestroy_r +.Fn hsearch , +and +.Fn hsearch_r +functions manage hash search tables. +.Pp +The +.Fn hcreate +function allocates sufficient space for the table, and the application should +ensure it is called before +.Fn hsearch +is used. +The +.Fa nel +argument is an estimate of the maximum +number of entries that the table should contain. +As this implementation resizes the hash table dynamically, +this argument is ignored. +.Pp +The +.Fn hdestroy +function disposes of the search table, and may be followed by another call to +.Fn hcreate . +After the call to +.Fn hdestroy , +the data can no longer be considered accessible. +The +.Fn hdestroy +function calls +.Xr free 3 +for each comparison key in the search table +but not the data item associated with the key. +.Pp +The +.Fn hsearch +function is a hash-table search routine. +It returns a pointer into a hash table +indicating the location at which an entry can be found. +The +.Fa item +argument is a structure of type +.Vt ENTRY +(defined in the +.In search.h +header) that contains two pointers: +.Fa item.key +points to the comparison key (a +.Vt "char *" ) , +and +.Fa item.data +(a +.Vt "void *" ) +points to any other data to be associated with +that key. +The comparison function used by +.Fn hsearch +is +.Xr strcmp 3 . +The +.Fa action +argument is a +member of an enumeration type +.Vt ACTION +indicating the disposition of the entry if it cannot be +found in the table. +.Dv ENTER +indicates that the +.Fa item +should be inserted in the table at an +appropriate point. +.Dv FIND +indicates that no entry should be made. +Unsuccessful resolution is +indicated by the return of a +.Dv NULL +pointer. +.Pp +The comparison key (passed to +.Fn hsearch +as +.Fa item.key ) +must be allocated using +.Xr malloc 3 +if +.Fa action +is +.Dv ENTER +and +.Fn hdestroy +is called. +.Pp +The +.Fn hcreate_r , +.Fn hdestroy_r , +and +.Fn hsearch_r +functions are re-entrant versions of the above functions that can +operate on a table supplied by the user. +The +.Fn hsearch_r +function returns +.Dv 0 +if the action is +.Dv ENTER +and the element cannot be created, +.Dv 1 +otherwise. +If the element exists or can be created, it will be placed in +.Fa itemp , +otherwise +.Fa itemp +will be set to +.Dv NULL . +.Sh RETURN VALUES +The +.Fn hcreate +and +.Fn hcreate_r +functions return 0 if the table creation failed and the global variable +.Va errno +is set to indicate the error; +otherwise, a non-zero value is returned. +.Pp +The +.Fn hdestroy +and +.Fn hdestroy_r +functions return no value. +.Pp +The +.Fn hsearch +and +.Fn hsearch_r +functions return a +.Dv NULL +pointer if either the +.Fa action +is +.Dv FIND +and the +.Fa item +could not be found or the +.Fa action +is +.Dv ENTER +and the table is full. +.Sh EXAMPLES +The following example reads in strings followed by two numbers +and stores them in a hash table, discarding duplicates. +It then reads in strings and finds the matching entry in the hash +table and prints it out. +.Bd -literal +#include <stdio.h> +#include <search.h> +#include <string.h> +#include <stdlib.h> + +struct info { /* This is the info stored in the table */ + int age, room; /* other than the key. */ +}; + +#define NUM_EMPL 5000 /* # of elements in search table. */ + +int +main(void) +{ + char str[BUFSIZ]; /* Space to read string */ + struct info info_space[NUM_EMPL]; /* Space to store employee info. */ + struct info *info_ptr = info_space; /* Next space in info_space. */ + ENTRY item; + ENTRY *found_item; /* Name to look for in table. */ + char name_to_find[30]; + int i = 0; + + /* Create table; no error checking is performed. */ + (void) hcreate(NUM_EMPL); + + while (scanf("%s%d%d", str, &info_ptr->age, + &info_ptr->room) != EOF && i++ < NUM_EMPL) { + /* Put information in structure, and structure in item. */ + item.key = strdup(str); + item.data = info_ptr; + info_ptr++; + /* Put item into table. */ + (void) hsearch(item, ENTER); + } + + /* Access table. */ + item.key = name_to_find; + while (scanf("%s", item.key) != EOF) { + if ((found_item = hsearch(item, FIND)) != NULL) { + /* If item is in the table. */ + (void)printf("found %s, age = %d, room = %d\en", + found_item->key, + ((struct info *)found_item->data)->age, + ((struct info *)found_item->data)->room); + } else + (void)printf("no such employee %s\en", name_to_find); + } + hdestroy(); + return 0; +} +.Ed +.Sh ERRORS +The +.Fn hcreate , +.Fn hcreate_r , +.Fn hsearch , +and +.Fn hsearch_r +functions will fail if: +.Bl -tag -width Er +.It Bq Er ENOMEM +Insufficient memory is available. +.El +.Pp +The +.Fn hsearch +and +.Fn hsearch_r +functions will also fail if the action is +.Dv FIND +and the element is not found: +.Bl -tag -width Er +.It Bq Er ESRCH +The +.Fa item +given is not found. +.El +.Sh SEE ALSO +.Xr bsearch 3 , +.Xr lsearch 3 , +.Xr malloc 3 , +.Xr strcmp 3 , +.Xr tsearch 3 +.Sh STANDARDS +The +.Fn hcreate , +.Fn hdestroy , +and +.Fn hsearch +functions conform to +.St -xpg4.2 . +.Sh HISTORY +The +.Fn hcreate , +.Fn hdestroy , +and +.Fn hsearch +functions first appeared in +.At V . +The +.Fn hcreate_r , +.Fn hdestroy_r +and +.Fn hsearch_r +functions are +.Tn GNU +extensions. +.Sh BUGS +The original, +.Pf non- Tn GNU +interface permits the use of only one hash table at a time. diff --git a/lib/libc/stdlib/hcreate.c b/lib/libc/stdlib/hcreate.c new file mode 100644 index 000000000000..261f55bfec39 --- /dev/null +++ b/lib/libc/stdlib/hcreate.c @@ -0,0 +1,72 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <search.h> +#include <stdbool.h> +#include <stddef.h> + +/* + * Thread unsafe interface: use a single process-wide hash table and + * forward calls to *_r() functions. + */ + +static struct hsearch_data global_hashtable; +static bool global_hashtable_initialized = false; + +int +hcreate(size_t nel) +{ + + return (1); +} + +void +hdestroy(void) +{ + + /* Destroy global hash table if present. */ + if (global_hashtable_initialized) { + hdestroy_r(&global_hashtable); + global_hashtable_initialized = false; + } +} + +ENTRY * +hsearch(ENTRY item, ACTION action) +{ + ENTRY *retval; + + /* Create global hash table if needed. */ + if (!global_hashtable_initialized) { + if (hcreate_r(0, &global_hashtable) == 0) + return (NULL); + global_hashtable_initialized = true; + } + if (hsearch_r(item, action, &retval, &global_hashtable) == 0) + return (NULL); + return (retval); +} diff --git a/lib/libc/stdlib/hcreate_r.c b/lib/libc/stdlib/hcreate_r.c new file mode 100644 index 000000000000..90eff3318be9 --- /dev/null +++ b/lib/libc/stdlib/hcreate_r.c @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <search.h> +#include <stdlib.h> + +#include "hsearch.h" + +int +hcreate_r(size_t nel, struct hsearch_data *htab) +{ + struct __hsearch *hsearch; + + /* + * Allocate a hash table object. Ignore the provided hint and start + * off with a table of sixteen entries. In most cases this hint is + * just a wild guess. Resizing the table dynamically if the use + * increases a threshold does not affect the worst-case running time. + */ + hsearch = malloc(sizeof(*hsearch)); + if (hsearch == NULL) + return 0; + hsearch->entries = calloc(16, sizeof(ENTRY)); + if (hsearch->entries == NULL) { + free(hsearch); + return 0; + } + + /* + * Pick a random initialization for the FNV-1a hashing. This makes it + * hard to come up with a fixed set of keys to force hash collisions. + */ + arc4random_buf(&hsearch->offset_basis, sizeof(hsearch->offset_basis)); + hsearch->index_mask = 0xf; + hsearch->entries_used = 0; + htab->__hsearch = hsearch; + return 1; +} diff --git a/lib/libc/stdlib/hdestroy_r.c b/lib/libc/stdlib/hdestroy_r.c new file mode 100644 index 000000000000..e9435c43bca1 --- /dev/null +++ b/lib/libc/stdlib/hdestroy_r.c @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <search.h> +#include <stdlib.h> + +#include "hsearch.h" + +void +hdestroy_r(struct hsearch_data *htab) +{ + struct __hsearch *hsearch; + + /* Free hash table object and its entries. */ + hsearch = htab->__hsearch; + free(hsearch->entries); + free(hsearch); +} diff --git a/lib/libc/stdlib/heapsort.c b/lib/libc/stdlib/heapsort.c new file mode 100644 index 000000000000..7816caf17048 --- /dev/null +++ b/lib/libc/stdlib/heapsort.c @@ -0,0 +1,196 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2014 David T. Chisnall + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ronnie Kon at Mindcraft Inc., Kevin Lew and Elmer Yglesias. + * + * 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. + */ + +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> + +#ifdef I_AM_HEAPSORT_B +#include "block_abi.h" +#define COMPAR(x, y) CALL_BLOCK(compar, x, y) +typedef DECLARE_BLOCK(int, heapsort_block, const void *, const void *); +#else +#define COMPAR(x, y) compar(x, y) +#endif + +/* + * Swap two areas of size number of bytes. Although qsort(3) permits random + * blocks of memory to be sorted, sorting pointers is almost certainly the + * common case (and, were it not, could easily be made so). Regardless, it + * isn't worth optimizing; the SWAP's get sped up by the cache, and pointer + * arithmetic gets lost in the time required for comparison function calls. + */ +#define SWAP(a, b, count, size, tmp) { \ + count = size; \ + do { \ + tmp = *a; \ + *a++ = *b; \ + *b++ = tmp; \ + } while (--count); \ +} + +/* Copy one block of size size to another. */ +#define COPY(a, b, count, size, tmp1, tmp2) { \ + count = size; \ + tmp1 = a; \ + tmp2 = b; \ + do { \ + *tmp1++ = *tmp2++; \ + } while (--count); \ +} + +/* + * Build the list into a heap, where a heap is defined such that for + * the records K1 ... KN, Kj/2 >= Kj for 1 <= j/2 <= j <= N. + * + * There two cases. If j == nmemb, select largest of Ki and Kj. If + * j < nmemb, select largest of Ki, Kj and Kj+1. + */ +#define CREATE(initval, nmemb, par_i, child_i, par, child, size, count, tmp) { \ + for (par_i = initval; (child_i = par_i * 2) <= nmemb; \ + par_i = child_i) { \ + child = base + child_i * size; \ + if (child_i < nmemb && COMPAR(child, child + size) < 0) { \ + child += size; \ + ++child_i; \ + } \ + par = base + par_i * size; \ + if (COMPAR(child, par) <= 0) \ + break; \ + SWAP(par, child, count, size, tmp); \ + } \ +} + +/* + * Select the top of the heap and 'heapify'. Since by far the most expensive + * action is the call to the compar function, a considerable optimization + * in the average case can be achieved due to the fact that k, the displaced + * elememt, is usually quite small, so it would be preferable to first + * heapify, always maintaining the invariant that the larger child is copied + * over its parent's record. + * + * Then, starting from the *bottom* of the heap, finding k's correct place, + * again maintianing the invariant. As a result of the invariant no element + * is 'lost' when k is assigned its correct place in the heap. + * + * The time savings from this optimization are on the order of 15-20% for the + * average case. See Knuth, Vol. 3, page 158, problem 18. + * + * XXX Don't break the #define SELECT line, below. Reiser cpp gets upset. + */ +#define SELECT(par_i, child_i, nmemb, par, child, size, k, count, tmp1, tmp2) { \ + for (par_i = 1; (child_i = par_i * 2) <= nmemb; par_i = child_i) { \ + child = base + child_i * size; \ + if (child_i < nmemb && COMPAR(child, child + size) < 0) { \ + child += size; \ + ++child_i; \ + } \ + par = base + par_i * size; \ + COPY(par, child, count, size, tmp1, tmp2); \ + } \ + for (;;) { \ + child_i = par_i; \ + par_i = child_i / 2; \ + child = base + child_i * size; \ + par = base + par_i * size; \ + if (child_i == 1 || COMPAR(k, par) < 0) { \ + COPY(child, k, count, size, tmp1, tmp2); \ + break; \ + } \ + COPY(child, par, count, size, tmp1, tmp2); \ + } \ +} + +#ifdef I_AM_HEAPSORT_B +int heapsort_b(void *, size_t, size_t, heapsort_block); +#else +int heapsort(void *, size_t, size_t, + int (*)(const void *, const void *)); +#endif +/* + * Heapsort -- Knuth, Vol. 3, page 145. Runs in O (N lg N), both average + * and worst. While heapsort is faster than the worst case of quicksort, + * the BSD quicksort does median selection so that the chance of finding + * a data set that will trigger the worst case is nonexistent. Heapsort's + * only advantage over quicksort is that it requires little additional memory. + */ +#ifdef I_AM_HEAPSORT_B +int +heapsort_b(void *vbase, size_t nmemb, size_t size, heapsort_block compar) +#else +int +heapsort(void *vbase, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) +#endif +{ + size_t cnt, i, j, l; + char tmp, *tmp1, *tmp2; + char *base, *k, *p, *t; + + if (nmemb <= 1) + return (0); + + if (!size) { + errno = EINVAL; + return (-1); + } + + if ((k = malloc(size)) == NULL) + return (-1); + + /* + * Items are numbered from 1 to nmemb, so offset from size bytes + * below the starting address. + */ + base = (char *)vbase - size; + + for (l = nmemb / 2 + 1; --l;) + CREATE(l, nmemb, i, j, t, p, size, cnt, tmp); + + /* + * For each element of the heap, save the largest element into its + * final slot, save the displaced element (k), then recreate the + * heap. + */ + while (nmemb > 1) { + COPY(k, base + nmemb * size, cnt, size, tmp1, tmp2); + COPY(base + nmemb * size, base + size, cnt, size, tmp1, tmp2); + --nmemb; + SELECT(i, j, nmemb, t, p, size, k, cnt, tmp1, tmp2); + } + free(k); + return (0); +} diff --git a/lib/libc/stdlib/heapsort_b.c b/lib/libc/stdlib/heapsort_b.c new file mode 100644 index 000000000000..b030fbe6ee6d --- /dev/null +++ b/lib/libc/stdlib/heapsort_b.c @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2014 David Chisnall + * 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 AUTHOR 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 AUTHOR 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. + */ +#define I_AM_HEAPSORT_B +#include "heapsort.c" diff --git a/lib/libc/stdlib/hsearch.h b/lib/libc/stdlib/hsearch.h new file mode 100644 index 000000000000..2d849357e52d --- /dev/null +++ b/lib/libc/stdlib/hsearch.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#ifndef HSEARCH_H +#define HSEARCH_H + +#include <search.h> + +struct __hsearch { + size_t offset_basis; /* Initial value for FNV-1a hashing. */ + size_t index_mask; /* Bitmask for indexing the table. */ + size_t entries_used; /* Number of entries currently used. */ + ENTRY *entries; /* Hash table entries. */ +}; + +#endif diff --git a/lib/libc/stdlib/hsearch_r.c b/lib/libc/stdlib/hsearch_r.c new file mode 100644 index 000000000000..15c2c156fbec --- /dev/null +++ b/lib/libc/stdlib/hsearch_r.c @@ -0,0 +1,147 @@ +/*- + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <errno.h> +#include <limits.h> +#include <search.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "hsearch.h" + +/* + * Look up an unused entry in the hash table for a given hash. For this + * implementation we use quadratic probing. Quadratic probing has the + * advantage of preventing primary clustering. + */ +static ENTRY * +hsearch_lookup_free(struct __hsearch *hsearch, size_t hash) +{ + size_t index, i; + + for (index = hash, i = 0;; index += ++i) { + ENTRY *entry = &hsearch->entries[index & hsearch->index_mask]; + if (entry->key == NULL) + return (entry); + } +} + +/* + * Computes an FNV-1a hash of the key. Depending on the pointer size, this + * either uses the 32- or 64-bit FNV prime. + */ +static size_t +hsearch_hash(size_t offset_basis, const char *str) +{ + size_t hash; + + hash = offset_basis; + while (*str != '\0') { + hash ^= (uint8_t)*str++; + if (sizeof(size_t) * CHAR_BIT <= 32) + hash *= UINT32_C(16777619); + else + hash *= UINT64_C(1099511628211); + } + return (hash); +} + +int +hsearch_r(ENTRY item, ACTION action, ENTRY **retval, struct hsearch_data *htab) +{ + struct __hsearch *hsearch; + ENTRY *entry, *old_entries, *new_entries; + size_t hash, index, i, old_hash, old_count, new_count; + + hsearch = htab->__hsearch; + hash = hsearch_hash(hsearch->offset_basis, item.key); + + /* + * Search the hash table for an existing entry for this key. + * Stop searching if we run into an unused hash table entry. + */ + for (index = hash, i = 0;; index += ++i) { + entry = &hsearch->entries[index & hsearch->index_mask]; + if (entry->key == NULL) + break; + if (strcmp(entry->key, item.key) == 0) { + *retval = entry; + return (1); + } + } + + /* Only perform the insertion if action is set to ENTER. */ + if (action == FIND) { + errno = ESRCH; + return (0); + } + + if (hsearch->entries_used * 2 >= hsearch->index_mask) { + /* Preserve the old hash table entries. */ + old_count = hsearch->index_mask + 1; + old_entries = hsearch->entries; + + /* + * Allocate and install a new table if insertion would + * yield a hash table that is more than 50% used. By + * using 50% as a threshold, a lookup will only take up + * to two steps on average. + */ + new_count = (hsearch->index_mask + 1) * 2; + new_entries = calloc(new_count, sizeof(ENTRY)); + if (new_entries == NULL) + return (0); + hsearch->entries = new_entries; + hsearch->index_mask = new_count - 1; + + /* Copy over the entries from the old table to the new table. */ + for (i = 0; i < old_count; ++i) { + entry = &old_entries[i]; + if (entry->key != NULL) { + old_hash = hsearch_hash(hsearch->offset_basis, + entry->key); + *hsearch_lookup_free(hsearch, old_hash) = + *entry; + } + } + + /* Destroy the old hash table entries. */ + free(old_entries); + + /* + * Perform a new lookup for a free table entry, so that + * we insert the entry into the new hash table. + */ + hsearch = htab->__hsearch; + entry = hsearch_lookup_free(hsearch, hash); + } + + /* Insert the new entry into the hash table. */ + *entry = item; + ++hsearch->entries_used; + *retval = entry; + return (1); +} diff --git a/lib/libc/stdlib/imaxabs.3 b/lib/libc/stdlib/imaxabs.3 new file mode 100644 index 000000000000..fa68216facc1 --- /dev/null +++ b/lib/libc/stdlib/imaxabs.3 @@ -0,0 +1,60 @@ +.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org> +.\" 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 AUTHOR 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 AUTHOR 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. +.\" +.Dd November 14, 2001 +.Dt IMAXABS 3 +.Os +.Sh NAME +.Nm imaxabs +.Nd returns absolute value +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In inttypes.h +.Ft intmax_t +.Fn imaxabs "intmax_t j" +.Sh DESCRIPTION +The +.Fn imaxabs +function returns the absolute value of +.Fa j . +.Sh SEE ALSO +.Xr abs 3 , +.Xr fabs 3 , +.Xr hypot 3 , +.Xr labs 3 , +.Xr llabs 3 , +.Xr math 3 +.Sh STANDARDS +The +.Fn imaxabs +function conforms to +.St -isoC-99 . +.Sh HISTORY +The +.Fn imaxabs +function first appeared in +.Fx 5.0 . +.Sh BUGS +The absolute value of the most negative integer remains negative. diff --git a/lib/libc/stdlib/imaxabs.c b/lib/libc/stdlib/imaxabs.c new file mode 100644 index 000000000000..08a27ac98da7 --- /dev/null +++ b/lib/libc/stdlib/imaxabs.c @@ -0,0 +1,35 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org> + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <inttypes.h> + +intmax_t +imaxabs(intmax_t j) +{ + return (j < 0 ? -j : j); +} diff --git a/lib/libc/stdlib/imaxdiv.3 b/lib/libc/stdlib/imaxdiv.3 new file mode 100644 index 000000000000..1553a81edae2 --- /dev/null +++ b/lib/libc/stdlib/imaxdiv.3 @@ -0,0 +1,71 @@ +.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org> +.\" 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 AUTHOR 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 AUTHOR 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. +.\" +.Dd November 14, 2001 +.Dt IMAXDIV 3 +.Os +.Sh NAME +.Nm imaxdiv +.Nd returns quotient and remainder +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In inttypes.h +.Ft imaxdiv_t +.Fn imaxdiv "intmax_t numer" "intmax_t denom" +.Sh DESCRIPTION +The +.Fn imaxdiv +function computes the value of +.Fa numer +divided by +.Fa denom +and returns the stored result in the form of the +.Vt imaxdiv_t +type. +.Pp +The +.Vt imaxdiv_t +type is defined as: +.Bd -literal -offset indent +typedef struct { + intmax_t quot; /* Quotient. */ + intmax_t rem; /* Remainder. */ +} imaxdiv_t; +.Ed +.Sh SEE ALSO +.Xr div 3 , +.Xr ldiv 3 , +.Xr lldiv 3 , +.Xr math 3 +.Sh STANDARDS +The +.Fn imaxdiv +function conforms to +.St -isoC-99 . +.Sh HISTORY +The +.Fn imaxdiv +function first appeared in +.Fx 5.0 . diff --git a/lib/libc/stdlib/imaxdiv.c b/lib/libc/stdlib/imaxdiv.c new file mode 100644 index 000000000000..bf9737a3c47a --- /dev/null +++ b/lib/libc/stdlib/imaxdiv.c @@ -0,0 +1,41 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org> + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <inttypes.h> + +/* See comments in div.c for implementation details. */ +imaxdiv_t +imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t retval; + + retval.quot = numer / denom; + retval.rem = numer % denom; + + return (retval); +} diff --git a/lib/libc/stdlib/insque.3 b/lib/libc/stdlib/insque.3 new file mode 100644 index 000000000000..5ae44273dd00 --- /dev/null +++ b/lib/libc/stdlib/insque.3 @@ -0,0 +1,59 @@ +.\" +.\" Initial implementation: +.\" Copyright (c) 2002 Robert Drehmel +.\" All rights reserved. +.\" +.\" As long as the above copyright statement and this notice remain +.\" unchanged, you can do what ever you want with this file. +.\" +.Dd October 10, 2002 +.Dt INSQUE 3 +.Os +.Sh NAME +.Nm insque , +.Nm remque +.Nd doubly-linked list management +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In search.h +.Ft void +.Fn insque "void *element1" "void *pred" +.Ft void +.Fn remque "void *element" +.Sh DESCRIPTION +The +.Fn insque +and +.Fn remque +functions encapsulate the ever-repeating task of doing insertion and +removal operations on doubly linked lists. +The functions expect their +arguments to point to a structure whose first and second members are +pointers to the next and previous element, respectively. +The +.Fn insque +function also allows the +.Fa pred +argument to be a +.Dv NULL +pointer for the initialization of a new list's +head element. +.Sh STANDARDS +The +.Fn insque +and +.Fn remque +functions conform to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn insque +and +.Fn remque +functions appeared in +.Bx 4.2 . +In +.Fx 5.0 , +they reappeared conforming to +.St -p1003.1-2001 . diff --git a/lib/libc/stdlib/insque.c b/lib/libc/stdlib/insque.c new file mode 100644 index 000000000000..3af31eb15554 --- /dev/null +++ b/lib/libc/stdlib/insque.c @@ -0,0 +1,44 @@ +/* + * Initial implementation: + * Copyright (c) 2002 Robert Drehmel + * All rights reserved. + * + * As long as the above copyright statement and this notice remain + * unchanged, you can do what ever you want with this file. + */ +#define _SEARCH_PRIVATE +#include <search.h> +#ifdef DEBUG +#include <stdio.h> +#else +#include <stdlib.h> /* for NULL */ +#endif + +void +insque(void *element, void *pred) +{ + struct que_elem *prev, *next, *elem; + + elem = (struct que_elem *)element; + prev = (struct que_elem *)pred; + + if (prev == NULL) { + elem->prev = elem->next = NULL; + return; + } + + next = prev->next; + if (next != NULL) { +#ifdef DEBUG + if (next->prev != prev) { + fprintf(stderr, "insque: Inconsistency detected:" + " next(%p)->prev(%p) != prev(%p)\n", + next, next->prev, prev); + } +#endif + next->prev = elem; + } + prev->next = elem; + elem->prev = prev; + elem->next = next; +} diff --git a/lib/libc/stdlib/l64a.c b/lib/libc/stdlib/l64a.c new file mode 100644 index 000000000000..5be50118d274 --- /dev/null +++ b/lib/libc/stdlib/l64a.c @@ -0,0 +1,42 @@ +/* + * Written by J.T. Conklin <jtc@NetBSD.org>. + * Public domain. + */ + +#if 0 +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: l64a.c,v 1.13 2003/07/26 19:24:54 salo Exp $"); +#endif /* not lint */ +#endif + +#include <sys/cdefs.h> +#include <stdint.h> +#include <stdlib.h> + +char * +l64a(long value) +{ + static char buf[7]; + + (void)l64a_r(value, buf, sizeof(buf)); + return (buf); +} + +int +l64a_r(long value, char *buffer, int buflen) +{ + static const char chars[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + uint32_t v; + + v = value; + while (buflen-- > 0) { + if (v == 0) { + *buffer = '\0'; + return (0); + } + *buffer++ = chars[v & 0x3f]; + v >>= 6; + } + return (-1); +} diff --git a/lib/libc/stdlib/labs.3 b/lib/libc/stdlib/labs.3 new file mode 100644 index 000000000000..97f527b7d941 --- /dev/null +++ b/lib/libc/stdlib/labs.3 @@ -0,0 +1,64 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd November 14, 2001 +.Dt LABS 3 +.Os +.Sh NAME +.Nm labs +.Nd return the absolute value of a long integer +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft long +.Fn labs "long j" +.Sh DESCRIPTION +The +.Fn labs +function +returns the absolute value of the long integer +.Fa j . +.Sh SEE ALSO +.Xr abs 3 , +.Xr cabs 3 , +.Xr floor 3 , +.Xr imaxabs 3 , +.Xr llabs 3 , +.Xr math 3 +.Sh STANDARDS +The +.Fn labs +function +conforms to +.St -isoC . +.Sh BUGS +The absolute value of the most negative integer remains negative. diff --git a/lib/libc/stdlib/labs.c b/lib/libc/stdlib/labs.c new file mode 100644 index 000000000000..23696f1c0f0c --- /dev/null +++ b/lib/libc/stdlib/labs.c @@ -0,0 +1,38 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. + * 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. + */ + +#include <stdlib.h> + +long +labs(long j) +{ + return(j < 0 ? -j : j); +} diff --git a/lib/libc/stdlib/ldiv.3 b/lib/libc/stdlib/ldiv.3 new file mode 100644 index 000000000000..66abb00d4d6c --- /dev/null +++ b/lib/libc/stdlib/ldiv.3 @@ -0,0 +1,74 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Chris Torek and the American National Standards Committee X3, +.\" on Information Processing Systems. +.\" +.\" 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. +.\" +.Dd April 3, 2022 +.Dt LDIV 3 +.Os +.Sh NAME +.Nm ldiv +.Nd return quotient and remainder from division +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft ldiv_t +.Fn ldiv "long num" "long denom" +.Sh DESCRIPTION +The +.Fn ldiv +function +computes the value +.Fa num Ns / Ns Fa denom +and returns the quotient and remainder in a structure named +.Vt ldiv_t +that contains two +.Vt long +members named +.Va quot +and +.Va rem . +.Sh SEE ALSO +.Xr div 3 , +.Xr imaxdiv 3 , +.Xr lldiv 3 , +.Xr math 3 +.Sh STANDARDS +The +.Fn ldiv +function +conforms to +.St -isoC-99 . +.Sh HISTORY +An +.Fn ldiv +function with similar functionality, but a different calling convention, +first appeared in +.At v4 . diff --git a/lib/libc/stdlib/ldiv.c b/lib/libc/stdlib/ldiv.c new file mode 100644 index 000000000000..4c73bcc14af4 --- /dev/null +++ b/lib/libc/stdlib/ldiv.c @@ -0,0 +1,48 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + */ + +#include <stdlib.h> /* ldiv_t */ + +ldiv_t +ldiv(long num, long denom) +{ + ldiv_t r; + + /* see div.c for comments */ + + r.quot = num / denom; + r.rem = num % denom; + + return (r); +} diff --git a/lib/libc/stdlib/llabs.3 b/lib/libc/stdlib/llabs.3 new file mode 100644 index 000000000000..6a12fd539dc6 --- /dev/null +++ b/lib/libc/stdlib/llabs.3 @@ -0,0 +1,60 @@ +.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org> +.\" 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 AUTHOR 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 AUTHOR 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. +.\" +.Dd November 14, 2001 +.Dt LLABS 3 +.Os +.Sh NAME +.Nm llabs +.Nd returns absolute value +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft "long long" +.Fn llabs "long long j" +.Sh DESCRIPTION +The +.Fn llabs +function returns the absolute value of +.Fa j . +.Sh SEE ALSO +.Xr abs 3 , +.Xr fabs 3 , +.Xr hypot 3 , +.Xr imaxabs 3 , +.Xr labs 3 , +.Xr math 3 +.Sh STANDARDS +The +.Fn llabs +function conforms to +.St -isoC-99 . +.Sh HISTORY +The +.Fn llabs +function first appeared in +.Fx 5.0 . +.Sh BUGS +The absolute value of the most negative integer remains negative. diff --git a/lib/libc/stdlib/llabs.c b/lib/libc/stdlib/llabs.c new file mode 100644 index 000000000000..ac151e3a5036 --- /dev/null +++ b/lib/libc/stdlib/llabs.c @@ -0,0 +1,35 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org> + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <stdlib.h> + +long long +llabs(long long j) +{ + return (j < 0 ? -j : j); +} diff --git a/lib/libc/stdlib/lldiv.3 b/lib/libc/stdlib/lldiv.3 new file mode 100644 index 000000000000..d1de4e9234e3 --- /dev/null +++ b/lib/libc/stdlib/lldiv.3 @@ -0,0 +1,71 @@ +.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org> +.\" 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 AUTHOR 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 AUTHOR 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. +.\" +.Dd November 14, 2001 +.Dt LLDIV 3 +.Os +.Sh NAME +.Nm lldiv +.Nd returns quotient and remainder +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft lldiv_t +.Fn lldiv "long long numer" "long long denom" +.Sh DESCRIPTION +The +.Fn lldiv +function computes the value of +.Fa numer +divided by +.Fa denom +and returns the stored result in the form of the +.Vt lldiv_t +type. +.Pp +The +.Vt lldiv_t +type is defined as: +.Bd -literal -offset indent +typedef struct { + long long quot; /* Quotient. */ + long long rem; /* Remainder. */ +} lldiv_t; +.Ed +.Sh SEE ALSO +.Xr div 3 , +.Xr imaxdiv 3 , +.Xr ldiv 3 , +.Xr math 3 +.Sh STANDARDS +The +.Fn lldiv +function conforms to +.St -isoC-99 . +.Sh HISTORY +The +.Fn lldiv +function first appeared in +.Fx 5.0 . diff --git a/lib/libc/stdlib/lldiv.c b/lib/libc/stdlib/lldiv.c new file mode 100644 index 000000000000..6feeb74bacd6 --- /dev/null +++ b/lib/libc/stdlib/lldiv.c @@ -0,0 +1,41 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org> + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <stdlib.h> + +/* See comments in div.c for implementation details. */ +lldiv_t +lldiv(long long numer, long long denom) +{ + lldiv_t retval; + + retval.quot = numer / denom; + retval.rem = numer % denom; + + return (retval); +} diff --git a/lib/libc/stdlib/lsearch.3 b/lib/libc/stdlib/lsearch.3 new file mode 100644 index 000000000000..5433acfb9bfb --- /dev/null +++ b/lib/libc/stdlib/lsearch.3 @@ -0,0 +1,144 @@ +.\" +.\" Initial implementation: +.\" Copyright (c) 2002 Robert Drehmel +.\" All rights reserved. +.\" +.\" As long as the above copyright statement and this notice remain +.\" unchanged, you can do what ever you want with this file. +.\" +.Dd April 17, 2016 +.Dt LSEARCH 3 +.Os +.Sh NAME +.Nm lsearch , +.Nm lfind +.Nd linear search and append +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In search.h +.Ft "void *" +.Fo lsearch +.Fa "const void *key" "void *base" "size_t *nelp" "size_t width" +.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]" +.Fc +.Ft "void *" +.Fo lfind +.Fa "const void *key" "const void *base" "size_t *nelp" "size_t width" +.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]" +.Fc +.Sh DESCRIPTION +The +.Fn lsearch +and +.Fn lfind +functions walk linearly through an array and compare each element with +the one to be sought using a supplied comparison function. +.Pp +The +.Fa key +argument +points to an element that matches the one that is searched. +The array's address in memory is denoted by the +.Fa base +argument. +The width of one element (i.e., the size as returned by +.Fn sizeof ) +is passed as the +.Fa width +argument. +The number of valid elements contained in the array (not the number of +elements the array has space reserved for) is given in the integer pointed +to by +.Fa nelp . +The +.Fa compar +argument points to a function which compares its two arguments and returns +zero if they are matching, and non-zero otherwise. +.Pp +If no matching element was found in the array, +.Fn lsearch +copies +.Fa key +into the position after the last element and increments the +integer pointed to by +.Fa nelp . +.Sh RETURN VALUES +The +.Fn lsearch +and +.Fn lfind +functions +return a pointer to the first element found. +If no element was found, +.Fn lsearch +returns a pointer to the newly added element, whereas +.Fn lfind +returns +.Dv NULL . +Both functions return +.Dv NULL +if an error occurs. +.Sh EXAMPLES +.Bd -literal +#include <search.h> +#include <stdio.h> +#include <stdlib.h> + +static int +element_compare(const void *p1, const void *p2) +{ + int left = *(const int *)p1; + int right = *(const int *)p2; + + return (left - right); +} + +int +main(int argc, char **argv) +{ + const int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + size_t element_size = sizeof(array[0]); + size_t array_size = sizeof(array) / element_size; + int key; + void *element; + + printf("Enter a number: "); + if (scanf("%d", &key) != 1) { + printf("Bad input\en"); + return (EXIT_FAILURE); + } + + element = lfind(&key, array, &array_size, element_size, + element_compare); + + if (element != NULL) + printf("Element found: %d\en", *(int *)element); + else + printf("Element not found\en"); + + return (EXIT_SUCCESS); +} +.Ed +.Sh SEE ALSO +.Xr bsearch 3 , +.Xr hsearch 3 , +.Xr tsearch 3 +.Sh STANDARDS +The +.Fn lsearch +and +.Fn lfind +functions conform to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn lsearch +and +.Fn lfind +functions appeared in +.Bx 4.2 . +In +.Fx 5.0 , +they reappeared conforming to +.St -p1003.1-2001 . diff --git a/lib/libc/stdlib/lsearch.c b/lib/libc/stdlib/lsearch.c new file mode 100644 index 000000000000..e2b83473411e --- /dev/null +++ b/lib/libc/stdlib/lsearch.c @@ -0,0 +1,57 @@ +/* + * Initial implementation: + * Copyright (c) 2002 Robert Drehmel + * All rights reserved. + * + * As long as the above copyright statement and this notice remain + * unchanged, you can do what ever you want with this file. + */ +#include <sys/types.h> +#define _SEARCH_PRIVATE +#include <search.h> +#include <stdint.h> /* for uint8_t */ +#include <stdlib.h> /* for NULL */ +#include <string.h> /* for memcpy() prototype */ + +static void *lwork(const void *, const void *, size_t *, size_t, + int (*)(const void *, const void *), int); + +void *lsearch(const void *key, void *base, size_t *nelp, size_t width, + int (*compar)(const void *, const void *)) +{ + + return (lwork(key, base, nelp, width, compar, 1)); +} + +void *lfind(const void *key, const void *base, size_t *nelp, size_t width, + int (*compar)(const void *, const void *)) +{ + + return (lwork(key, base, nelp, width, compar, 0)); +} + +static void * +lwork(const void *key, const void *base, size_t *nelp, size_t width, + int (*compar)(const void *, const void *), int addelem) +{ + uint8_t *ep, *endp; + + ep = __DECONST(uint8_t *, base); + for (endp = (uint8_t *)(ep + width * *nelp); ep < endp; ep += width) { + if (compar(key, ep) == 0) + return (ep); + } + + /* lfind() shall return when the key was not found. */ + if (!addelem) + return (NULL); + + /* + * lsearch() adds the key to the end of the table and increments + * the number of elements. + */ + memcpy(endp, key, width); + ++*nelp; + + return (endp); +} diff --git a/lib/libc/stdlib/malloc/Makefile.inc b/lib/libc/stdlib/malloc/Makefile.inc new file mode 100644 index 000000000000..3bae4ff1505b --- /dev/null +++ b/lib/libc/stdlib/malloc/Makefile.inc @@ -0,0 +1,3 @@ +SYM_MAPS+=${LIBC_SRCTOP}/stdlib/malloc/Symbol.map + +.include "${LIBC_SRCTOP}/stdlib/malloc/${OPT_LIBC_MALLOC}/Makefile.inc" diff --git a/lib/libc/stdlib/malloc/Symbol.map b/lib/libc/stdlib/malloc/Symbol.map new file mode 100644 index 000000000000..d3aa7f3f9988 --- /dev/null +++ b/lib/libc/stdlib/malloc/Symbol.map @@ -0,0 +1,55 @@ +FBSD_1.0 { + _malloc_options; + _malloc_message; + malloc; + posix_memalign; + calloc; + realloc; + free; + malloc_usable_size; +}; + +FBSD_1.3 { + malloc_conf; + malloc_message; + aligned_alloc; + malloc_stats_print; + mallctl; + mallctlnametomib; + mallctlbymib; + mallocx; + rallocx; + xallocx; + sallocx; + dallocx; + nallocx; + __malloc; + __calloc; + __realloc; + __free; + __posix_memalign; + __malloc_usable_size; + __mallocx; + __rallocx; + __xallocx; + __sallocx; + __dallocx; + __nallocx; +}; + +FBSD_1.4 { + sdallocx; + __sdallocx; + __aligned_alloc; + __malloc_stats_print; + __mallctl; + __mallctlnametomib; + __mallctlbymib; +}; + +FBSDprivate_1.0 { + _malloc_thread_cleanup; + _malloc_prefork; + _malloc_postfork; + _malloc_first_thread; +}; diff --git a/lib/libc/stdlib/malloc/jemalloc/Makefile.inc b/lib/libc/stdlib/malloc/jemalloc/Makefile.inc new file mode 100644 index 000000000000..7722a7b755f3 --- /dev/null +++ b/lib/libc/stdlib/malloc/jemalloc/Makefile.inc @@ -0,0 +1,52 @@ +.PATH: ${LIBC_SRCTOP}/stdlib/malloc/jemalloc + +JEMALLOCSRCS:= jemalloc.c arena.c background_thread.c base.c bin.c bitmap.c \ + ckh.c ctl.c div.c extent.c extent_dss.c extent_mmap.c hook.c \ + large.c log.c malloc_io.c mutex.c nstime.c pages.c \ + prof.c rtree.c safety_check.c sc.c stats.c sz.c tcache.c \ + test_hooks.c ticker.c tsd.c witness.c \ + bin_info.c san.c san_bump.c counter.c prof_data.c prof_log.c prof_recent.c prof_stats.c prof_sys.c \ + emap.c edata.c edata_cache.c pa.c pa_extra.c pac.c decay.c hpa.c hpa_hooks.c fxp.c hpdata.c pai.c \ + ecache.c ehooks.c eset.c sec.c cache_bin.c peak_event.c psset.c inspect.c exp_grow.c thread_event.c \ + buf_writer.c + +CFLAGS+=-I${SRCTOP}/contrib/jemalloc/include -I${LIBC_SRCTOP}/stdlib/malloc/jemalloc/include +.if ${MK_JEMALLOC_LG_VADDR_WIDE} != no +CFLAGS+=-D_USE_LG_VADDR_WIDE +.endif +CFLAGS.gcc+=-Wno-error=missing-braces + + +.for src in ${JEMALLOCSRCS} +MISRCS+=jemalloc_${src} +CLEANFILES+=jemalloc_${src} +jemalloc_${src}: ${SRCTOP}/contrib/jemalloc/src/${src} .NOMETA + ln -sf ${.ALLSRC} ${.TARGET} +.endfor + +MAN+= jemalloc.3 + +MLINKS+= \ + jemalloc.3 malloc.3 \ + jemalloc.3 calloc.3 \ + jemalloc.3 posix_memalign.3 \ + jemalloc.3 aligned_alloc.3 \ + jemalloc.3 realloc.3 \ + jemalloc.3 free.3 \ + jemalloc.3 malloc_usable_size.3 \ + jemalloc.3 malloc_stats_print.3 \ + jemalloc.3 mallctl.3 \ + jemalloc.3 mallctlnametomib.3 \ + jemalloc.3 mallctlbymib.3 \ + jemalloc.3 mallocx.3 \ + jemalloc.3 rallocx.3 \ + jemalloc.3 xallocx.3 \ + jemalloc.3 sallocx.3 \ + jemalloc.3 dallocx.3 \ + jemalloc.3 sdallocx.3 \ + jemalloc.3 nallocx.3 \ + jemalloc.3 malloc.conf.5 + +.if ${MK_MALLOC_PRODUCTION} != "no" || defined(MALLOC_PRODUCTION) +CFLAGS+= -DMALLOC_PRODUCTION +.endif diff --git a/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h new file mode 100644 index 000000000000..900ae867f321 --- /dev/null +++ b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h @@ -0,0 +1,428 @@ +/* include/jemalloc/internal/jemalloc_internal_defs.h. Generated from jemalloc_internal_defs.h.in by configure. */ +#ifndef JEMALLOC_INTERNAL_DEFS_H_ +#define JEMALLOC_INTERNAL_DEFS_H_ +/* + * If JEMALLOC_PREFIX is defined via --with-jemalloc-prefix, it will cause all + * public APIs to be prefixed. This makes it possible, with some care, to use + * multiple allocators simultaneously. + */ +/* #undef JEMALLOC_PREFIX */ +/* #undef JEMALLOC_CPREFIX */ + +/* + * Define overrides for non-standard allocator-related functions if they are + * present on the system. + */ +/* #undef JEMALLOC_OVERRIDE___LIBC_CALLOC */ +/* #undef JEMALLOC_OVERRIDE___LIBC_FREE */ +/* #undef JEMALLOC_OVERRIDE___LIBC_MALLOC */ +/* #undef JEMALLOC_OVERRIDE___LIBC_MEMALIGN */ +/* #undef JEMALLOC_OVERRIDE___LIBC_REALLOC */ +/* #undef JEMALLOC_OVERRIDE___LIBC_VALLOC */ +#define JEMALLOC_OVERRIDE___POSIX_MEMALIGN + +/* + * JEMALLOC_PRIVATE_NAMESPACE is used as a prefix for all library-private APIs. + * For shared libraries, symbol visibility mechanisms prevent these symbols + * from being exported, but for static libraries, naming collisions are a real + * possibility. + */ +#define JEMALLOC_PRIVATE_NAMESPACE __je_ + +/* + * Hyper-threaded CPUs may need a special instruction inside spin loops in + * order to yield to another virtual CPU. + */ +#define CPU_SPINWAIT __asm__ volatile("pause") +/* 1 if CPU_SPINWAIT is defined, 0 otherwise. */ +#define HAVE_CPU_SPINWAIT 1 + +/* + * Number of significant bits in virtual addresses. This may be less than the + * total number of bits in a pointer, e.g. on x64, for which the uppermost 16 + * bits are the same as bit 47. + */ +#define LG_VADDR 48 + +/* Defined if C11 atomics are available. */ +#define JEMALLOC_C11_ATOMICS + +/* Defined if GCC __atomic atomics are available. */ +#define JEMALLOC_GCC_ATOMIC_ATOMICS +/* and the 8-bit variant support. */ +#define JEMALLOC_GCC_U8_ATOMIC_ATOMICS + +/* Defined if GCC __sync atomics are available. */ +#define JEMALLOC_GCC_SYNC_ATOMICS +/* and the 8-bit variant support. */ +#define JEMALLOC_GCC_U8_SYNC_ATOMICS + +/* + * Defined if __builtin_clz() and __builtin_clzl() are available. + */ +#define JEMALLOC_HAVE_BUILTIN_CLZ + +/* + * Defined if os_unfair_lock_*() functions are available, as provided by Darwin. + */ +/* #undef JEMALLOC_OS_UNFAIR_LOCK */ + +/* Defined if syscall(2) is usable. */ +#define JEMALLOC_USE_SYSCALL + +/* + * Defined if secure_getenv(3) is available. + */ +#define JEMALLOC_HAVE_SECURE_GETENV + +/* + * Defined if issetugid(2) is available. + */ +#define JEMALLOC_HAVE_ISSETUGID + +/* Defined if pthread_atfork(3) is available. */ +#define JEMALLOC_HAVE_PTHREAD_ATFORK + +/* Defined if pthread_setname_np(3) is available. */ +#define JEMALLOC_HAVE_PTHREAD_SETNAME_NP + +/* Defined if pthread_getname_np(3) is available. */ +#define JEMALLOC_HAVE_PTHREAD_GETNAME_NP + +/* Defined if pthread_get_name_np(3) is available. */ +#define JEMALLOC_HAVE_PTHREAD_GET_NAME_NP + +/* + * Defined if clock_gettime(CLOCK_MONOTONIC_COARSE, ...) is available. + */ +#define JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE + +/* + * Defined if clock_gettime(CLOCK_MONOTONIC, ...) is available. + */ +#define JEMALLOC_HAVE_CLOCK_MONOTONIC + +/* + * Defined if mach_absolute_time() is available. + */ +/* #undef JEMALLOC_HAVE_MACH_ABSOLUTE_TIME */ + +/* + * Defined if clock_gettime(CLOCK_REALTIME, ...) is available. + */ +#define JEMALLOC_HAVE_CLOCK_REALTIME + +/* + * Defined if _malloc_thread_cleanup() exists. At least in the case of + * FreeBSD, pthread_key_create() allocates, which if used during malloc + * bootstrapping will cause recursion into the pthreads library. Therefore, if + * _malloc_thread_cleanup() exists, use it as the basis for thread cleanup in + * malloc_tsd. + */ +#define JEMALLOC_MALLOC_THREAD_CLEANUP + +/* + * Defined if threaded initialization is known to be safe on this platform. + * Among other things, it must be possible to initialize a mutex without + * triggering allocation in order for threaded allocation to be safe. + */ +/* #undef JEMALLOC_THREADED_INIT */ + +/* + * Defined if the pthreads implementation defines + * _pthread_mutex_init_calloc_cb(), in which case the function is used in order + * to avoid recursive allocation during mutex initialization. + */ +#define JEMALLOC_MUTEX_INIT_CB + +/* Non-empty if the tls_model attribute is supported. */ +#define JEMALLOC_TLS_MODEL __attribute__((tls_model("initial-exec"))) + +/* + * JEMALLOC_DEBUG enables assertions and other sanity checks, and disables + * inline functions. + */ +/* #undef JEMALLOC_DEBUG */ + +/* JEMALLOC_STATS enables statistics calculation. */ +#define JEMALLOC_STATS + +/* JEMALLOC_EXPERIMENTAL_SMALLOCX_API enables experimental smallocx API. */ +/* #undef JEMALLOC_EXPERIMENTAL_SMALLOCX_API */ + +/* JEMALLOC_PROF enables allocation profiling. */ +/* #undef JEMALLOC_PROF */ + +/* Use libunwind for profile backtracing if defined. */ +/* #undef JEMALLOC_PROF_LIBUNWIND */ + +/* Use libgcc for profile backtracing if defined. */ +/* #undef JEMALLOC_PROF_LIBGCC */ + +/* Use gcc intrinsics for profile backtracing if defined. */ +/* #undef JEMALLOC_PROF_GCC */ + +/* + * JEMALLOC_DSS enables use of sbrk(2) to allocate extents from the data storage + * segment (DSS). + */ +#define JEMALLOC_DSS + +/* Support memory filling (junk/zero). */ +#define JEMALLOC_FILL + +/* Support utrace(2)-based tracing. */ +#define JEMALLOC_UTRACE + +/* Support utrace(2)-based tracing (label based signature). */ +/* #undef JEMALLOC_UTRACE_LABEL */ + +/* Support optional abort() on OOM. */ +#define JEMALLOC_XMALLOC + +/* Support lazy locking (avoid locking unless a second thread is launched). */ +#define JEMALLOC_LAZY_LOCK + +/* + * Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size + * classes). + */ +/* #undef LG_QUANTUM */ + +/* One page is 2^LG_PAGE bytes. */ +#define LG_PAGE 12 + +/* Maximum number of regions in a slab. */ +/* #undef CONFIG_LG_SLAB_MAXREGS */ + +/* + * One huge page is 2^LG_HUGEPAGE bytes. Note that this is defined even if the + * system does not explicitly support huge pages; system calls that require + * explicit huge page support are separately configured. + */ +#define LG_HUGEPAGE 21 + +/* + * If defined, adjacent virtual memory mappings with identical attributes + * automatically coalesce, and they fragment when changes are made to subranges. + * This is the normal order of things for mmap()/munmap(), but on Windows + * VirtualAlloc()/VirtualFree() operations must be precisely matched, i.e. + * mappings do *not* coalesce/fragment. + */ +#define JEMALLOC_MAPS_COALESCE + +/* + * If defined, retain memory for later reuse by default rather than using e.g. + * munmap() to unmap freed extents. This is enabled on 64-bit Linux because + * common sequences of mmap()/munmap() calls will cause virtual memory map + * holes. + */ +/* #undef JEMALLOC_RETAIN */ + +/* TLS is used to map arenas and magazine caches to threads. */ +#define JEMALLOC_TLS + +/* + * Used to mark unreachable code to quiet "end of non-void" compiler warnings. + * Don't use this directly; instead use unreachable() from util.h + */ +#define JEMALLOC_INTERNAL_UNREACHABLE __builtin_unreachable + +/* + * ffs*() functions to use for bitmapping. Don't use these directly; instead, + * use ffs_*() from util.h. + */ +#define JEMALLOC_INTERNAL_FFSLL __builtin_ffsll +#define JEMALLOC_INTERNAL_FFSL __builtin_ffsl +#define JEMALLOC_INTERNAL_FFS __builtin_ffs + +/* + * popcount*() functions to use for bitmapping. + */ +#define JEMALLOC_INTERNAL_POPCOUNTL __builtin_popcountl +#define JEMALLOC_INTERNAL_POPCOUNT __builtin_popcount + +/* + * If defined, explicitly attempt to more uniformly distribute large allocation + * pointer alignments across all cache indices. + */ +#define JEMALLOC_CACHE_OBLIVIOUS + +/* + * If defined, enable logging facilities. We make this a configure option to + * avoid taking extra branches everywhere. + */ +/* #undef JEMALLOC_LOG */ + +/* + * If defined, use readlinkat() (instead of readlink()) to follow + * /etc/malloc_conf. + */ +/* #undef JEMALLOC_READLINKAT */ + +/* + * Darwin (OS X) uses zones to work around Mach-O symbol override shortcomings. + */ +/* #undef JEMALLOC_ZONE */ + +/* + * Methods for determining whether the OS overcommits. + * JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY: Linux's + * /proc/sys/vm.overcommit_memory file. + * JEMALLOC_SYSCTL_VM_OVERCOMMIT: FreeBSD's vm.overcommit sysctl. + */ +#define JEMALLOC_SYSCTL_VM_OVERCOMMIT +/* #undef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY */ + +/* Defined if madvise(2) is available. */ +#define JEMALLOC_HAVE_MADVISE + +/* + * Defined if transparent huge pages are supported via the MADV_[NO]HUGEPAGE + * arguments to madvise(2). + */ +/* #undef JEMALLOC_HAVE_MADVISE_HUGE */ + +/* + * Methods for purging unused pages differ between operating systems. + * + * madvise(..., MADV_FREE) : This marks pages as being unused, such that they + * will be discarded rather than swapped out. + * madvise(..., MADV_DONTNEED) : If JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS is + * defined, this immediately discards pages, + * such that new pages will be demand-zeroed if + * the address region is later touched; + * otherwise this behaves similarly to + * MADV_FREE, though typically with higher + * system overhead. + */ +#define JEMALLOC_PURGE_MADVISE_FREE +#define JEMALLOC_PURGE_MADVISE_DONTNEED +/* #undef JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS */ + +/* Defined if madvise(2) is available but MADV_FREE is not (x86 Linux only). */ +/* #undef JEMALLOC_DEFINE_MADVISE_FREE */ + +/* + * Defined if MADV_DO[NT]DUMP is supported as an argument to madvise. + */ +/* #undef JEMALLOC_MADVISE_DONTDUMP */ + +/* + * Defined if MADV_[NO]CORE is supported as an argument to madvise. + */ +#define JEMALLOC_MADVISE_NOCORE + +/* Defined if mprotect(2) is available. */ +#define JEMALLOC_HAVE_MPROTECT + +/* + * Defined if transparent huge pages (THPs) are supported via the + * MADV_[NO]HUGEPAGE arguments to madvise(2), and THP support is enabled. + */ +/* #undef JEMALLOC_THP */ + +/* Defined if posix_madvise is available. */ +/* #undef JEMALLOC_HAVE_POSIX_MADVISE */ + +/* + * Method for purging unused pages using posix_madvise. + * + * posix_madvise(..., POSIX_MADV_DONTNEED) + */ +/* #undef JEMALLOC_PURGE_POSIX_MADVISE_DONTNEED */ +/* #undef JEMALLOC_PURGE_POSIX_MADVISE_DONTNEED_ZEROS */ + +/* + * Defined if memcntl page admin call is supported + */ +/* #undef JEMALLOC_HAVE_MEMCNTL */ + +/* + * Defined if malloc_size is supported + */ +/* #undef JEMALLOC_HAVE_MALLOC_SIZE */ + +/* Define if operating system has alloca.h header. */ +/* #undef JEMALLOC_HAS_ALLOCA_H */ + +/* C99 restrict keyword supported. */ +#define JEMALLOC_HAS_RESTRICT + +/* For use by hash code. */ +/* #undef JEMALLOC_BIG_ENDIAN */ + +/* sizeof(int) == 2^LG_SIZEOF_INT. */ +#define LG_SIZEOF_INT 2 + +/* sizeof(long) == 2^LG_SIZEOF_LONG. */ +#define LG_SIZEOF_LONG 3 + +/* sizeof(long long) == 2^LG_SIZEOF_LONG_LONG. */ +#define LG_SIZEOF_LONG_LONG 3 + +/* sizeof(intmax_t) == 2^LG_SIZEOF_INTMAX_T. */ +#define LG_SIZEOF_INTMAX_T 3 + +/* glibc malloc hooks (__malloc_hook, __realloc_hook, __free_hook). */ +/* #undef JEMALLOC_GLIBC_MALLOC_HOOK */ + +/* glibc memalign hook. */ +/* #undef JEMALLOC_GLIBC_MEMALIGN_HOOK */ + +/* pthread support */ +#define JEMALLOC_HAVE_PTHREAD + +/* dlsym() support */ +#define JEMALLOC_HAVE_DLSYM + +/* Adaptive mutex support in pthreads. */ +#define JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP + +/* GNU specific sched_getcpu support */ +#define JEMALLOC_HAVE_SCHED_GETCPU + +/* GNU specific sched_setaffinity support */ +#define JEMALLOC_HAVE_SCHED_SETAFFINITY + +/* + * If defined, all the features necessary for background threads are present. + */ +#define JEMALLOC_BACKGROUND_THREAD + +/* + * If defined, jemalloc symbols are not exported (doesn't work when + * JEMALLOC_PREFIX is not defined). + */ +/* #undef JEMALLOC_EXPORT */ + +/* config.malloc_conf options string. */ +#define JEMALLOC_CONFIG_MALLOC_CONF "abort_conf:false" + +/* If defined, jemalloc takes the malloc/free/etc. symbol names. */ +#define JEMALLOC_IS_MALLOC + +/* + * Defined if strerror_r returns char * if _GNU_SOURCE is defined. + */ +/* #undef JEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE */ + +/* Performs additional safety checks when defined. */ +/* #undef JEMALLOC_OPT_SAFETY_CHECKS */ + +/* Is C++ support being built? */ +#define JEMALLOC_ENABLE_CXX + +/* Performs additional size checks when defined. */ +/* #undef JEMALLOC_OPT_SIZE_CHECKS */ + +/* Allows sampled junk and stash for checking use-after-free when defined. */ +/* #undef JEMALLOC_UAF_DETECTION */ + +/* Darwin VM_MAKE_TAG support */ +/* #undef JEMALLOC_HAVE_VM_MAKE_TAG */ + +/* If defined, realloc(ptr, 0) defaults to "free" instead of "alloc". */ +/* #undef JEMALLOC_ZERO_REALLOC_DEFAULT_FREE */ + +#endif /* JEMALLOC_INTERNAL_DEFS_H_ */ diff --git a/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/jemalloc_internal_defs_FreeBSD.h b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/jemalloc_internal_defs_FreeBSD.h new file mode 100644 index 000000000000..0dab1296d849 --- /dev/null +++ b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/jemalloc_internal_defs_FreeBSD.h @@ -0,0 +1,9 @@ +#ifndef __clang__ +# undef JEMALLOC_INTERNAL_UNREACHABLE +# define JEMALLOC_INTERNAL_UNREACHABLE abort + +# undef JEMALLOC_C11_ATOMICS +# undef JEMALLOC_GCC_ATOMIC_ATOMICS +# undef JEMALLOC_GCC_U8_ATOMIC_ATOMICS +# undef JEMALLOC_GCC_U8_SYNC_ATOMICS +#endif diff --git a/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/jemalloc_preamble.h b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/jemalloc_preamble.h new file mode 100644 index 000000000000..b6cf5864109d --- /dev/null +++ b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/jemalloc_preamble.h @@ -0,0 +1,262 @@ +#ifndef JEMALLOC_PREAMBLE_H +#define JEMALLOC_PREAMBLE_H + +#include "jemalloc_internal_defs.h" +#include "jemalloc/internal/jemalloc_internal_decls.h" + +#if defined(JEMALLOC_UTRACE) || defined(JEMALLOC_UTRACE_LABEL) +#include <sys/ktrace.h> +# if defined(JEMALLOC_UTRACE) +# define UTRACE_CALL(p, l) utrace(p, l) +# else +# define UTRACE_CALL(p, l) utrace("jemalloc_process", p, l) +# define JEMALLOC_UTRACE +# endif +#endif + +#ifndef JEMALLOC_PRIVATE_NAMESPACE +#include "un-namespace.h" +#include "libc_private.h" +#endif + +#define JEMALLOC_NO_DEMANGLE +#ifdef JEMALLOC_JET +# undef JEMALLOC_IS_MALLOC +# define JEMALLOC_N(n) jet_##n +# include "jemalloc/internal/public_namespace.h" +# define JEMALLOC_NO_RENAME +# include "../jemalloc.h" +# undef JEMALLOC_NO_RENAME +#else +# define JEMALLOC_N(n) __je_##n +# include "../jemalloc.h" +#endif + +#if defined(JEMALLOC_OSATOMIC) +#include <libkern/OSAtomic.h> +#endif + +#ifdef JEMALLOC_ZONE +#include <mach/mach_error.h> +#include <mach/mach_init.h> +#include <mach/vm_map.h> +#endif + +#include "jemalloc/internal/jemalloc_internal_macros.h" + +/* + * Note that the ordering matters here; the hook itself is name-mangled. We + * want the inclusion of hooks to happen early, so that we hook as much as + * possible. + */ +#ifndef JEMALLOC_NO_PRIVATE_NAMESPACE +# ifndef JEMALLOC_JET +# include "jemalloc/internal/private_namespace.h" +# else +# include "jemalloc/internal/private_namespace_jet.h" +# endif +#endif +#include "jemalloc/internal/test_hooks.h" + +#ifdef JEMALLOC_DEFINE_MADVISE_FREE +# define JEMALLOC_MADV_FREE 8 +#endif + +static const bool config_debug = +#ifdef JEMALLOC_DEBUG + true +#else + false +#endif + ; +static const bool have_dss = +#ifdef JEMALLOC_DSS + true +#else + false +#endif + ; +static const bool have_madvise_huge = +#ifdef JEMALLOC_HAVE_MADVISE_HUGE + true +#else + false +#endif + ; +static const bool config_fill = +#ifdef JEMALLOC_FILL + true +#else + false +#endif + ; +static const bool config_lazy_lock = true; +static const char * const config_malloc_conf = JEMALLOC_CONFIG_MALLOC_CONF; +static const bool config_prof = +#ifdef JEMALLOC_PROF + true +#else + false +#endif + ; +static const bool config_prof_libgcc = +#ifdef JEMALLOC_PROF_LIBGCC + true +#else + false +#endif + ; +static const bool config_prof_libunwind = +#ifdef JEMALLOC_PROF_LIBUNWIND + true +#else + false +#endif + ; +static const bool maps_coalesce = +#ifdef JEMALLOC_MAPS_COALESCE + true +#else + false +#endif + ; +static const bool config_stats = +#ifdef JEMALLOC_STATS + true +#else + false +#endif + ; +static const bool config_tls = +#ifdef JEMALLOC_TLS + true +#else + false +#endif + ; +static const bool config_utrace = +#ifdef JEMALLOC_UTRACE + true +#else + false +#endif + ; +static const bool config_xmalloc = +#ifdef JEMALLOC_XMALLOC + true +#else + false +#endif + ; +static const bool config_cache_oblivious = +#ifdef JEMALLOC_CACHE_OBLIVIOUS + true +#else + false +#endif + ; +/* + * Undocumented, for jemalloc development use only at the moment. See the note + * in jemalloc/internal/log.h. + */ +static const bool config_log = +#ifdef JEMALLOC_LOG + true +#else + false +#endif + ; +/* + * Are extra safety checks enabled; things like checking the size of sized + * deallocations, double-frees, etc. + */ +static const bool config_opt_safety_checks = +#ifdef JEMALLOC_OPT_SAFETY_CHECKS + true +#elif defined(JEMALLOC_DEBUG) + /* + * This lets us only guard safety checks by one flag instead of two; fast + * checks can guard solely by config_opt_safety_checks and run in debug mode + * too. + */ + true +#else + false +#endif + ; + +/* + * Extra debugging of sized deallocations too onerous to be included in the + * general safety checks. + */ +static const bool config_opt_size_checks = +#if defined(JEMALLOC_OPT_SIZE_CHECKS) || defined(JEMALLOC_DEBUG) + true +#else + false +#endif + ; + +static const bool config_uaf_detection = +#if defined(JEMALLOC_UAF_DETECTION) || defined(JEMALLOC_DEBUG) + true +#else + false +#endif + ; + +/* Whether or not the C++ extensions are enabled. */ +static const bool config_enable_cxx = +#ifdef JEMALLOC_ENABLE_CXX + true +#else + false +#endif +; + +#if defined(_WIN32) || defined(JEMALLOC_HAVE_SCHED_GETCPU) +/* Currently percpu_arena depends on sched_getcpu. */ +#define JEMALLOC_PERCPU_ARENA +#endif +static const bool have_percpu_arena = +#ifdef JEMALLOC_PERCPU_ARENA + true +#else + false +#endif + ; +/* + * Undocumented, and not recommended; the application should take full + * responsibility for tracking provenance. + */ +static const bool force_ivsalloc = +#ifdef JEMALLOC_FORCE_IVSALLOC + true +#else + false +#endif + ; +static const bool have_background_thread = +#ifdef JEMALLOC_BACKGROUND_THREAD + true +#else + false +#endif + ; +static const bool config_high_res_timer = +#ifdef JEMALLOC_HAVE_CLOCK_REALTIME + true +#else + false +#endif + ; + +static const bool have_memcntl = +#ifdef JEMALLOC_HAVE_MEMCNTL + true +#else + false +#endif + ; + +#endif /* JEMALLOC_PREAMBLE_H */ diff --git a/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/private_namespace.h b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/private_namespace.h new file mode 100644 index 000000000000..08ce9219cbf8 --- /dev/null +++ b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/private_namespace.h @@ -0,0 +1,723 @@ +#define a0dalloc JEMALLOC_N(a0dalloc) +#define a0malloc JEMALLOC_N(a0malloc) +#define arena_choose_hard JEMALLOC_N(arena_choose_hard) +#define arena_cleanup JEMALLOC_N(arena_cleanup) +#define arena_init JEMALLOC_N(arena_init) +#define arena_migrate JEMALLOC_N(arena_migrate) +#define arena_set JEMALLOC_N(arena_set) +#define arenas JEMALLOC_N(arenas) +#define arenas_lock JEMALLOC_N(arenas_lock) +#define batch_alloc JEMALLOC_N(batch_alloc) +#define bootstrap_calloc JEMALLOC_N(bootstrap_calloc) +#define bootstrap_free JEMALLOC_N(bootstrap_free) +#define bootstrap_malloc JEMALLOC_N(bootstrap_malloc) +#define free_default JEMALLOC_N(free_default) +#define iarena_cleanup JEMALLOC_N(iarena_cleanup) +#define je_sdallocx_noflags JEMALLOC_N(je_sdallocx_noflags) +#define jemalloc_postfork_child JEMALLOC_N(jemalloc_postfork_child) +#define junk_alloc_callback JEMALLOC_N(junk_alloc_callback) +#define junk_free_callback JEMALLOC_N(junk_free_callback) +#define malloc_default JEMALLOC_N(malloc_default) +#define malloc_init_state JEMALLOC_N(malloc_init_state) +#define malloc_slow JEMALLOC_N(malloc_slow) +#define manual_arena_base JEMALLOC_N(manual_arena_base) +#define narenas_auto JEMALLOC_N(narenas_auto) +#define narenas_total_get JEMALLOC_N(narenas_total_get) +#define ncpus JEMALLOC_N(ncpus) +#define opt_abort JEMALLOC_N(opt_abort) +#define opt_abort_conf JEMALLOC_N(opt_abort_conf) +#define opt_cache_oblivious JEMALLOC_N(opt_cache_oblivious) +#define opt_confirm_conf JEMALLOC_N(opt_confirm_conf) +#define opt_experimental_infallible_new JEMALLOC_N(opt_experimental_infallible_new) +#define opt_hpa JEMALLOC_N(opt_hpa) +#define opt_hpa_opts JEMALLOC_N(opt_hpa_opts) +#define opt_hpa_sec_opts JEMALLOC_N(opt_hpa_sec_opts) +#define opt_junk JEMALLOC_N(opt_junk) +#define opt_junk_alloc JEMALLOC_N(opt_junk_alloc) +#define opt_junk_free JEMALLOC_N(opt_junk_free) +#define opt_narenas JEMALLOC_N(opt_narenas) +#define opt_narenas_ratio JEMALLOC_N(opt_narenas_ratio) +#define opt_trust_madvise JEMALLOC_N(opt_trust_madvise) +#define opt_utrace JEMALLOC_N(opt_utrace) +#define opt_xmalloc JEMALLOC_N(opt_xmalloc) +#define opt_zero JEMALLOC_N(opt_zero) +#define opt_zero_realloc_action JEMALLOC_N(opt_zero_realloc_action) +#define sdallocx_default JEMALLOC_N(sdallocx_default) +#define zero_realloc_count JEMALLOC_N(zero_realloc_count) +#define zero_realloc_mode_names JEMALLOC_N(zero_realloc_mode_names) +#define arena_basic_stats_merge JEMALLOC_N(arena_basic_stats_merge) +#define arena_bin_choose JEMALLOC_N(arena_bin_choose) +#define arena_bin_offsets JEMALLOC_N(arena_bin_offsets) +#define arena_binind_div_info JEMALLOC_N(arena_binind_div_info) +#define arena_boot JEMALLOC_N(arena_boot) +#define arena_cache_bin_fill_small JEMALLOC_N(arena_cache_bin_fill_small) +#define arena_choose_huge JEMALLOC_N(arena_choose_huge) +#define arena_config_default JEMALLOC_N(arena_config_default) +#define arena_dalloc_bin_locked_handle_newly_empty JEMALLOC_N(arena_dalloc_bin_locked_handle_newly_empty) +#define arena_dalloc_bin_locked_handle_newly_nonempty JEMALLOC_N(arena_dalloc_bin_locked_handle_newly_nonempty) +#define arena_dalloc_promoted JEMALLOC_N(arena_dalloc_promoted) +#define arena_dalloc_small JEMALLOC_N(arena_dalloc_small) +#define arena_decay JEMALLOC_N(arena_decay) +#define arena_decay_ms_get JEMALLOC_N(arena_decay_ms_get) +#define arena_decay_ms_set JEMALLOC_N(arena_decay_ms_set) +#define arena_destroy JEMALLOC_N(arena_destroy) +#define arena_dirty_decay_ms_default_get JEMALLOC_N(arena_dirty_decay_ms_default_get) +#define arena_dirty_decay_ms_default_set JEMALLOC_N(arena_dirty_decay_ms_default_set) +#define arena_do_deferred_work JEMALLOC_N(arena_do_deferred_work) +#define arena_dss_prec_get JEMALLOC_N(arena_dss_prec_get) +#define arena_dss_prec_set JEMALLOC_N(arena_dss_prec_set) +#define arena_emap_global JEMALLOC_N(arena_emap_global) +#define arena_extent_alloc_large JEMALLOC_N(arena_extent_alloc_large) +#define arena_extent_dalloc_large_prep JEMALLOC_N(arena_extent_dalloc_large_prep) +#define arena_extent_ralloc_large_expand JEMALLOC_N(arena_extent_ralloc_large_expand) +#define arena_extent_ralloc_large_shrink JEMALLOC_N(arena_extent_ralloc_large_shrink) +#define arena_fill_small_fresh JEMALLOC_N(arena_fill_small_fresh) +#define arena_get_ehooks JEMALLOC_N(arena_get_ehooks) +#define arena_handle_deferred_work JEMALLOC_N(arena_handle_deferred_work) +#define arena_init_huge JEMALLOC_N(arena_init_huge) +#define arena_is_huge JEMALLOC_N(arena_is_huge) +#define arena_malloc_hard JEMALLOC_N(arena_malloc_hard) +#define arena_muzzy_decay_ms_default_get JEMALLOC_N(arena_muzzy_decay_ms_default_get) +#define arena_muzzy_decay_ms_default_set JEMALLOC_N(arena_muzzy_decay_ms_default_set) +#define arena_new JEMALLOC_N(arena_new) +#define arena_nthreads_dec JEMALLOC_N(arena_nthreads_dec) +#define arena_nthreads_get JEMALLOC_N(arena_nthreads_get) +#define arena_nthreads_inc JEMALLOC_N(arena_nthreads_inc) +#define arena_pa_central_global JEMALLOC_N(arena_pa_central_global) +#define arena_palloc JEMALLOC_N(arena_palloc) +#define arena_postfork_child JEMALLOC_N(arena_postfork_child) +#define arena_postfork_parent JEMALLOC_N(arena_postfork_parent) +#define arena_prefork0 JEMALLOC_N(arena_prefork0) +#define arena_prefork1 JEMALLOC_N(arena_prefork1) +#define arena_prefork2 JEMALLOC_N(arena_prefork2) +#define arena_prefork3 JEMALLOC_N(arena_prefork3) +#define arena_prefork4 JEMALLOC_N(arena_prefork4) +#define arena_prefork5 JEMALLOC_N(arena_prefork5) +#define arena_prefork6 JEMALLOC_N(arena_prefork6) +#define arena_prefork7 JEMALLOC_N(arena_prefork7) +#define arena_prefork8 JEMALLOC_N(arena_prefork8) +#define arena_prof_promote JEMALLOC_N(arena_prof_promote) +#define arena_ralloc JEMALLOC_N(arena_ralloc) +#define arena_ralloc_no_move JEMALLOC_N(arena_ralloc_no_move) +#define arena_reset JEMALLOC_N(arena_reset) +#define arena_retain_grow_limit_get_set JEMALLOC_N(arena_retain_grow_limit_get_set) +#define arena_set_extent_hooks JEMALLOC_N(arena_set_extent_hooks) +#define arena_slab_dalloc JEMALLOC_N(arena_slab_dalloc) +#define arena_stats_merge JEMALLOC_N(arena_stats_merge) +#define opt_dirty_decay_ms JEMALLOC_N(opt_dirty_decay_ms) +#define opt_muzzy_decay_ms JEMALLOC_N(opt_muzzy_decay_ms) +#define opt_oversize_threshold JEMALLOC_N(opt_oversize_threshold) +#define opt_percpu_arena JEMALLOC_N(opt_percpu_arena) +#define oversize_threshold JEMALLOC_N(oversize_threshold) +#define percpu_arena_mode_names JEMALLOC_N(percpu_arena_mode_names) +#define background_thread_boot0 JEMALLOC_N(background_thread_boot0) +#define background_thread_boot1 JEMALLOC_N(background_thread_boot1) +#define background_thread_create JEMALLOC_N(background_thread_create) +#define background_thread_ctl_init JEMALLOC_N(background_thread_ctl_init) +#define background_thread_enabled_state JEMALLOC_N(background_thread_enabled_state) +#define background_thread_info JEMALLOC_N(background_thread_info) +#define background_thread_is_started JEMALLOC_N(background_thread_is_started) +#define background_thread_lock JEMALLOC_N(background_thread_lock) +#define background_thread_postfork_child JEMALLOC_N(background_thread_postfork_child) +#define background_thread_postfork_parent JEMALLOC_N(background_thread_postfork_parent) +#define background_thread_prefork0 JEMALLOC_N(background_thread_prefork0) +#define background_thread_prefork1 JEMALLOC_N(background_thread_prefork1) +#define background_thread_stats_read JEMALLOC_N(background_thread_stats_read) +#define background_thread_wakeup_early JEMALLOC_N(background_thread_wakeup_early) +#define background_threads_disable JEMALLOC_N(background_threads_disable) +#define background_threads_enable JEMALLOC_N(background_threads_enable) +#define max_background_threads JEMALLOC_N(max_background_threads) +#define n_background_threads JEMALLOC_N(n_background_threads) +#define opt_background_thread JEMALLOC_N(opt_background_thread) +#define opt_max_background_threads JEMALLOC_N(opt_max_background_threads) +#define pthread_create_wrapper JEMALLOC_N(pthread_create_wrapper) +#define b0get JEMALLOC_N(b0get) +#define base_alloc JEMALLOC_N(base_alloc) +#define base_alloc_edata JEMALLOC_N(base_alloc_edata) +#define base_boot JEMALLOC_N(base_boot) +#define base_delete JEMALLOC_N(base_delete) +#define base_ehooks_get JEMALLOC_N(base_ehooks_get) +#define base_ehooks_get_for_metadata JEMALLOC_N(base_ehooks_get_for_metadata) +#define base_extent_hooks_set JEMALLOC_N(base_extent_hooks_set) +#define base_new JEMALLOC_N(base_new) +#define base_postfork_child JEMALLOC_N(base_postfork_child) +#define base_postfork_parent JEMALLOC_N(base_postfork_parent) +#define base_prefork JEMALLOC_N(base_prefork) +#define base_stats_get JEMALLOC_N(base_stats_get) +#define metadata_thp_mode_names JEMALLOC_N(metadata_thp_mode_names) +#define opt_metadata_thp JEMALLOC_N(opt_metadata_thp) +#define bin_init JEMALLOC_N(bin_init) +#define bin_postfork_child JEMALLOC_N(bin_postfork_child) +#define bin_postfork_parent JEMALLOC_N(bin_postfork_parent) +#define bin_prefork JEMALLOC_N(bin_prefork) +#define bin_shard_sizes_boot JEMALLOC_N(bin_shard_sizes_boot) +#define bin_update_shard_size JEMALLOC_N(bin_update_shard_size) +#define bin_info_boot JEMALLOC_N(bin_info_boot) +#define bin_infos JEMALLOC_N(bin_infos) +#define bitmap_info_init JEMALLOC_N(bitmap_info_init) +#define bitmap_init JEMALLOC_N(bitmap_init) +#define bitmap_size JEMALLOC_N(bitmap_size) +#define buf_writer_cb JEMALLOC_N(buf_writer_cb) +#define buf_writer_flush JEMALLOC_N(buf_writer_flush) +#define buf_writer_init JEMALLOC_N(buf_writer_init) +#define buf_writer_pipe JEMALLOC_N(buf_writer_pipe) +#define buf_writer_terminate JEMALLOC_N(buf_writer_terminate) +#define cache_bin_info_compute_alloc JEMALLOC_N(cache_bin_info_compute_alloc) +#define cache_bin_info_init JEMALLOC_N(cache_bin_info_init) +#define cache_bin_init JEMALLOC_N(cache_bin_init) +#define cache_bin_postincrement JEMALLOC_N(cache_bin_postincrement) +#define cache_bin_preincrement JEMALLOC_N(cache_bin_preincrement) +#define cache_bin_still_zero_initialized JEMALLOC_N(cache_bin_still_zero_initialized) +#define ckh_count JEMALLOC_N(ckh_count) +#define ckh_delete JEMALLOC_N(ckh_delete) +#define ckh_insert JEMALLOC_N(ckh_insert) +#define ckh_iter JEMALLOC_N(ckh_iter) +#define ckh_new JEMALLOC_N(ckh_new) +#define ckh_pointer_hash JEMALLOC_N(ckh_pointer_hash) +#define ckh_pointer_keycomp JEMALLOC_N(ckh_pointer_keycomp) +#define ckh_remove JEMALLOC_N(ckh_remove) +#define ckh_search JEMALLOC_N(ckh_search) +#define ckh_string_hash JEMALLOC_N(ckh_string_hash) +#define ckh_string_keycomp JEMALLOC_N(ckh_string_keycomp) +#define counter_accum_init JEMALLOC_N(counter_accum_init) +#define counter_postfork_child JEMALLOC_N(counter_postfork_child) +#define counter_postfork_parent JEMALLOC_N(counter_postfork_parent) +#define counter_prefork JEMALLOC_N(counter_prefork) +#define ctl_boot JEMALLOC_N(ctl_boot) +#define ctl_bymib JEMALLOC_N(ctl_bymib) +#define ctl_bymibname JEMALLOC_N(ctl_bymibname) +#define ctl_byname JEMALLOC_N(ctl_byname) +#define ctl_mibnametomib JEMALLOC_N(ctl_mibnametomib) +#define ctl_mtx_assert_held JEMALLOC_N(ctl_mtx_assert_held) +#define ctl_nametomib JEMALLOC_N(ctl_nametomib) +#define ctl_postfork_child JEMALLOC_N(ctl_postfork_child) +#define ctl_postfork_parent JEMALLOC_N(ctl_postfork_parent) +#define ctl_prefork JEMALLOC_N(ctl_prefork) +#define decay_deadline_init JEMALLOC_N(decay_deadline_init) +#define decay_init JEMALLOC_N(decay_init) +#define decay_maybe_advance_epoch JEMALLOC_N(decay_maybe_advance_epoch) +#define decay_ms_valid JEMALLOC_N(decay_ms_valid) +#define decay_npages_purge_in JEMALLOC_N(decay_npages_purge_in) +#define decay_ns_until_purge JEMALLOC_N(decay_ns_until_purge) +#define decay_reinit JEMALLOC_N(decay_reinit) +#define div_init JEMALLOC_N(div_init) +#define ecache_init JEMALLOC_N(ecache_init) +#define ecache_postfork_child JEMALLOC_N(ecache_postfork_child) +#define ecache_postfork_parent JEMALLOC_N(ecache_postfork_parent) +#define ecache_prefork JEMALLOC_N(ecache_prefork) +#define edata_avail_any JEMALLOC_N(edata_avail_any) +#define edata_avail_empty JEMALLOC_N(edata_avail_empty) +#define edata_avail_first JEMALLOC_N(edata_avail_first) +#define edata_avail_insert JEMALLOC_N(edata_avail_insert) +#define edata_avail_new JEMALLOC_N(edata_avail_new) +#define edata_avail_remove JEMALLOC_N(edata_avail_remove) +#define edata_avail_remove_any JEMALLOC_N(edata_avail_remove_any) +#define edata_avail_remove_first JEMALLOC_N(edata_avail_remove_first) +#define edata_heap_any JEMALLOC_N(edata_heap_any) +#define edata_heap_empty JEMALLOC_N(edata_heap_empty) +#define edata_heap_first JEMALLOC_N(edata_heap_first) +#define edata_heap_insert JEMALLOC_N(edata_heap_insert) +#define edata_heap_new JEMALLOC_N(edata_heap_new) +#define edata_heap_remove JEMALLOC_N(edata_heap_remove) +#define edata_heap_remove_any JEMALLOC_N(edata_heap_remove_any) +#define edata_heap_remove_first JEMALLOC_N(edata_heap_remove_first) +#define edata_cache_fast_disable JEMALLOC_N(edata_cache_fast_disable) +#define edata_cache_fast_get JEMALLOC_N(edata_cache_fast_get) +#define edata_cache_fast_init JEMALLOC_N(edata_cache_fast_init) +#define edata_cache_fast_put JEMALLOC_N(edata_cache_fast_put) +#define edata_cache_get JEMALLOC_N(edata_cache_get) +#define edata_cache_init JEMALLOC_N(edata_cache_init) +#define edata_cache_postfork_child JEMALLOC_N(edata_cache_postfork_child) +#define edata_cache_postfork_parent JEMALLOC_N(edata_cache_postfork_parent) +#define edata_cache_prefork JEMALLOC_N(edata_cache_prefork) +#define edata_cache_put JEMALLOC_N(edata_cache_put) +#define ehooks_default_alloc_impl JEMALLOC_N(ehooks_default_alloc_impl) +#define ehooks_default_commit_impl JEMALLOC_N(ehooks_default_commit_impl) +#define ehooks_default_dalloc_impl JEMALLOC_N(ehooks_default_dalloc_impl) +#define ehooks_default_decommit_impl JEMALLOC_N(ehooks_default_decommit_impl) +#define ehooks_default_destroy_impl JEMALLOC_N(ehooks_default_destroy_impl) +#define ehooks_default_extent_hooks JEMALLOC_N(ehooks_default_extent_hooks) +#define ehooks_default_guard_impl JEMALLOC_N(ehooks_default_guard_impl) +#define ehooks_default_merge JEMALLOC_N(ehooks_default_merge) +#define ehooks_default_merge_impl JEMALLOC_N(ehooks_default_merge_impl) +#define ehooks_default_purge_forced_impl JEMALLOC_N(ehooks_default_purge_forced_impl) +#define ehooks_default_purge_lazy_impl JEMALLOC_N(ehooks_default_purge_lazy_impl) +#define ehooks_default_split_impl JEMALLOC_N(ehooks_default_split_impl) +#define ehooks_default_unguard_impl JEMALLOC_N(ehooks_default_unguard_impl) +#define ehooks_default_zero_impl JEMALLOC_N(ehooks_default_zero_impl) +#define ehooks_init JEMALLOC_N(ehooks_init) +#define emap_deregister_boundary JEMALLOC_N(emap_deregister_boundary) +#define emap_deregister_interior JEMALLOC_N(emap_deregister_interior) +#define emap_do_assert_mapped JEMALLOC_N(emap_do_assert_mapped) +#define emap_do_assert_not_mapped JEMALLOC_N(emap_do_assert_not_mapped) +#define emap_init JEMALLOC_N(emap_init) +#define emap_merge_commit JEMALLOC_N(emap_merge_commit) +#define emap_merge_prepare JEMALLOC_N(emap_merge_prepare) +#define emap_register_boundary JEMALLOC_N(emap_register_boundary) +#define emap_register_interior JEMALLOC_N(emap_register_interior) +#define emap_release_edata JEMALLOC_N(emap_release_edata) +#define emap_remap JEMALLOC_N(emap_remap) +#define emap_split_commit JEMALLOC_N(emap_split_commit) +#define emap_split_prepare JEMALLOC_N(emap_split_prepare) +#define emap_try_acquire_edata_neighbor JEMALLOC_N(emap_try_acquire_edata_neighbor) +#define emap_try_acquire_edata_neighbor_expand JEMALLOC_N(emap_try_acquire_edata_neighbor_expand) +#define emap_update_edata_state JEMALLOC_N(emap_update_edata_state) +#define eset_fit JEMALLOC_N(eset_fit) +#define eset_init JEMALLOC_N(eset_init) +#define eset_insert JEMALLOC_N(eset_insert) +#define eset_nbytes_get JEMALLOC_N(eset_nbytes_get) +#define eset_nextents_get JEMALLOC_N(eset_nextents_get) +#define eset_npages_get JEMALLOC_N(eset_npages_get) +#define eset_remove JEMALLOC_N(eset_remove) +#define exp_grow_init JEMALLOC_N(exp_grow_init) +#define ecache_alloc JEMALLOC_N(ecache_alloc) +#define ecache_alloc_grow JEMALLOC_N(ecache_alloc_grow) +#define ecache_dalloc JEMALLOC_N(ecache_dalloc) +#define ecache_evict JEMALLOC_N(ecache_evict) +#define extent_alloc_wrapper JEMALLOC_N(extent_alloc_wrapper) +#define extent_boot JEMALLOC_N(extent_boot) +#define extent_commit_wrapper JEMALLOC_N(extent_commit_wrapper) +#define extent_commit_zero JEMALLOC_N(extent_commit_zero) +#define extent_dalloc_gap JEMALLOC_N(extent_dalloc_gap) +#define extent_dalloc_wrapper JEMALLOC_N(extent_dalloc_wrapper) +#define extent_decommit_wrapper JEMALLOC_N(extent_decommit_wrapper) +#define extent_destroy_wrapper JEMALLOC_N(extent_destroy_wrapper) +#define extent_gdump_add JEMALLOC_N(extent_gdump_add) +#define extent_merge_wrapper JEMALLOC_N(extent_merge_wrapper) +#define extent_purge_forced_wrapper JEMALLOC_N(extent_purge_forced_wrapper) +#define extent_purge_lazy_wrapper JEMALLOC_N(extent_purge_lazy_wrapper) +#define extent_record JEMALLOC_N(extent_record) +#define extent_sn_next JEMALLOC_N(extent_sn_next) +#define extent_split_wrapper JEMALLOC_N(extent_split_wrapper) +#define opt_lg_extent_max_active_fit JEMALLOC_N(opt_lg_extent_max_active_fit) +#define dss_prec_names JEMALLOC_N(dss_prec_names) +#define extent_alloc_dss JEMALLOC_N(extent_alloc_dss) +#define extent_dss_boot JEMALLOC_N(extent_dss_boot) +#define extent_dss_mergeable JEMALLOC_N(extent_dss_mergeable) +#define extent_dss_prec_get JEMALLOC_N(extent_dss_prec_get) +#define extent_dss_prec_set JEMALLOC_N(extent_dss_prec_set) +#define extent_in_dss JEMALLOC_N(extent_in_dss) +#define opt_dss JEMALLOC_N(opt_dss) +#define extent_alloc_mmap JEMALLOC_N(extent_alloc_mmap) +#define extent_dalloc_mmap JEMALLOC_N(extent_dalloc_mmap) +#define opt_retain JEMALLOC_N(opt_retain) +#define fxp_parse JEMALLOC_N(fxp_parse) +#define fxp_print JEMALLOC_N(fxp_print) +#define opt_lg_san_uaf_align JEMALLOC_N(opt_lg_san_uaf_align) +#define opt_san_guard_large JEMALLOC_N(opt_san_guard_large) +#define opt_san_guard_small JEMALLOC_N(opt_san_guard_small) +#define san_cache_bin_nonfast_mask JEMALLOC_N(san_cache_bin_nonfast_mask) +#define san_check_stashed_ptrs JEMALLOC_N(san_check_stashed_ptrs) +#define san_guard_pages JEMALLOC_N(san_guard_pages) +#define san_init JEMALLOC_N(san_init) +#define san_unguard_pages JEMALLOC_N(san_unguard_pages) +#define san_unguard_pages_pre_destroy JEMALLOC_N(san_unguard_pages_pre_destroy) +#define tsd_san_init JEMALLOC_N(tsd_san_init) +#define san_bump_alloc JEMALLOC_N(san_bump_alloc) +#define hook_boot JEMALLOC_N(hook_boot) +#define hook_install JEMALLOC_N(hook_install) +#define hook_invoke_alloc JEMALLOC_N(hook_invoke_alloc) +#define hook_invoke_dalloc JEMALLOC_N(hook_invoke_dalloc) +#define hook_invoke_expand JEMALLOC_N(hook_invoke_expand) +#define hook_remove JEMALLOC_N(hook_remove) +#define hpa_central_extract JEMALLOC_N(hpa_central_extract) +#define hpa_central_init JEMALLOC_N(hpa_central_init) +#define hpa_shard_destroy JEMALLOC_N(hpa_shard_destroy) +#define hpa_shard_disable JEMALLOC_N(hpa_shard_disable) +#define hpa_shard_do_deferred_work JEMALLOC_N(hpa_shard_do_deferred_work) +#define hpa_shard_init JEMALLOC_N(hpa_shard_init) +#define hpa_shard_postfork_child JEMALLOC_N(hpa_shard_postfork_child) +#define hpa_shard_postfork_parent JEMALLOC_N(hpa_shard_postfork_parent) +#define hpa_shard_prefork3 JEMALLOC_N(hpa_shard_prefork3) +#define hpa_shard_prefork4 JEMALLOC_N(hpa_shard_prefork4) +#define hpa_shard_set_deferral_allowed JEMALLOC_N(hpa_shard_set_deferral_allowed) +#define hpa_shard_stats_accum JEMALLOC_N(hpa_shard_stats_accum) +#define hpa_shard_stats_merge JEMALLOC_N(hpa_shard_stats_merge) +#define hpa_supported JEMALLOC_N(hpa_supported) +#define hpa_hooks_default JEMALLOC_N(hpa_hooks_default) +#define hpdata_age_heap_any JEMALLOC_N(hpdata_age_heap_any) +#define hpdata_age_heap_empty JEMALLOC_N(hpdata_age_heap_empty) +#define hpdata_age_heap_first JEMALLOC_N(hpdata_age_heap_first) +#define hpdata_age_heap_insert JEMALLOC_N(hpdata_age_heap_insert) +#define hpdata_age_heap_new JEMALLOC_N(hpdata_age_heap_new) +#define hpdata_age_heap_remove JEMALLOC_N(hpdata_age_heap_remove) +#define hpdata_age_heap_remove_any JEMALLOC_N(hpdata_age_heap_remove_any) +#define hpdata_age_heap_remove_first JEMALLOC_N(hpdata_age_heap_remove_first) +#define hpdata_dehugify JEMALLOC_N(hpdata_dehugify) +#define hpdata_hugify JEMALLOC_N(hpdata_hugify) +#define hpdata_init JEMALLOC_N(hpdata_init) +#define hpdata_purge_begin JEMALLOC_N(hpdata_purge_begin) +#define hpdata_purge_end JEMALLOC_N(hpdata_purge_end) +#define hpdata_purge_next JEMALLOC_N(hpdata_purge_next) +#define hpdata_reserve_alloc JEMALLOC_N(hpdata_reserve_alloc) +#define hpdata_unreserve JEMALLOC_N(hpdata_unreserve) +#define inspect_extent_util_stats_get JEMALLOC_N(inspect_extent_util_stats_get) +#define inspect_extent_util_stats_verbose_get JEMALLOC_N(inspect_extent_util_stats_verbose_get) +#define large_dalloc JEMALLOC_N(large_dalloc) +#define large_dalloc_finish JEMALLOC_N(large_dalloc_finish) +#define large_dalloc_prep_locked JEMALLOC_N(large_dalloc_prep_locked) +#define large_malloc JEMALLOC_N(large_malloc) +#define large_palloc JEMALLOC_N(large_palloc) +#define large_prof_info_get JEMALLOC_N(large_prof_info_get) +#define large_prof_info_set JEMALLOC_N(large_prof_info_set) +#define large_prof_tctx_reset JEMALLOC_N(large_prof_tctx_reset) +#define large_ralloc JEMALLOC_N(large_ralloc) +#define large_ralloc_no_move JEMALLOC_N(large_ralloc_no_move) +#define large_salloc JEMALLOC_N(large_salloc) +#define log_init_done JEMALLOC_N(log_init_done) +#define log_var_names JEMALLOC_N(log_var_names) +#define log_var_update_state JEMALLOC_N(log_var_update_state) +#define buferror JEMALLOC_N(buferror) +#define malloc_cprintf JEMALLOC_N(malloc_cprintf) +#define malloc_printf JEMALLOC_N(malloc_printf) +#define malloc_snprintf JEMALLOC_N(malloc_snprintf) +#define malloc_strtoumax JEMALLOC_N(malloc_strtoumax) +#define malloc_vcprintf JEMALLOC_N(malloc_vcprintf) +#define malloc_vsnprintf JEMALLOC_N(malloc_vsnprintf) +#define malloc_write JEMALLOC_N(malloc_write) +#define wrtmessage JEMALLOC_N(wrtmessage) +#define wrtmessage_1_0 JEMALLOC_N(wrtmessage_1_0) +#define malloc_mutex_boot JEMALLOC_N(malloc_mutex_boot) +#define malloc_mutex_first_thread JEMALLOC_N(malloc_mutex_first_thread) +#define malloc_mutex_init JEMALLOC_N(malloc_mutex_init) +#define malloc_mutex_lock_slow JEMALLOC_N(malloc_mutex_lock_slow) +#define malloc_mutex_postfork_child JEMALLOC_N(malloc_mutex_postfork_child) +#define malloc_mutex_postfork_parent JEMALLOC_N(malloc_mutex_postfork_parent) +#define malloc_mutex_prefork JEMALLOC_N(malloc_mutex_prefork) +#define malloc_mutex_prof_data_reset JEMALLOC_N(malloc_mutex_prof_data_reset) +#define opt_mutex_max_spin JEMALLOC_N(opt_mutex_max_spin) +#define nstime_add JEMALLOC_N(nstime_add) +#define nstime_compare JEMALLOC_N(nstime_compare) +#define nstime_copy JEMALLOC_N(nstime_copy) +#define nstime_divide JEMALLOC_N(nstime_divide) +#define nstime_iadd JEMALLOC_N(nstime_iadd) +#define nstime_idivide JEMALLOC_N(nstime_idivide) +#define nstime_imultiply JEMALLOC_N(nstime_imultiply) +#define nstime_init JEMALLOC_N(nstime_init) +#define nstime_init2 JEMALLOC_N(nstime_init2) +#define nstime_init_update JEMALLOC_N(nstime_init_update) +#define nstime_isubtract JEMALLOC_N(nstime_isubtract) +#define nstime_monotonic JEMALLOC_N(nstime_monotonic) +#define nstime_msec JEMALLOC_N(nstime_msec) +#define nstime_ns JEMALLOC_N(nstime_ns) +#define nstime_ns_since JEMALLOC_N(nstime_ns_since) +#define nstime_nsec JEMALLOC_N(nstime_nsec) +#define nstime_prof_init_update JEMALLOC_N(nstime_prof_init_update) +#define nstime_prof_update JEMALLOC_N(nstime_prof_update) +#define nstime_sec JEMALLOC_N(nstime_sec) +#define nstime_subtract JEMALLOC_N(nstime_subtract) +#define nstime_update JEMALLOC_N(nstime_update) +#define opt_prof_time_res JEMALLOC_N(opt_prof_time_res) +#define prof_time_res_mode_names JEMALLOC_N(prof_time_res_mode_names) +#define pa_alloc JEMALLOC_N(pa_alloc) +#define pa_central_init JEMALLOC_N(pa_central_init) +#define pa_dalloc JEMALLOC_N(pa_dalloc) +#define pa_decay_ms_get JEMALLOC_N(pa_decay_ms_get) +#define pa_decay_ms_set JEMALLOC_N(pa_decay_ms_set) +#define pa_expand JEMALLOC_N(pa_expand) +#define pa_shard_destroy JEMALLOC_N(pa_shard_destroy) +#define pa_shard_disable_hpa JEMALLOC_N(pa_shard_disable_hpa) +#define pa_shard_do_deferred_work JEMALLOC_N(pa_shard_do_deferred_work) +#define pa_shard_enable_hpa JEMALLOC_N(pa_shard_enable_hpa) +#define pa_shard_init JEMALLOC_N(pa_shard_init) +#define pa_shard_reset JEMALLOC_N(pa_shard_reset) +#define pa_shard_retain_grow_limit_get_set JEMALLOC_N(pa_shard_retain_grow_limit_get_set) +#define pa_shard_set_deferral_allowed JEMALLOC_N(pa_shard_set_deferral_allowed) +#define pa_shard_time_until_deferred_work JEMALLOC_N(pa_shard_time_until_deferred_work) +#define pa_shrink JEMALLOC_N(pa_shrink) +#define pa_shard_basic_stats_merge JEMALLOC_N(pa_shard_basic_stats_merge) +#define pa_shard_mtx_stats_read JEMALLOC_N(pa_shard_mtx_stats_read) +#define pa_shard_postfork_child JEMALLOC_N(pa_shard_postfork_child) +#define pa_shard_postfork_parent JEMALLOC_N(pa_shard_postfork_parent) +#define pa_shard_prefork0 JEMALLOC_N(pa_shard_prefork0) +#define pa_shard_prefork2 JEMALLOC_N(pa_shard_prefork2) +#define pa_shard_prefork3 JEMALLOC_N(pa_shard_prefork3) +#define pa_shard_prefork4 JEMALLOC_N(pa_shard_prefork4) +#define pa_shard_prefork5 JEMALLOC_N(pa_shard_prefork5) +#define pa_shard_stats_merge JEMALLOC_N(pa_shard_stats_merge) +#define pai_alloc_batch_default JEMALLOC_N(pai_alloc_batch_default) +#define pai_dalloc_batch_default JEMALLOC_N(pai_dalloc_batch_default) +#define pac_decay_all JEMALLOC_N(pac_decay_all) +#define pac_decay_ms_get JEMALLOC_N(pac_decay_ms_get) +#define pac_decay_ms_set JEMALLOC_N(pac_decay_ms_set) +#define pac_destroy JEMALLOC_N(pac_destroy) +#define pac_init JEMALLOC_N(pac_init) +#define pac_maybe_decay_purge JEMALLOC_N(pac_maybe_decay_purge) +#define pac_reset JEMALLOC_N(pac_reset) +#define pac_retain_grow_limit_get_set JEMALLOC_N(pac_retain_grow_limit_get_set) +#define init_system_thp_mode JEMALLOC_N(init_system_thp_mode) +#define opt_thp JEMALLOC_N(opt_thp) +#define pages_boot JEMALLOC_N(pages_boot) +#define pages_commit JEMALLOC_N(pages_commit) +#define pages_decommit JEMALLOC_N(pages_decommit) +#define pages_dodump JEMALLOC_N(pages_dodump) +#define pages_dontdump JEMALLOC_N(pages_dontdump) +#define pages_huge JEMALLOC_N(pages_huge) +#define pages_map JEMALLOC_N(pages_map) +#define pages_mark_guards JEMALLOC_N(pages_mark_guards) +#define pages_nohuge JEMALLOC_N(pages_nohuge) +#define pages_purge_forced JEMALLOC_N(pages_purge_forced) +#define pages_purge_lazy JEMALLOC_N(pages_purge_lazy) +#define pages_set_thp_state JEMALLOC_N(pages_set_thp_state) +#define pages_unmap JEMALLOC_N(pages_unmap) +#define pages_unmark_guards JEMALLOC_N(pages_unmark_guards) +#define thp_mode_names JEMALLOC_N(thp_mode_names) +#define peak_alloc_event_handler JEMALLOC_N(peak_alloc_event_handler) +#define peak_alloc_new_event_wait JEMALLOC_N(peak_alloc_new_event_wait) +#define peak_alloc_postponed_event_wait JEMALLOC_N(peak_alloc_postponed_event_wait) +#define peak_dalloc_event_handler JEMALLOC_N(peak_dalloc_event_handler) +#define peak_dalloc_new_event_wait JEMALLOC_N(peak_dalloc_new_event_wait) +#define peak_dalloc_postponed_event_wait JEMALLOC_N(peak_dalloc_postponed_event_wait) +#define peak_event_max JEMALLOC_N(peak_event_max) +#define peak_event_update JEMALLOC_N(peak_event_update) +#define peak_event_zero JEMALLOC_N(peak_event_zero) +#define lg_prof_sample JEMALLOC_N(lg_prof_sample) +#define opt_lg_prof_interval JEMALLOC_N(opt_lg_prof_interval) +#define opt_lg_prof_sample JEMALLOC_N(opt_lg_prof_sample) +#define opt_prof JEMALLOC_N(opt_prof) +#define opt_prof_accum JEMALLOC_N(opt_prof_accum) +#define opt_prof_active JEMALLOC_N(opt_prof_active) +#define opt_prof_final JEMALLOC_N(opt_prof_final) +#define opt_prof_gdump JEMALLOC_N(opt_prof_gdump) +#define opt_prof_leak JEMALLOC_N(opt_prof_leak) +#define opt_prof_leak_error JEMALLOC_N(opt_prof_leak_error) +#define opt_prof_prefix JEMALLOC_N(opt_prof_prefix) +#define opt_prof_sys_thread_name JEMALLOC_N(opt_prof_sys_thread_name) +#define opt_prof_thread_active_init JEMALLOC_N(opt_prof_thread_active_init) +#define opt_prof_unbias JEMALLOC_N(opt_prof_unbias) +#define prof_active_get JEMALLOC_N(prof_active_get) +#define prof_active_set JEMALLOC_N(prof_active_set) +#define prof_active_state JEMALLOC_N(prof_active_state) +#define prof_alloc_rollback JEMALLOC_N(prof_alloc_rollback) +#define prof_backtrace_hook JEMALLOC_N(prof_backtrace_hook) +#define prof_backtrace_hook_get JEMALLOC_N(prof_backtrace_hook_get) +#define prof_backtrace_hook_set JEMALLOC_N(prof_backtrace_hook_set) +#define prof_boot0 JEMALLOC_N(prof_boot0) +#define prof_boot1 JEMALLOC_N(prof_boot1) +#define prof_boot2 JEMALLOC_N(prof_boot2) +#define prof_booted JEMALLOC_N(prof_booted) +#define prof_dump_hook JEMALLOC_N(prof_dump_hook) +#define prof_dump_hook_get JEMALLOC_N(prof_dump_hook_get) +#define prof_dump_hook_set JEMALLOC_N(prof_dump_hook_set) +#define prof_free_sampled_object JEMALLOC_N(prof_free_sampled_object) +#define prof_gdump JEMALLOC_N(prof_gdump) +#define prof_gdump_get JEMALLOC_N(prof_gdump_get) +#define prof_gdump_set JEMALLOC_N(prof_gdump_set) +#define prof_gdump_val JEMALLOC_N(prof_gdump_val) +#define prof_idump JEMALLOC_N(prof_idump) +#define prof_interval JEMALLOC_N(prof_interval) +#define prof_malloc_sample_object JEMALLOC_N(prof_malloc_sample_object) +#define prof_mdump JEMALLOC_N(prof_mdump) +#define prof_postfork_child JEMALLOC_N(prof_postfork_child) +#define prof_postfork_parent JEMALLOC_N(prof_postfork_parent) +#define prof_prefork0 JEMALLOC_N(prof_prefork0) +#define prof_prefork1 JEMALLOC_N(prof_prefork1) +#define prof_sample_event_handler JEMALLOC_N(prof_sample_event_handler) +#define prof_sample_new_event_wait JEMALLOC_N(prof_sample_new_event_wait) +#define prof_sample_postponed_event_wait JEMALLOC_N(prof_sample_postponed_event_wait) +#define prof_tctx_create JEMALLOC_N(prof_tctx_create) +#define prof_tdata_cleanup JEMALLOC_N(prof_tdata_cleanup) +#define prof_tdata_init JEMALLOC_N(prof_tdata_init) +#define prof_tdata_reinit JEMALLOC_N(prof_tdata_reinit) +#define prof_thread_active_get JEMALLOC_N(prof_thread_active_get) +#define prof_thread_active_init_get JEMALLOC_N(prof_thread_active_init_get) +#define prof_thread_active_init_set JEMALLOC_N(prof_thread_active_init_set) +#define prof_thread_active_set JEMALLOC_N(prof_thread_active_set) +#define prof_thread_name_get JEMALLOC_N(prof_thread_name_get) +#define prof_thread_name_set JEMALLOC_N(prof_thread_name_set) +#define bt2gctx_mtx JEMALLOC_N(bt2gctx_mtx) +#define gctx_locks JEMALLOC_N(gctx_locks) +#define prof_bt_count JEMALLOC_N(prof_bt_count) +#define prof_bt_hash JEMALLOC_N(prof_bt_hash) +#define prof_bt_keycomp JEMALLOC_N(prof_bt_keycomp) +#define prof_cnt_all JEMALLOC_N(prof_cnt_all) +#define prof_data_init JEMALLOC_N(prof_data_init) +#define prof_dump_impl JEMALLOC_N(prof_dump_impl) +#define prof_dump_mtx JEMALLOC_N(prof_dump_mtx) +#define prof_lookup JEMALLOC_N(prof_lookup) +#define prof_reset JEMALLOC_N(prof_reset) +#define prof_shifted_unbiased_cnt JEMALLOC_N(prof_shifted_unbiased_cnt) +#define prof_tctx_try_destroy JEMALLOC_N(prof_tctx_try_destroy) +#define prof_tdata_count JEMALLOC_N(prof_tdata_count) +#define prof_tdata_detach JEMALLOC_N(prof_tdata_detach) +#define prof_tdata_init_impl JEMALLOC_N(prof_tdata_init_impl) +#define prof_thread_name_alloc JEMALLOC_N(prof_thread_name_alloc) +#define prof_thread_name_set_impl JEMALLOC_N(prof_thread_name_set_impl) +#define prof_unbias_map_init JEMALLOC_N(prof_unbias_map_init) +#define prof_unbiased_sz JEMALLOC_N(prof_unbiased_sz) +#define tdata_locks JEMALLOC_N(tdata_locks) +#define tdatas_mtx JEMALLOC_N(tdatas_mtx) +#define log_mtx JEMALLOC_N(log_mtx) +#define opt_prof_log JEMALLOC_N(opt_prof_log) +#define prof_log_alloc_count JEMALLOC_N(prof_log_alloc_count) +#define prof_log_bt_count JEMALLOC_N(prof_log_bt_count) +#define prof_log_dummy_set JEMALLOC_N(prof_log_dummy_set) +#define prof_log_init JEMALLOC_N(prof_log_init) +#define prof_log_is_logging JEMALLOC_N(prof_log_is_logging) +#define prof_log_rep_check JEMALLOC_N(prof_log_rep_check) +#define prof_log_start JEMALLOC_N(prof_log_start) +#define prof_log_stop JEMALLOC_N(prof_log_stop) +#define prof_log_thr_count JEMALLOC_N(prof_log_thr_count) +#define prof_logging_state JEMALLOC_N(prof_logging_state) +#define prof_try_log JEMALLOC_N(prof_try_log) +#define edata_prof_recent_alloc_get_no_lock_test JEMALLOC_N(edata_prof_recent_alloc_get_no_lock_test) +#define edata_prof_recent_alloc_init JEMALLOC_N(edata_prof_recent_alloc_init) +#define opt_prof_recent_alloc_max JEMALLOC_N(opt_prof_recent_alloc_max) +#define prof_recent_alloc JEMALLOC_N(prof_recent_alloc) +#define prof_recent_alloc_dump JEMALLOC_N(prof_recent_alloc_dump) +#define prof_recent_alloc_edata_get_no_lock_test JEMALLOC_N(prof_recent_alloc_edata_get_no_lock_test) +#define prof_recent_alloc_list JEMALLOC_N(prof_recent_alloc_list) +#define prof_recent_alloc_max_ctl_read JEMALLOC_N(prof_recent_alloc_max_ctl_read) +#define prof_recent_alloc_max_ctl_write JEMALLOC_N(prof_recent_alloc_max_ctl_write) +#define prof_recent_alloc_mtx JEMALLOC_N(prof_recent_alloc_mtx) +#define prof_recent_alloc_prepare JEMALLOC_N(prof_recent_alloc_prepare) +#define prof_recent_alloc_reset JEMALLOC_N(prof_recent_alloc_reset) +#define prof_recent_dump_mtx JEMALLOC_N(prof_recent_dump_mtx) +#define prof_recent_init JEMALLOC_N(prof_recent_init) +#define opt_prof_stats JEMALLOC_N(opt_prof_stats) +#define prof_stats_dec JEMALLOC_N(prof_stats_dec) +#define prof_stats_get_accum JEMALLOC_N(prof_stats_get_accum) +#define prof_stats_get_live JEMALLOC_N(prof_stats_get_live) +#define prof_stats_inc JEMALLOC_N(prof_stats_inc) +#define prof_stats_mtx JEMALLOC_N(prof_stats_mtx) +#define bt_init JEMALLOC_N(bt_init) +#define prof_backtrace JEMALLOC_N(prof_backtrace) +#define prof_base JEMALLOC_N(prof_base) +#define prof_do_mock JEMALLOC_N(prof_do_mock) +#define prof_dump_filename_mtx JEMALLOC_N(prof_dump_filename_mtx) +#define prof_dump_open_file JEMALLOC_N(prof_dump_open_file) +#define prof_dump_open_maps JEMALLOC_N(prof_dump_open_maps) +#define prof_dump_write_file JEMALLOC_N(prof_dump_write_file) +#define prof_fdump_impl JEMALLOC_N(prof_fdump_impl) +#define prof_gdump_impl JEMALLOC_N(prof_gdump_impl) +#define prof_get_default_filename JEMALLOC_N(prof_get_default_filename) +#define prof_getpid JEMALLOC_N(prof_getpid) +#define prof_hooks_init JEMALLOC_N(prof_hooks_init) +#define prof_idump_impl JEMALLOC_N(prof_idump_impl) +#define prof_mdump_impl JEMALLOC_N(prof_mdump_impl) +#define prof_prefix_set JEMALLOC_N(prof_prefix_set) +#define prof_sys_thread_name_fetch JEMALLOC_N(prof_sys_thread_name_fetch) +#define prof_sys_thread_name_read JEMALLOC_N(prof_sys_thread_name_read) +#define prof_unwind_init JEMALLOC_N(prof_unwind_init) +#define psset_init JEMALLOC_N(psset_init) +#define psset_insert JEMALLOC_N(psset_insert) +#define psset_pick_alloc JEMALLOC_N(psset_pick_alloc) +#define psset_pick_hugify JEMALLOC_N(psset_pick_hugify) +#define psset_pick_purge JEMALLOC_N(psset_pick_purge) +#define psset_remove JEMALLOC_N(psset_remove) +#define psset_stats_accum JEMALLOC_N(psset_stats_accum) +#define psset_update_begin JEMALLOC_N(psset_update_begin) +#define psset_update_end JEMALLOC_N(psset_update_end) +#define rtree_ctx_data_init JEMALLOC_N(rtree_ctx_data_init) +#define rtree_leaf_elm_lookup_hard JEMALLOC_N(rtree_leaf_elm_lookup_hard) +#define rtree_new JEMALLOC_N(rtree_new) +#define safety_check_fail JEMALLOC_N(safety_check_fail) +#define safety_check_fail_sized_dealloc JEMALLOC_N(safety_check_fail_sized_dealloc) +#define safety_check_set_abort JEMALLOC_N(safety_check_set_abort) +#define reg_size_compute JEMALLOC_N(reg_size_compute) +#define sc_boot JEMALLOC_N(sc_boot) +#define sc_data_init JEMALLOC_N(sc_data_init) +#define sc_data_update_slab_size JEMALLOC_N(sc_data_update_slab_size) +#define sec_disable JEMALLOC_N(sec_disable) +#define sec_flush JEMALLOC_N(sec_flush) +#define sec_init JEMALLOC_N(sec_init) +#define sec_mutex_stats_read JEMALLOC_N(sec_mutex_stats_read) +#define sec_postfork_child JEMALLOC_N(sec_postfork_child) +#define sec_postfork_parent JEMALLOC_N(sec_postfork_parent) +#define sec_prefork2 JEMALLOC_N(sec_prefork2) +#define sec_stats_merge JEMALLOC_N(sec_stats_merge) +#define arena_mutex_names JEMALLOC_N(arena_mutex_names) +#define global_mutex_names JEMALLOC_N(global_mutex_names) +#define opt_stats_interval JEMALLOC_N(opt_stats_interval) +#define opt_stats_interval_opts JEMALLOC_N(opt_stats_interval_opts) +#define opt_stats_print JEMALLOC_N(opt_stats_print) +#define opt_stats_print_opts JEMALLOC_N(opt_stats_print_opts) +#define stats_boot JEMALLOC_N(stats_boot) +#define stats_interval_event_handler JEMALLOC_N(stats_interval_event_handler) +#define stats_interval_new_event_wait JEMALLOC_N(stats_interval_new_event_wait) +#define stats_interval_postponed_event_wait JEMALLOC_N(stats_interval_postponed_event_wait) +#define stats_postfork_child JEMALLOC_N(stats_postfork_child) +#define stats_postfork_parent JEMALLOC_N(stats_postfork_parent) +#define stats_prefork JEMALLOC_N(stats_prefork) +#define stats_print JEMALLOC_N(stats_print) +#define sz_boot JEMALLOC_N(sz_boot) +#define sz_index2size_tab JEMALLOC_N(sz_index2size_tab) +#define sz_large_pad JEMALLOC_N(sz_large_pad) +#define sz_pind2sz_tab JEMALLOC_N(sz_pind2sz_tab) +#define sz_psz_quantize_ceil JEMALLOC_N(sz_psz_quantize_ceil) +#define sz_psz_quantize_floor JEMALLOC_N(sz_psz_quantize_floor) +#define sz_size2index_tab JEMALLOC_N(sz_size2index_tab) +#define nhbins JEMALLOC_N(nhbins) +#define opt_lg_tcache_flush_large_div JEMALLOC_N(opt_lg_tcache_flush_large_div) +#define opt_lg_tcache_flush_small_div JEMALLOC_N(opt_lg_tcache_flush_small_div) +#define opt_lg_tcache_nslots_mul JEMALLOC_N(opt_lg_tcache_nslots_mul) +#define opt_tcache JEMALLOC_N(opt_tcache) +#define opt_tcache_gc_delay_bytes JEMALLOC_N(opt_tcache_gc_delay_bytes) +#define opt_tcache_gc_incr_bytes JEMALLOC_N(opt_tcache_gc_incr_bytes) +#define opt_tcache_max JEMALLOC_N(opt_tcache_max) +#define opt_tcache_nslots_large JEMALLOC_N(opt_tcache_nslots_large) +#define opt_tcache_nslots_small_max JEMALLOC_N(opt_tcache_nslots_small_max) +#define opt_tcache_nslots_small_min JEMALLOC_N(opt_tcache_nslots_small_min) +#define tcache_alloc_small_hard JEMALLOC_N(tcache_alloc_small_hard) +#define tcache_arena_associate JEMALLOC_N(tcache_arena_associate) +#define tcache_arena_reassociate JEMALLOC_N(tcache_arena_reassociate) +#define tcache_assert_initialized JEMALLOC_N(tcache_assert_initialized) +#define tcache_bin_flush_large JEMALLOC_N(tcache_bin_flush_large) +#define tcache_bin_flush_small JEMALLOC_N(tcache_bin_flush_small) +#define tcache_bin_flush_stashed JEMALLOC_N(tcache_bin_flush_stashed) +#define tcache_bin_info JEMALLOC_N(tcache_bin_info) +#define tcache_boot JEMALLOC_N(tcache_boot) +#define tcache_cleanup JEMALLOC_N(tcache_cleanup) +#define tcache_create_explicit JEMALLOC_N(tcache_create_explicit) +#define tcache_flush JEMALLOC_N(tcache_flush) +#define tcache_gc_dalloc_event_handler JEMALLOC_N(tcache_gc_dalloc_event_handler) +#define tcache_gc_dalloc_new_event_wait JEMALLOC_N(tcache_gc_dalloc_new_event_wait) +#define tcache_gc_dalloc_postponed_event_wait JEMALLOC_N(tcache_gc_dalloc_postponed_event_wait) +#define tcache_gc_event_handler JEMALLOC_N(tcache_gc_event_handler) +#define tcache_gc_new_event_wait JEMALLOC_N(tcache_gc_new_event_wait) +#define tcache_gc_postponed_event_wait JEMALLOC_N(tcache_gc_postponed_event_wait) +#define tcache_maxclass JEMALLOC_N(tcache_maxclass) +#define tcache_postfork_child JEMALLOC_N(tcache_postfork_child) +#define tcache_postfork_parent JEMALLOC_N(tcache_postfork_parent) +#define tcache_prefork JEMALLOC_N(tcache_prefork) +#define tcache_salloc JEMALLOC_N(tcache_salloc) +#define tcache_stats_merge JEMALLOC_N(tcache_stats_merge) +#define tcaches JEMALLOC_N(tcaches) +#define tcaches_create JEMALLOC_N(tcaches_create) +#define tcaches_destroy JEMALLOC_N(tcaches_destroy) +#define tcaches_flush JEMALLOC_N(tcaches_flush) +#define tsd_tcache_data_init JEMALLOC_N(tsd_tcache_data_init) +#define tsd_tcache_enabled_data_init JEMALLOC_N(tsd_tcache_enabled_data_init) +#define test_hooks_arena_new_hook JEMALLOC_N(test_hooks_arena_new_hook) +#define test_hooks_libc_hook JEMALLOC_N(test_hooks_libc_hook) +#define te_assert_invariants_debug JEMALLOC_N(te_assert_invariants_debug) +#define te_event_trigger JEMALLOC_N(te_event_trigger) +#define te_recompute_fast_threshold JEMALLOC_N(te_recompute_fast_threshold) +#define tsd_te_init JEMALLOC_N(tsd_te_init) +#define ticker_geom_table JEMALLOC_N(ticker_geom_table) +#define malloc_tsd_boot0 JEMALLOC_N(malloc_tsd_boot0) +#define malloc_tsd_boot1 JEMALLOC_N(malloc_tsd_boot1) +#define malloc_tsd_dalloc JEMALLOC_N(malloc_tsd_dalloc) +#define malloc_tsd_malloc JEMALLOC_N(malloc_tsd_malloc) +#define tsd_booted JEMALLOC_N(tsd_booted) +#define tsd_cleanup JEMALLOC_N(tsd_cleanup) +#define tsd_fetch_slow JEMALLOC_N(tsd_fetch_slow) +#define tsd_global_slow JEMALLOC_N(tsd_global_slow) +#define tsd_global_slow_dec JEMALLOC_N(tsd_global_slow_dec) +#define tsd_global_slow_inc JEMALLOC_N(tsd_global_slow_inc) +#define tsd_initialized JEMALLOC_N(tsd_initialized) +#define tsd_postfork_child JEMALLOC_N(tsd_postfork_child) +#define tsd_postfork_parent JEMALLOC_N(tsd_postfork_parent) +#define tsd_prefork JEMALLOC_N(tsd_prefork) +#define tsd_slow_update JEMALLOC_N(tsd_slow_update) +#define tsd_state_set JEMALLOC_N(tsd_state_set) +#define tsd_tls JEMALLOC_N(tsd_tls) +#define witness_depth_error JEMALLOC_N(witness_depth_error) +#define witness_init JEMALLOC_N(witness_init) +#define witness_lock_error JEMALLOC_N(witness_lock_error) +#define witness_not_owner_error JEMALLOC_N(witness_not_owner_error) +#define witness_owner_error JEMALLOC_N(witness_owner_error) +#define witness_postfork_child JEMALLOC_N(witness_postfork_child) +#define witness_postfork_parent JEMALLOC_N(witness_postfork_parent) +#define witness_prefork JEMALLOC_N(witness_prefork) +#define witnesses_cleanup JEMALLOC_N(witnesses_cleanup) diff --git a/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/public_namespace.h b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/public_namespace.h new file mode 100644 index 000000000000..6363f085f34b --- /dev/null +++ b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/internal/public_namespace.h @@ -0,0 +1,24 @@ +#define je_aligned_alloc JEMALLOC_N(aligned_alloc) +#define je_calloc JEMALLOC_N(calloc) +#define je_dallocx JEMALLOC_N(dallocx) +#define je_free JEMALLOC_N(free) +#define je_mallctl JEMALLOC_N(mallctl) +#define je_mallctlbymib JEMALLOC_N(mallctlbymib) +#define je_mallctlnametomib JEMALLOC_N(mallctlnametomib) +#define je_malloc JEMALLOC_N(malloc) +#define je_malloc_conf JEMALLOC_N(malloc_conf) +#define je_malloc_conf_2_conf_harder JEMALLOC_N(malloc_conf_2_conf_harder) +#define je_malloc_message JEMALLOC_N(malloc_message) +#define je_malloc_stats_print JEMALLOC_N(malloc_stats_print) +#define je_malloc_usable_size JEMALLOC_N(malloc_usable_size) +#define je_mallocx JEMALLOC_N(mallocx) +#define je_smallocx_54eaed1d8b56b1aa528be3bdd1877e59c56fa90c JEMALLOC_N(smallocx_54eaed1d8b56b1aa528be3bdd1877e59c56fa90c) +#define je_nallocx JEMALLOC_N(nallocx) +#define je_posix_memalign JEMALLOC_N(posix_memalign) +#define je_rallocx JEMALLOC_N(rallocx) +#define je_realloc JEMALLOC_N(realloc) +#define je_sallocx JEMALLOC_N(sallocx) +#define je_sdallocx JEMALLOC_N(sdallocx) +#define je_xallocx JEMALLOC_N(xallocx) +#define je_memalign JEMALLOC_N(memalign) +#define je_valloc JEMALLOC_N(valloc) diff --git a/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/jemalloc.h b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/jemalloc.h new file mode 100644 index 000000000000..f9ed38656a87 --- /dev/null +++ b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/jemalloc.h @@ -0,0 +1,468 @@ +#ifndef JEMALLOC_H_ +#define JEMALLOC_H_ +#ifdef __cplusplus +extern "C" { +#endif + +/* Defined if __attribute__((...)) syntax is supported. */ +#define JEMALLOC_HAVE_ATTR + +/* Defined if alloc_size attribute is supported. */ +#define JEMALLOC_HAVE_ATTR_ALLOC_SIZE + +/* Defined if format_arg(...) attribute is supported. */ +#define JEMALLOC_HAVE_ATTR_FORMAT_ARG + +/* Defined if format(gnu_printf, ...) attribute is supported. */ +/* #undef JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF */ + +/* Defined if format(printf, ...) attribute is supported. */ +#define JEMALLOC_HAVE_ATTR_FORMAT_PRINTF + +/* Defined if fallthrough attribute is supported. */ +#define JEMALLOC_HAVE_ATTR_FALLTHROUGH + +/* Defined if cold attribute is supported. */ +#define JEMALLOC_HAVE_ATTR_COLD + +/* + * Define overrides for non-standard allocator-related functions if they are + * present on the system. + */ +/* #undef JEMALLOC_OVERRIDE_MEMALIGN */ +#define JEMALLOC_OVERRIDE_VALLOC + +/* + * At least Linux omits the "const" in: + * + * size_t malloc_usable_size(const void *ptr); + * + * Match the operating system's prototype. + */ +#define JEMALLOC_USABLE_SIZE_CONST const + +/* + * If defined, specify throw() for the public function prototypes when compiling + * with C++. The only justification for this is to match the prototypes that + * glibc defines. + */ +/* #undef JEMALLOC_USE_CXX_THROW */ + +#ifdef _MSC_VER +# ifdef _WIN64 +# define LG_SIZEOF_PTR_WIN 3 +# else +# define LG_SIZEOF_PTR_WIN 2 +# endif +#endif + +/* sizeof(void *) == 2^LG_SIZEOF_PTR. */ +#define LG_SIZEOF_PTR 3 + +/* + * Name mangling for public symbols is controlled by --with-mangling and + * --with-jemalloc-prefix. With default settings the je_ prefix is stripped by + * these macro definitions. + */ +#ifndef JEMALLOC_NO_RENAME +# define je_aligned_alloc aligned_alloc +# define je_calloc calloc +# define je_dallocx dallocx +# define je_free free +# define je_mallctl mallctl +# define je_mallctlbymib mallctlbymib +# define je_mallctlnametomib mallctlnametomib +# define je_malloc malloc +# define je_malloc_conf malloc_conf +# define je_malloc_conf_2_conf_harder malloc_conf_2_conf_harder +# define je_malloc_message malloc_message +# define je_malloc_stats_print malloc_stats_print +# define je_malloc_usable_size malloc_usable_size +# define je_mallocx mallocx +# define je_smallocx_54eaed1d8b56b1aa528be3bdd1877e59c56fa90c smallocx_54eaed1d8b56b1aa528be3bdd1877e59c56fa90c +# define je_nallocx nallocx +# define je_posix_memalign posix_memalign +# define je_rallocx rallocx +# define je_realloc realloc +# define je_sallocx sallocx +# define je_sdallocx sdallocx +# define je_xallocx xallocx +# define je_memalign memalign +# define je_valloc valloc +#endif + +#include "jemalloc_FreeBSD.h" + +#include <stdlib.h> +#include <stdbool.h> +#include <stdint.h> +#include <limits.h> +#include <strings.h> + +#define JEMALLOC_VERSION "5.3.0-0-g54eaed1d8b56b1aa528be3bdd1877e59c56fa90c" +#define JEMALLOC_VERSION_MAJOR 5 +#define JEMALLOC_VERSION_MINOR 3 +#define JEMALLOC_VERSION_BUGFIX 0 +#define JEMALLOC_VERSION_NREV 0 +#define JEMALLOC_VERSION_GID "54eaed1d8b56b1aa528be3bdd1877e59c56fa90c" +#define JEMALLOC_VERSION_GID_IDENT 54eaed1d8b56b1aa528be3bdd1877e59c56fa90c + +#define MALLOCX_LG_ALIGN(la) ((int)(la)) +#if LG_SIZEOF_PTR == 2 +# define MALLOCX_ALIGN(a) ((int)(ffs((int)(a))-1)) +#else +# define MALLOCX_ALIGN(a) \ + ((int)(((size_t)(a) < (size_t)INT_MAX) ? ffs((int)(a))-1 : \ + ffs((int)(((size_t)(a))>>32))+31)) +#endif +#define MALLOCX_ZERO ((int)0x40) +/* + * Bias tcache index bits so that 0 encodes "automatic tcache management", and 1 + * encodes MALLOCX_TCACHE_NONE. + */ +#define MALLOCX_TCACHE(tc) ((int)(((tc)+2) << 8)) +#define MALLOCX_TCACHE_NONE MALLOCX_TCACHE(-1) +/* + * Bias arena index bits so that 0 encodes "use an automatically chosen arena". + */ +#define MALLOCX_ARENA(a) ((((int)(a))+1) << 20) + +/* + * Use as arena index in "arena.<i>.{purge,decay,dss}" and + * "stats.arenas.<i>.*" mallctl interfaces to select all arenas. This + * definition is intentionally specified in raw decimal format to support + * cpp-based string concatenation, e.g. + * + * #define STRINGIFY_HELPER(x) #x + * #define STRINGIFY(x) STRINGIFY_HELPER(x) + * + * mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".purge", NULL, NULL, NULL, + * 0); + */ +#define MALLCTL_ARENAS_ALL 4096 +/* + * Use as arena index in "stats.arenas.<i>.*" mallctl interfaces to select + * destroyed arenas. + */ +#define MALLCTL_ARENAS_DESTROYED 4097 + +#if defined(__cplusplus) && defined(JEMALLOC_USE_CXX_THROW) +# define JEMALLOC_CXX_THROW throw() +#else +# define JEMALLOC_CXX_THROW +#endif + +#if defined(_MSC_VER) +# define JEMALLOC_ATTR(s) +# define JEMALLOC_ALIGNED(s) __declspec(align(s)) +# define JEMALLOC_ALLOC_SIZE(s) +# define JEMALLOC_ALLOC_SIZE2(s1, s2) +# ifndef JEMALLOC_EXPORT +# ifdef DLLEXPORT +# define JEMALLOC_EXPORT __declspec(dllexport) +# else +# define JEMALLOC_EXPORT __declspec(dllimport) +# endif +# endif +# define JEMALLOC_FORMAT_ARG(i) +# define JEMALLOC_FORMAT_PRINTF(s, i) +# define JEMALLOC_FALLTHROUGH +# define JEMALLOC_NOINLINE __declspec(noinline) +# ifdef __cplusplus +# define JEMALLOC_NOTHROW __declspec(nothrow) +# else +# define JEMALLOC_NOTHROW +# endif +# define JEMALLOC_SECTION(s) __declspec(allocate(s)) +# define JEMALLOC_RESTRICT_RETURN __declspec(restrict) +# if _MSC_VER >= 1900 && !defined(__EDG__) +# define JEMALLOC_ALLOCATOR __declspec(allocator) +# else +# define JEMALLOC_ALLOCATOR +# endif +# define JEMALLOC_COLD +#elif defined(JEMALLOC_HAVE_ATTR) +# define JEMALLOC_ATTR(s) __attribute__((s)) +# define JEMALLOC_ALIGNED(s) JEMALLOC_ATTR(aligned(s)) +# ifdef JEMALLOC_HAVE_ATTR_ALLOC_SIZE +# define JEMALLOC_ALLOC_SIZE(s) JEMALLOC_ATTR(alloc_size(s)) +# define JEMALLOC_ALLOC_SIZE2(s1, s2) JEMALLOC_ATTR(alloc_size(s1, s2)) +# else +# define JEMALLOC_ALLOC_SIZE(s) +# define JEMALLOC_ALLOC_SIZE2(s1, s2) +# endif +# ifndef JEMALLOC_EXPORT +# define JEMALLOC_EXPORT JEMALLOC_ATTR(visibility("default")) +# endif +# ifdef JEMALLOC_HAVE_ATTR_FORMAT_ARG +# define JEMALLOC_FORMAT_ARG(i) JEMALLOC_ATTR(__format_arg__(3)) +# else +# define JEMALLOC_FORMAT_ARG(i) +# endif +# ifdef JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF +# define JEMALLOC_FORMAT_PRINTF(s, i) JEMALLOC_ATTR(format(gnu_printf, s, i)) +# elif defined(JEMALLOC_HAVE_ATTR_FORMAT_PRINTF) +# define JEMALLOC_FORMAT_PRINTF(s, i) JEMALLOC_ATTR(format(printf, s, i)) +# else +# define JEMALLOC_FORMAT_PRINTF(s, i) +# endif +# ifdef JEMALLOC_HAVE_ATTR_FALLTHROUGH +# define JEMALLOC_FALLTHROUGH JEMALLOC_ATTR(fallthrough) +# else +# define JEMALLOC_FALLTHROUGH +# endif +# define JEMALLOC_NOINLINE JEMALLOC_ATTR(noinline) +# define JEMALLOC_NOTHROW JEMALLOC_ATTR(nothrow) +# define JEMALLOC_SECTION(s) JEMALLOC_ATTR(section(s)) +# define JEMALLOC_RESTRICT_RETURN +# define JEMALLOC_ALLOCATOR +# ifdef JEMALLOC_HAVE_ATTR_COLD +# define JEMALLOC_COLD JEMALLOC_ATTR(__cold__) +# else +# define JEMALLOC_COLD +# endif +#else +# define JEMALLOC_ATTR(s) +# define JEMALLOC_ALIGNED(s) +# define JEMALLOC_ALLOC_SIZE(s) +# define JEMALLOC_ALLOC_SIZE2(s1, s2) +# define JEMALLOC_EXPORT +# define JEMALLOC_FORMAT_PRINTF(s, i) +# define JEMALLOC_FALLTHROUGH +# define JEMALLOC_NOINLINE +# define JEMALLOC_NOTHROW +# define JEMALLOC_SECTION(s) +# define JEMALLOC_RESTRICT_RETURN +# define JEMALLOC_ALLOCATOR +# define JEMALLOC_COLD +#endif + +#if (defined(__APPLE__) || defined(__FreeBSD__)) && !defined(JEMALLOC_NO_RENAME) +# define JEMALLOC_SYS_NOTHROW +#else +# define JEMALLOC_SYS_NOTHROW JEMALLOC_NOTHROW +#endif + +/* + * The je_ prefix on the following public symbol declarations is an artifact + * of namespace management, and should be omitted in application code unless + * JEMALLOC_NO_DEMANGLE is defined (see jemalloc_mangle.h). + */ +extern JEMALLOC_EXPORT const char *je_malloc_conf; +extern JEMALLOC_EXPORT void (*je_malloc_message)(void *cbopaque, + const char *s); + +JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN + void JEMALLOC_SYS_NOTHROW *je_malloc(size_t size) + JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1); +JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN + void JEMALLOC_SYS_NOTHROW *je_calloc(size_t num, size_t size) + JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE2(1, 2); +JEMALLOC_EXPORT int JEMALLOC_SYS_NOTHROW je_posix_memalign( + void **memptr, size_t alignment, size_t size) JEMALLOC_CXX_THROW + JEMALLOC_ATTR(nonnull(1)); +JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN + void JEMALLOC_SYS_NOTHROW *je_aligned_alloc(size_t alignment, + size_t size) JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc) + JEMALLOC_ALLOC_SIZE(2); +JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN + void JEMALLOC_SYS_NOTHROW *je_realloc(void *ptr, size_t size) + JEMALLOC_CXX_THROW JEMALLOC_ALLOC_SIZE(2); +JEMALLOC_EXPORT void JEMALLOC_SYS_NOTHROW je_free(void *ptr) + JEMALLOC_CXX_THROW; + +JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN + void JEMALLOC_NOTHROW *je_mallocx(size_t size, int flags) + JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1); +JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN + void JEMALLOC_NOTHROW *je_rallocx(void *ptr, size_t size, + int flags) JEMALLOC_ALLOC_SIZE(2); +JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW je_xallocx(void *ptr, size_t size, + size_t extra, int flags); +JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW je_sallocx(const void *ptr, + int flags) JEMALLOC_ATTR(pure); +JEMALLOC_EXPORT void JEMALLOC_NOTHROW je_dallocx(void *ptr, int flags); +JEMALLOC_EXPORT void JEMALLOC_NOTHROW je_sdallocx(void *ptr, size_t size, + int flags); +JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW je_nallocx(size_t size, int flags) + JEMALLOC_ATTR(pure); + +JEMALLOC_EXPORT int JEMALLOC_NOTHROW je_mallctl(const char *name, + void *oldp, size_t *oldlenp, void *newp, size_t newlen); +JEMALLOC_EXPORT int JEMALLOC_NOTHROW je_mallctlnametomib(const char *name, + size_t *mibp, size_t *miblenp); +JEMALLOC_EXPORT int JEMALLOC_NOTHROW je_mallctlbymib(const size_t *mib, + size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen); +JEMALLOC_EXPORT void JEMALLOC_NOTHROW je_malloc_stats_print( + void (*write_cb)(void *, const char *), void *je_cbopaque, + const char *opts); +JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW je_malloc_usable_size( + JEMALLOC_USABLE_SIZE_CONST void *ptr) JEMALLOC_CXX_THROW; +#ifdef JEMALLOC_HAVE_MALLOC_SIZE +JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW je_malloc_size( + const void *ptr); +#endif + +#ifdef JEMALLOC_OVERRIDE_MEMALIGN +JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN + void JEMALLOC_SYS_NOTHROW *je_memalign(size_t alignment, size_t size) + JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc); +#endif + +#ifdef JEMALLOC_OVERRIDE_VALLOC +JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN + void JEMALLOC_SYS_NOTHROW *je_valloc(size_t size) JEMALLOC_CXX_THROW + JEMALLOC_ATTR(malloc); +#endif + +typedef struct extent_hooks_s extent_hooks_t; + +/* + * void * + * extent_alloc(extent_hooks_t *extent_hooks, void *new_addr, size_t size, + * size_t alignment, bool *zero, bool *commit, unsigned arena_ind); + */ +typedef void *(extent_alloc_t)(extent_hooks_t *, void *, size_t, size_t, bool *, + bool *, unsigned); + +/* + * bool + * extent_dalloc(extent_hooks_t *extent_hooks, void *addr, size_t size, + * bool committed, unsigned arena_ind); + */ +typedef bool (extent_dalloc_t)(extent_hooks_t *, void *, size_t, bool, + unsigned); + +/* + * void + * extent_destroy(extent_hooks_t *extent_hooks, void *addr, size_t size, + * bool committed, unsigned arena_ind); + */ +typedef void (extent_destroy_t)(extent_hooks_t *, void *, size_t, bool, + unsigned); + +/* + * bool + * extent_commit(extent_hooks_t *extent_hooks, void *addr, size_t size, + * size_t offset, size_t length, unsigned arena_ind); + */ +typedef bool (extent_commit_t)(extent_hooks_t *, void *, size_t, size_t, size_t, + unsigned); + +/* + * bool + * extent_decommit(extent_hooks_t *extent_hooks, void *addr, size_t size, + * size_t offset, size_t length, unsigned arena_ind); + */ +typedef bool (extent_decommit_t)(extent_hooks_t *, void *, size_t, size_t, + size_t, unsigned); + +/* + * bool + * extent_purge(extent_hooks_t *extent_hooks, void *addr, size_t size, + * size_t offset, size_t length, unsigned arena_ind); + */ +typedef bool (extent_purge_t)(extent_hooks_t *, void *, size_t, size_t, size_t, + unsigned); + +/* + * bool + * extent_split(extent_hooks_t *extent_hooks, void *addr, size_t size, + * size_t size_a, size_t size_b, bool committed, unsigned arena_ind); + */ +typedef bool (extent_split_t)(extent_hooks_t *, void *, size_t, size_t, size_t, + bool, unsigned); + +/* + * bool + * extent_merge(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, + * void *addr_b, size_t size_b, bool committed, unsigned arena_ind); + */ +typedef bool (extent_merge_t)(extent_hooks_t *, void *, size_t, void *, size_t, + bool, unsigned); + +struct extent_hooks_s { + extent_alloc_t *alloc; + extent_dalloc_t *dalloc; + extent_destroy_t *destroy; + extent_commit_t *commit; + extent_decommit_t *decommit; + extent_purge_t *purge_lazy; + extent_purge_t *purge_forced; + extent_split_t *split; + extent_merge_t *merge; +}; + +/* + * By default application code must explicitly refer to mangled symbol names, + * so that it is possible to use jemalloc in conjunction with another allocator + * in the same application. Define JEMALLOC_MANGLE in order to cause automatic + * name mangling that matches the API prefixing that happened as a result of + * --with-mangling and/or --with-jemalloc-prefix configuration settings. + */ +#ifdef JEMALLOC_MANGLE +# ifndef JEMALLOC_NO_DEMANGLE +# define JEMALLOC_NO_DEMANGLE +# endif +# define aligned_alloc je_aligned_alloc +# define calloc je_calloc +# define dallocx je_dallocx +# define free je_free +# define mallctl je_mallctl +# define mallctlbymib je_mallctlbymib +# define mallctlnametomib je_mallctlnametomib +# define malloc je_malloc +# define malloc_conf je_malloc_conf +# define malloc_conf_2_conf_harder je_malloc_conf_2_conf_harder +# define malloc_message je_malloc_message +# define malloc_stats_print je_malloc_stats_print +# define malloc_usable_size je_malloc_usable_size +# define mallocx je_mallocx +# define smallocx_54eaed1d8b56b1aa528be3bdd1877e59c56fa90c je_smallocx_54eaed1d8b56b1aa528be3bdd1877e59c56fa90c +# define nallocx je_nallocx +# define posix_memalign je_posix_memalign +# define rallocx je_rallocx +# define realloc je_realloc +# define sallocx je_sallocx +# define sdallocx je_sdallocx +# define xallocx je_xallocx +# define valloc je_valloc +#endif + +/* + * The je_* macros can be used as stable alternative names for the + * public jemalloc API if JEMALLOC_NO_DEMANGLE is defined. This is primarily + * meant for use in jemalloc itself, but it can be used by application code to + * provide isolation from the name mangling specified via --with-mangling + * and/or --with-jemalloc-prefix. + */ +#ifndef JEMALLOC_NO_DEMANGLE +# undef je_aligned_alloc +# undef je_calloc +# undef je_dallocx +# undef je_free +# undef je_mallctl +# undef je_mallctlbymib +# undef je_mallctlnametomib +# undef je_malloc +# undef je_malloc_conf +# undef je_malloc_conf_2_conf_harder +# undef je_malloc_message +# undef je_malloc_stats_print +# undef je_malloc_usable_size +# undef je_mallocx +# undef je_smallocx_54eaed1d8b56b1aa528be3bdd1877e59c56fa90c +# undef je_nallocx +# undef je_posix_memalign +# undef je_rallocx +# undef je_realloc +# undef je_sallocx +# undef je_sdallocx +# undef je_xallocx +# undef je_valloc +#endif + +#ifdef __cplusplus +} +#endif +#endif /* JEMALLOC_H_ */ diff --git a/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/jemalloc_FreeBSD.h b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/jemalloc_FreeBSD.h new file mode 100644 index 000000000000..34c86271ab2e --- /dev/null +++ b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/jemalloc_FreeBSD.h @@ -0,0 +1,207 @@ +/* + * Override settings that were generated in jemalloc_defs.h as necessary. + */ + +#ifndef JEMALLOC_NO_PRIVATE_NAMESPACE + +#undef JEMALLOC_OVERRIDE_VALLOC + +#ifndef MALLOC_PRODUCTION +#define JEMALLOC_DEBUG +#endif + +#undef JEMALLOC_DSS + +#undef JEMALLOC_BACKGROUND_THREAD + +/* + * The following are architecture-dependent, so conditionally define them for + * each supported architecture. + */ +#undef JEMALLOC_TLS_MODEL +#undef LG_PAGE +#undef LG_VADDR +#undef LG_SIZEOF_PTR +#undef LG_SIZEOF_INT +#undef LG_SIZEOF_LONG +#undef LG_SIZEOF_INTMAX_T + +#ifdef __i386__ +# define LG_VADDR 32 +# define LG_SIZEOF_PTR 2 +# define JEMALLOC_TLS_MODEL __attribute__((tls_model("initial-exec"))) +#endif +#ifdef __ia64__ +# define LG_VADDR 64 +# define LG_SIZEOF_PTR 3 +#endif +#ifdef __sparc64__ +# define LG_VADDR 64 +# define LG_SIZEOF_PTR 3 +# define JEMALLOC_TLS_MODEL __attribute__((tls_model("initial-exec"))) +#endif +#ifdef __amd64__ +#ifdef _USE_LG_VADDR_WIDE +# define LG_VADDR 64 +#else +# define LG_VADDR 48 +#endif +# define LG_SIZEOF_PTR 3 +# define JEMALLOC_TLS_MODEL __attribute__((tls_model("initial-exec"))) +#endif +#ifdef __arm__ +# define LG_VADDR 32 +# define LG_SIZEOF_PTR 2 +#endif +#ifdef __aarch64__ +# define LG_VADDR 48 +# define LG_SIZEOF_PTR 3 +#endif +#ifdef __mips__ +#ifdef __mips_n64 +# define LG_VADDR 64 +# define LG_SIZEOF_PTR 3 +#else +# define LG_VADDR 32 +# define LG_SIZEOF_PTR 2 +#endif +#endif +#ifdef __powerpc64__ +# define LG_VADDR 64 +# define LG_SIZEOF_PTR 3 +# define JEMALLOC_TLS_MODEL __attribute__((tls_model("initial-exec"))) +#elif defined(__powerpc__) +# define LG_VADDR 32 +# define LG_SIZEOF_PTR 2 +# define JEMALLOC_TLS_MODEL __attribute__((tls_model("initial-exec"))) +#endif +#ifdef __riscv +# define LG_VADDR 48 +# define LG_SIZEOF_PTR 3 +#endif + +#if LG_VADDR > 32 +# define JEMALLOC_RETAIN +#endif + +#ifndef JEMALLOC_TLS_MODEL +# define JEMALLOC_TLS_MODEL /* Default. */ +#endif + +#define LG_PAGE PAGE_SHIFT +#define LG_SIZEOF_INT 2 +#define LG_SIZEOF_LONG LG_SIZEOF_PTR +#define LG_SIZEOF_INTMAX_T 3 + +#undef CPU_SPINWAIT +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#define CPU_SPINWAIT cpu_spinwait() + +/* + * Disable lazy-lock machinery, redirect isthreaded to libc's flag, undo + * jemalloc's namespace stuff for it and adjust its type. + */ +#undef JEMALLOC_LAZY_LOCK +#undef isthreaded +extern int __isthreaded; +#define isthreaded ((bool)__isthreaded) + +/* Mangle. */ +#undef je_malloc +#undef je_calloc +#undef je_posix_memalign +#undef je_aligned_alloc +#undef je_realloc +#undef je_free +#undef je_malloc_usable_size +#undef je_mallocx +#undef je_rallocx +#undef je_xallocx +#undef je_sallocx +#undef je_dallocx +#undef je_sdallocx +#undef je_nallocx +#undef je_mallctl +#undef je_mallctlnametomib +#undef je_mallctlbymib +#undef je_malloc_stats_print +#undef je_allocm +#undef je_rallocm +#undef je_dallocm +#undef je_nallocm +#define je_malloc __malloc +#define je_calloc __calloc +#define je_posix_memalign __posix_memalign +#define je_aligned_alloc __aligned_alloc +#define je_realloc __realloc +#define je_free __free +#define je_malloc_usable_size __malloc_usable_size +#define je_mallocx __mallocx +#define je_rallocx __rallocx +#define je_xallocx __xallocx +#define je_sallocx __sallocx +#define je_dallocx __dallocx +#define je_sdallocx __sdallocx +#define je_nallocx __nallocx +#define je_mallctl __mallctl +#define je_mallctlnametomib __mallctlnametomib +#define je_mallctlbymib __mallctlbymib +#define je_malloc_stats_print __malloc_stats_print +#define open _open +#define read _read +#define write _write +#define close _close +#define pthread_join _pthread_join +#define pthread_once _pthread_once +#define pthread_self _pthread_self +#define pthread_equal _pthread_equal +#define pthread_mutex_lock _pthread_mutex_lock +#define pthread_mutex_trylock _pthread_mutex_trylock +#define pthread_mutex_unlock _pthread_mutex_unlock +#define pthread_cond_init _pthread_cond_init +#define pthread_cond_wait _pthread_cond_wait +#define pthread_cond_timedwait _pthread_cond_timedwait +#define pthread_cond_signal _pthread_cond_signal + +#ifdef JEMALLOC_C_ +/* + * Define 'weak' symbols so that an application can have its own versions + * of malloc, calloc, realloc, free, et al. + */ +__weak_reference(__malloc, malloc); +__weak_reference(__calloc, calloc); +__weak_reference(__posix_memalign, posix_memalign); +__weak_reference(__aligned_alloc, aligned_alloc); +__weak_reference(__realloc, realloc); +__weak_reference(__free, free); +__weak_reference(__malloc_usable_size, malloc_usable_size); +__weak_reference(__mallocx, mallocx); +__weak_reference(__rallocx, rallocx); +__weak_reference(__xallocx, xallocx); +__weak_reference(__sallocx, sallocx); +__weak_reference(__dallocx, dallocx); +__weak_reference(__sdallocx, sdallocx); +__weak_reference(__nallocx, nallocx); +__weak_reference(__mallctl, mallctl); +__weak_reference(__mallctlnametomib, mallctlnametomib); +__weak_reference(__mallctlbymib, mallctlbymib); +__weak_reference(__malloc_stats_print, malloc_stats_print); +__weak_reference(je_allocm, weak_allocm); +__weak_reference(je_rallocm, weak_rallocm); +__weak_reference(je_sallocm, weak_sallocm); +__weak_reference(je_dallocm, weak_dallocm); +__weak_reference(je_nallocm, weak_nallocm); +__sym_compat(__allocm, je_allocm, FBSD_1.3); +__sym_compat(__rallocm, je_rallocm, FBSD_1.3); +__sym_compat(__sallocm, je_sallocm, FBSD_1.3); +__sym_compat(__dallocm, je_dallocm, FBSD_1.3); +__sym_compat(__nallocm, je_nallocm, FBSD_1.3); +__sym_compat(allocm, weak_allocm, FBSD_1.3); +__sym_compat(rallocm, weak_rallocm, FBSD_1.3); +__sym_compat(sallocm, weak_sallocm, FBSD_1.3); +__sym_compat(dallocm, weak_dallocm, FBSD_1.3); +__sym_compat(nallocm, weak_nallocm, FBSD_1.3); +#endif + +#endif diff --git a/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/jemalloc_defs.h b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/jemalloc_defs.h new file mode 100644 index 000000000000..fb104aaeec98 --- /dev/null +++ b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/jemalloc_defs.h @@ -0,0 +1,55 @@ +/* include/jemalloc/jemalloc_defs.h. Generated from jemalloc_defs.h.in by configure. */ +/* Defined if __attribute__((...)) syntax is supported. */ +#define JEMALLOC_HAVE_ATTR + +/* Defined if alloc_size attribute is supported. */ +#define JEMALLOC_HAVE_ATTR_ALLOC_SIZE + +/* Defined if format_arg(...) attribute is supported. */ +#define JEMALLOC_HAVE_ATTR_FORMAT_ARG + +/* Defined if format(gnu_printf, ...) attribute is supported. */ +#define JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF + +/* Defined if format(printf, ...) attribute is supported. */ +#define JEMALLOC_HAVE_ATTR_FORMAT_PRINTF + +/* Defined if fallthrough attribute is supported. */ +#define JEMALLOC_HAVE_ATTR_FALLTHROUGH + +/* Defined if cold attribute is supported. */ +#define JEMALLOC_HAVE_ATTR_COLD + +/* + * Define overrides for non-standard allocator-related functions if they are + * present on the system. + */ +#define JEMALLOC_OVERRIDE_MEMALIGN +#define JEMALLOC_OVERRIDE_VALLOC + +/* + * At least Linux omits the "const" in: + * + * size_t malloc_usable_size(const void *ptr); + * + * Match the operating system's prototype. + */ +#define JEMALLOC_USABLE_SIZE_CONST const + +/* + * If defined, specify throw() for the public function prototypes when compiling + * with C++. The only justification for this is to match the prototypes that + * glibc defines. + */ +/* #undef JEMALLOC_USE_CXX_THROW */ + +#ifdef _MSC_VER +# ifdef _WIN64 +# define LG_SIZEOF_PTR_WIN 3 +# else +# define LG_SIZEOF_PTR_WIN 2 +# endif +#endif + +/* sizeof(void *) == 2^LG_SIZEOF_PTR. */ +#define LG_SIZEOF_PTR 3 diff --git a/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/jemalloc_typedefs.h b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/jemalloc_typedefs.h new file mode 100644 index 000000000000..1a58874306eb --- /dev/null +++ b/lib/libc/stdlib/malloc/jemalloc/include/jemalloc/jemalloc_typedefs.h @@ -0,0 +1,77 @@ +typedef struct extent_hooks_s extent_hooks_t; + +/* + * void * + * extent_alloc(extent_hooks_t *extent_hooks, void *new_addr, size_t size, + * size_t alignment, bool *zero, bool *commit, unsigned arena_ind); + */ +typedef void *(extent_alloc_t)(extent_hooks_t *, void *, size_t, size_t, bool *, + bool *, unsigned); + +/* + * bool + * extent_dalloc(extent_hooks_t *extent_hooks, void *addr, size_t size, + * bool committed, unsigned arena_ind); + */ +typedef bool (extent_dalloc_t)(extent_hooks_t *, void *, size_t, bool, + unsigned); + +/* + * void + * extent_destroy(extent_hooks_t *extent_hooks, void *addr, size_t size, + * bool committed, unsigned arena_ind); + */ +typedef void (extent_destroy_t)(extent_hooks_t *, void *, size_t, bool, + unsigned); + +/* + * bool + * extent_commit(extent_hooks_t *extent_hooks, void *addr, size_t size, + * size_t offset, size_t length, unsigned arena_ind); + */ +typedef bool (extent_commit_t)(extent_hooks_t *, void *, size_t, size_t, size_t, + unsigned); + +/* + * bool + * extent_decommit(extent_hooks_t *extent_hooks, void *addr, size_t size, + * size_t offset, size_t length, unsigned arena_ind); + */ +typedef bool (extent_decommit_t)(extent_hooks_t *, void *, size_t, size_t, + size_t, unsigned); + +/* + * bool + * extent_purge(extent_hooks_t *extent_hooks, void *addr, size_t size, + * size_t offset, size_t length, unsigned arena_ind); + */ +typedef bool (extent_purge_t)(extent_hooks_t *, void *, size_t, size_t, size_t, + unsigned); + +/* + * bool + * extent_split(extent_hooks_t *extent_hooks, void *addr, size_t size, + * size_t size_a, size_t size_b, bool committed, unsigned arena_ind); + */ +typedef bool (extent_split_t)(extent_hooks_t *, void *, size_t, size_t, size_t, + bool, unsigned); + +/* + * bool + * extent_merge(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, + * void *addr_b, size_t size_b, bool committed, unsigned arena_ind); + */ +typedef bool (extent_merge_t)(extent_hooks_t *, void *, size_t, void *, size_t, + bool, unsigned); + +struct extent_hooks_s { + extent_alloc_t *alloc; + extent_dalloc_t *dalloc; + extent_destroy_t *destroy; + extent_commit_t *commit; + extent_decommit_t *decommit; + extent_purge_t *purge_lazy; + extent_purge_t *purge_forced; + extent_split_t *split; + extent_merge_t *merge; +}; diff --git a/lib/libc/stdlib/malloc/jemalloc/jemalloc.3 b/lib/libc/stdlib/malloc/jemalloc/jemalloc.3 new file mode 100644 index 000000000000..a4ea3e1f54a9 --- /dev/null +++ b/lib/libc/stdlib/malloc/jemalloc/jemalloc.3 @@ -0,0 +1,2560 @@ +'\" t +.\" Title: JEMALLOC +.\" Author: Jason Evans +.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/> +.\" Date: 11/10/2019 +.\" Manual: User Manual +.\" Source: jemalloc 5.2.1-0-gea6b3e973b477b8061e0076bb257dbd7f3faa756 +.\" Language: English +.\" +.TH "JEMALLOC" "3" "11/10/2019" "jemalloc 5.2.1-0-gea6b3e973b47" "User Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +jemalloc \- general purpose memory allocation functions +.SH "LIBRARY" +.PP +This manual describes jemalloc 5\&.2\&.1\-0\-gea6b3e973b477b8061e0076bb257dbd7f3faa756\&. More information can be found at the +\m[blue]\fBjemalloc website\fR\m[]\&\s-2\u[1]\d\s+2\&. +.PP +The following configuration options are enabled in libc\*(Aqs built\-in jemalloc: +\fB\-\-enable\-fill\fR, +\fB\-\-enable\-lazy\-lock\fR, +\fB\-\-enable\-stats\fR, +\fB\-\-enable\-utrace\fR, +\fB\-\-enable\-xmalloc\fR, and +\fB\-\-with\-malloc\-conf=abort_conf:false\fR\&. Additionally, +\fB\-\-enable\-debug\fR +is enabled in development versions of FreeBSD (controlled by the +\fBMK_MALLOC_PRODUCTION\fR +make variable)\&. +.SH "SYNOPSIS" +.sp +.ft B +.nf +#include <stdlib\&.h> +#include <malloc_np\&.h> +.fi +.ft +.SS "Standard API" +.HP \w'void\ *malloc('u +.BI "void *malloc(size_t\ " "size" ");" +.HP \w'void\ *calloc('u +.BI "void *calloc(size_t\ " "number" ", size_t\ " "size" ");" +.HP \w'int\ posix_memalign('u +.BI "int posix_memalign(void\ **" "ptr" ", size_t\ " "alignment" ", size_t\ " "size" ");" +.HP \w'void\ *aligned_alloc('u +.BI "void *aligned_alloc(size_t\ " "alignment" ", size_t\ " "size" ");" +.HP \w'void\ *realloc('u +.BI "void *realloc(void\ *" "ptr" ", size_t\ " "size" ");" +.HP \w'void\ free('u +.BI "void free(void\ *" "ptr" ");" +.SS "Non\-standard API" +.HP \w'void\ *mallocx('u +.BI "void *mallocx(size_t\ " "size" ", int\ " "flags" ");" +.HP \w'void\ *rallocx('u +.BI "void *rallocx(void\ *" "ptr" ", size_t\ " "size" ", int\ " "flags" ");" +.HP \w'size_t\ xallocx('u +.BI "size_t xallocx(void\ *" "ptr" ", size_t\ " "size" ", size_t\ " "extra" ", int\ " "flags" ");" +.HP \w'size_t\ sallocx('u +.BI "size_t sallocx(void\ *" "ptr" ", int\ " "flags" ");" +.HP \w'void\ dallocx('u +.BI "void dallocx(void\ *" "ptr" ", int\ " "flags" ");" +.HP \w'void\ sdallocx('u +.BI "void sdallocx(void\ *" "ptr" ", size_t\ " "size" ", int\ " "flags" ");" +.HP \w'size_t\ nallocx('u +.BI "size_t nallocx(size_t\ " "size" ", int\ " "flags" ");" +.HP \w'int\ mallctl('u +.BI "int mallctl(const\ char\ *" "name" ", void\ *" "oldp" ", size_t\ *" "oldlenp" ", void\ *" "newp" ", size_t\ " "newlen" ");" +.HP \w'int\ mallctlnametomib('u +.BI "int mallctlnametomib(const\ char\ *" "name" ", size_t\ *" "mibp" ", size_t\ *" "miblenp" ");" +.HP \w'int\ mallctlbymib('u +.BI "int mallctlbymib(const\ size_t\ *" "mib" ", size_t\ " "miblen" ", void\ *" "oldp" ", size_t\ *" "oldlenp" ", void\ *" "newp" ", size_t\ " "newlen" ");" +.HP \w'void\ malloc_stats_print('u +.BI "void malloc_stats_print(void\ " "(*write_cb)" "\ (void\ *,\ const\ char\ *), void\ *" "cbopaque" ", const\ char\ *" "opts" ");" +.HP \w'size_t\ malloc_usable_size('u +.BI "size_t malloc_usable_size(const\ void\ *" "ptr" ");" +.HP \w'void\ (*malloc_message)('u +.BI "void (*malloc_message)(void\ *" "cbopaque" ", const\ char\ *" "s" ");" +.PP +const char *\fImalloc_conf\fR; +.SH "DESCRIPTION" +.SS "Standard API" +.PP +The +malloc() +function allocates +\fIsize\fR +bytes of uninitialized memory\&. The allocated space is suitably aligned (after possible pointer coercion) for storage of any type of object\&. +.PP +The +calloc() +function allocates space for +\fInumber\fR +objects, each +\fIsize\fR +bytes in length\&. The result is identical to calling +malloc() +with an argument of +\fInumber\fR +* +\fIsize\fR, with the exception that the allocated memory is explicitly initialized to zero bytes\&. +.PP +The +posix_memalign() +function allocates +\fIsize\fR +bytes of memory such that the allocation\*(Aqs base address is a multiple of +\fIalignment\fR, and returns the allocation in the value pointed to by +\fIptr\fR\&. The requested +\fIalignment\fR +must be a power of 2 at least as large as +sizeof(\fBvoid *\fR)\&. +.PP +The +aligned_alloc() +function allocates +\fIsize\fR +bytes of memory such that the allocation\*(Aqs base address is a multiple of +\fIalignment\fR\&. The requested +\fIalignment\fR +must be a power of 2\&. Behavior is undefined if +\fIsize\fR +is not an integral multiple of +\fIalignment\fR\&. +.PP +The +realloc() +function changes the size of the previously allocated memory referenced by +\fIptr\fR +to +\fIsize\fR +bytes\&. The contents of the memory are unchanged up to the lesser of the new and old sizes\&. If the new size is larger, the contents of the newly allocated portion of the memory are undefined\&. Upon success, the memory referenced by +\fIptr\fR +is freed and a pointer to the newly allocated memory is returned\&. Note that +realloc() +may move the memory allocation, resulting in a different return value than +\fIptr\fR\&. If +\fIptr\fR +is +\fBNULL\fR, the +realloc() +function behaves identically to +malloc() +for the specified size\&. +.PP +The +free() +function causes the allocated memory referenced by +\fIptr\fR +to be made available for future allocations\&. If +\fIptr\fR +is +\fBNULL\fR, no action occurs\&. +.SS "Non\-standard API" +.PP +The +mallocx(), +rallocx(), +xallocx(), +sallocx(), +dallocx(), +sdallocx(), and +nallocx() +functions all have a +\fIflags\fR +argument that can be used to specify options\&. The functions only check the options that are contextually relevant\&. Use bitwise or (|) operations to specify one or more of the following: +.PP +\fBMALLOCX_LG_ALIGN(\fR\fB\fIla\fR\fR\fB) \fR +.RS 4 +Align the memory allocation to start at an address that is a multiple of +(1 << \fIla\fR)\&. This macro does not validate that +\fIla\fR +is within the valid range\&. +.RE +.PP +\fBMALLOCX_ALIGN(\fR\fB\fIa\fR\fR\fB) \fR +.RS 4 +Align the memory allocation to start at an address that is a multiple of +\fIa\fR, where +\fIa\fR +is a power of two\&. This macro does not validate that +\fIa\fR +is a power of 2\&. +.RE +.PP +\fBMALLOCX_ZERO\fR +.RS 4 +Initialize newly allocated memory to contain zero bytes\&. In the growing reallocation case, the real size prior to reallocation defines the boundary between untouched bytes and those that are initialized to contain zero bytes\&. If this macro is absent, newly allocated memory is uninitialized\&. +.RE +.PP +\fBMALLOCX_TCACHE(\fR\fB\fItc\fR\fR\fB) \fR +.RS 4 +Use the thread\-specific cache (tcache) specified by the identifier +\fItc\fR, which must have been acquired via the +tcache\&.create +mallctl\&. This macro does not validate that +\fItc\fR +specifies a valid identifier\&. +.RE +.PP +\fBMALLOCX_TCACHE_NONE\fR +.RS 4 +Do not use a thread\-specific cache (tcache)\&. Unless +\fBMALLOCX_TCACHE(\fR\fB\fItc\fR\fR\fB)\fR +or +\fBMALLOCX_TCACHE_NONE\fR +is specified, an automatically managed tcache will be used under many circumstances\&. This macro cannot be used in the same +\fIflags\fR +argument as +\fBMALLOCX_TCACHE(\fR\fB\fItc\fR\fR\fB)\fR\&. +.RE +.PP +\fBMALLOCX_ARENA(\fR\fB\fIa\fR\fR\fB) \fR +.RS 4 +Use the arena specified by the index +\fIa\fR\&. This macro has no effect for regions that were allocated via an arena other than the one specified\&. This macro does not validate that +\fIa\fR +specifies an arena index in the valid range\&. +.RE +.PP +The +mallocx() +function allocates at least +\fIsize\fR +bytes of memory, and returns a pointer to the base address of the allocation\&. Behavior is undefined if +\fIsize\fR +is +\fB0\fR\&. +.PP +The +rallocx() +function resizes the allocation at +\fIptr\fR +to be at least +\fIsize\fR +bytes, and returns a pointer to the base address of the resulting allocation, which may or may not have moved from its original location\&. Behavior is undefined if +\fIsize\fR +is +\fB0\fR\&. +.PP +The +xallocx() +function resizes the allocation at +\fIptr\fR +in place to be at least +\fIsize\fR +bytes, and returns the real size of the allocation\&. If +\fIextra\fR +is non\-zero, an attempt is made to resize the allocation to be at least +(\fIsize\fR + \fIextra\fR) +bytes, though inability to allocate the extra byte(s) will not by itself result in failure to resize\&. Behavior is undefined if +\fIsize\fR +is +\fB0\fR, or if +(\fIsize\fR + \fIextra\fR > \fBSIZE_T_MAX\fR)\&. +.PP +The +sallocx() +function returns the real size of the allocation at +\fIptr\fR\&. +.PP +The +dallocx() +function causes the memory referenced by +\fIptr\fR +to be made available for future allocations\&. +.PP +The +sdallocx() +function is an extension of +dallocx() +with a +\fIsize\fR +parameter to allow the caller to pass in the allocation size as an optimization\&. The minimum valid input size is the original requested size of the allocation, and the maximum valid input size is the corresponding value returned by +nallocx() +or +sallocx()\&. +.PP +The +nallocx() +function allocates no memory, but it performs the same size computation as the +mallocx() +function, and returns the real size of the allocation that would result from the equivalent +mallocx() +function call, or +\fB0\fR +if the inputs exceed the maximum supported size class and/or alignment\&. Behavior is undefined if +\fIsize\fR +is +\fB0\fR\&. +.PP +The +mallctl() +function provides a general interface for introspecting the memory allocator, as well as setting modifiable parameters and triggering actions\&. The period\-separated +\fIname\fR +argument specifies a location in a tree\-structured namespace; see the +MALLCTL NAMESPACE +section for documentation on the tree contents\&. To read a value, pass a pointer via +\fIoldp\fR +to adequate space to contain the value, and a pointer to its length via +\fIoldlenp\fR; otherwise pass +\fBNULL\fR +and +\fBNULL\fR\&. Similarly, to write a value, pass a pointer to the value via +\fInewp\fR, and its length via +\fInewlen\fR; otherwise pass +\fBNULL\fR +and +\fB0\fR\&. +.PP +The +mallctlnametomib() +function provides a way to avoid repeated name lookups for applications that repeatedly query the same portion of the namespace, by translating a name to a +\(lqManagement Information Base\(rq +(MIB) that can be passed repeatedly to +mallctlbymib()\&. Upon successful return from +mallctlnametomib(), +\fImibp\fR +contains an array of +\fI*miblenp\fR +integers, where +\fI*miblenp\fR +is the lesser of the number of components in +\fIname\fR +and the input value of +\fI*miblenp\fR\&. Thus it is possible to pass a +\fI*miblenp\fR +that is smaller than the number of period\-separated name components, which results in a partial MIB that can be used as the basis for constructing a complete MIB\&. For name components that are integers (e\&.g\&. the 2 in +arenas\&.bin\&.2\&.size), the corresponding MIB component will always be that integer\&. Therefore, it is legitimate to construct code like the following: +.sp +.if n \{\ +.RS 4 +.\} +.nf +unsigned nbins, i; +size_t mib[4]; +size_t len, miblen; + +len = sizeof(nbins); +mallctl("arenas\&.nbins", &nbins, &len, NULL, 0); + +miblen = 4; +mallctlnametomib("arenas\&.bin\&.0\&.size", mib, &miblen); +for (i = 0; i < nbins; i++) { + size_t bin_size; + + mib[2] = i; + len = sizeof(bin_size); + mallctlbymib(mib, miblen, (void *)&bin_size, &len, NULL, 0); + /* Do something with bin_size\&.\&.\&. */ +} +.fi +.if n \{\ +.RE +.\} +.PP +.RS 4 +.RE +.PP +The +malloc_stats_print() +function writes summary statistics via the +\fIwrite_cb\fR +callback function pointer and +\fIcbopaque\fR +data passed to +\fIwrite_cb\fR, or +malloc_message() +if +\fIwrite_cb\fR +is +\fBNULL\fR\&. The statistics are presented in human\-readable form unless +\(lqJ\(rq +is specified as a character within the +\fIopts\fR +string, in which case the statistics are presented in +\m[blue]\fBJSON format\fR\m[]\&\s-2\u[2]\d\s+2\&. This function can be called repeatedly\&. General information that never changes during execution can be omitted by specifying +\(lqg\(rq +as a character within the +\fIopts\fR +string\&. Note that +malloc_stats_print() +uses the +mallctl*() +functions internally, so inconsistent statistics can be reported if multiple threads use these functions simultaneously\&. If +\fB\-\-enable\-stats\fR +is specified during configuration, +\(lqm\(rq, +\(lqd\(rq, and +\(lqa\(rq +can be specified to omit merged arena, destroyed merged arena, and per arena statistics, respectively; +\(lqb\(rq +and +\(lql\(rq +can be specified to omit per size class statistics for bins and large objects, respectively; +\(lqx\(rq +can be specified to omit all mutex statistics; +\(lqe\(rq +can be used to omit extent statistics\&. Unrecognized characters are silently ignored\&. Note that thread caching may prevent some statistics from being completely up to date, since extra locking would be required to merge counters that track thread cache operations\&. +.PP +The +malloc_usable_size() +function returns the usable size of the allocation pointed to by +\fIptr\fR\&. The return value may be larger than the size that was requested during allocation\&. The +malloc_usable_size() +function is not a mechanism for in\-place +realloc(); rather it is provided solely as a tool for introspection purposes\&. Any discrepancy between the requested allocation size and the size reported by +malloc_usable_size() +should not be depended on, since such behavior is entirely implementation\-dependent\&. +.SH "TUNING" +.PP +Once, when the first call is made to one of the memory allocation routines, the allocator initializes its internals based in part on various options that can be specified at compile\- or run\-time\&. +.PP +The string specified via +\fB\-\-with\-malloc\-conf\fR, the string pointed to by the global variable +\fImalloc_conf\fR, the +\(lqname\(rq +of the file referenced by the symbolic link named +/etc/malloc\&.conf, and the value of the environment variable +\fBMALLOC_CONF\fR, will be interpreted, in that order, from left to right as options\&. Note that +\fImalloc_conf\fR +may be read before +main() +is entered, so the declaration of +\fImalloc_conf\fR +should specify an initializer that contains the final value to be read by jemalloc\&. +\fB\-\-with\-malloc\-conf\fR +and +\fImalloc_conf\fR +are compile\-time mechanisms, whereas +/etc/malloc\&.conf +and +\fBMALLOC_CONF\fR +can be safely set any time prior to program invocation\&. +.PP +An options string is a comma\-separated list of option:value pairs\&. There is one key corresponding to each +opt\&.* +mallctl (see the +MALLCTL NAMESPACE +section for options documentation)\&. For example, +abort:true,narenas:1 +sets the +opt\&.abort +and +opt\&.narenas +options\&. Some options have boolean values (true/false), others have integer values (base 8, 10, or 16, depending on prefix), and yet others have raw string values\&. +.SH "IMPLEMENTATION NOTES" +.PP +Traditionally, allocators have used +\fBsbrk\fR(2) +to obtain memory, which is suboptimal for several reasons, including race conditions, increased fragmentation, and artificial limitations on maximum usable memory\&. If +\fBsbrk\fR(2) +is supported by the operating system, this allocator uses both +\fBmmap\fR(2) +and +\fBsbrk\fR(2), in that order of preference; otherwise only +\fBmmap\fR(2) +is used\&. +.PP +This allocator uses multiple arenas in order to reduce lock contention for threaded programs on multi\-processor systems\&. This works well with regard to threading scalability, but incurs some costs\&. There is a small fixed per\-arena overhead, and additionally, arenas manage memory completely independently of each other, which means a small fixed increase in overall memory fragmentation\&. These overheads are not generally an issue, given the number of arenas normally used\&. Note that using substantially more arenas than the default is not likely to improve performance, mainly due to reduced cache performance\&. However, it may make sense to reduce the number of arenas if an application does not make much use of the allocation functions\&. +.PP +In addition to multiple arenas, this allocator supports thread\-specific caching, in order to make it possible to completely avoid synchronization for most allocation requests\&. Such caching allows very fast allocation in the common case, but it increases memory usage and fragmentation, since a bounded number of objects can remain allocated in each thread cache\&. +.PP +Memory is conceptually broken into extents\&. Extents are always aligned to multiples of the page size\&. This alignment makes it possible to find metadata for user objects quickly\&. User objects are broken into two categories according to size: small and large\&. Contiguous small objects comprise a slab, which resides within a single extent, whereas large objects each have their own extents backing them\&. +.PP +Small objects are managed in groups by slabs\&. Each slab maintains a bitmap to track which regions are in use\&. Allocation requests that are no more than half the quantum (8 or 16, depending on architecture) are rounded up to the nearest power of two that is at least +sizeof(\fBdouble\fR)\&. All other object size classes are multiples of the quantum, spaced such that there are four size classes for each doubling in size, which limits internal fragmentation to approximately 20% for all but the smallest size classes\&. Small size classes are smaller than four times the page size, and large size classes extend from four times the page size up to the largest size class that does not exceed +\fBPTRDIFF_MAX\fR\&. +.PP +Allocations are packed tightly together, which can be an issue for multi\-threaded applications\&. If you need to assure that allocations do not suffer from cacheline sharing, round your allocation requests up to the nearest multiple of the cacheline size, or specify cacheline alignment when allocating\&. +.PP +The +realloc(), +rallocx(), and +xallocx() +functions may resize allocations without moving them under limited circumstances\&. Unlike the +*allocx() +API, the standard API does not officially round up the usable size of an allocation to the nearest size class, so technically it is necessary to call +realloc() +to grow e\&.g\&. a 9\-byte allocation to 16 bytes, or shrink a 16\-byte allocation to 9 bytes\&. Growth and shrinkage trivially succeeds in place as long as the pre\-size and post\-size both round up to the same size class\&. No other API guarantees are made regarding in\-place resizing, but the current implementation also tries to resize large allocations in place, as long as the pre\-size and post\-size are both large\&. For shrinkage to succeed, the extent allocator must support splitting (see +arena\&.<i>\&.extent_hooks)\&. Growth only succeeds if the trailing memory is currently available, and the extent allocator supports merging\&. +.PP +Assuming 4 KiB pages and a 16\-byte quantum on a 64\-bit system, the size classes in each category are as shown in +Table 1\&. +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.B Table\ \&1.\ \&Size classes +.TS +allbox tab(:); +lB rB lB. +T{ +Category +T}:T{ +Spacing +T}:T{ +Size +T} +.T& +l r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l +l r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l +^ r l. +T{ +Small +T}:T{ +lg +T}:T{ +[8] +T} +:T{ +16 +T}:T{ +[16, 32, 48, 64, 80, 96, 112, 128] +T} +:T{ +32 +T}:T{ +[160, 192, 224, 256] +T} +:T{ +64 +T}:T{ +[320, 384, 448, 512] +T} +:T{ +128 +T}:T{ +[640, 768, 896, 1024] +T} +:T{ +256 +T}:T{ +[1280, 1536, 1792, 2048] +T} +:T{ +512 +T}:T{ +[2560, 3072, 3584, 4096] +T} +:T{ +1 KiB +T}:T{ +[5 KiB, 6 KiB, 7 KiB, 8 KiB] +T} +:T{ +2 KiB +T}:T{ +[10 KiB, 12 KiB, 14 KiB] +T} +T{ +Large +T}:T{ +2 KiB +T}:T{ +[16 KiB] +T} +:T{ +4 KiB +T}:T{ +[20 KiB, 24 KiB, 28 KiB, 32 KiB] +T} +:T{ +8 KiB +T}:T{ +[40 KiB, 48 KiB, 54 KiB, 64 KiB] +T} +:T{ +16 KiB +T}:T{ +[80 KiB, 96 KiB, 112 KiB, 128 KiB] +T} +:T{ +32 KiB +T}:T{ +[160 KiB, 192 KiB, 224 KiB, 256 KiB] +T} +:T{ +64 KiB +T}:T{ +[320 KiB, 384 KiB, 448 KiB, 512 KiB] +T} +:T{ +128 KiB +T}:T{ +[640 KiB, 768 KiB, 896 KiB, 1 MiB] +T} +:T{ +256 KiB +T}:T{ +[1280 KiB, 1536 KiB, 1792 KiB, 2 MiB] +T} +:T{ +512 KiB +T}:T{ +[2560 KiB, 3 MiB, 3584 KiB, 4 MiB] +T} +:T{ +1 MiB +T}:T{ +[5 MiB, 6 MiB, 7 MiB, 8 MiB] +T} +:T{ +2 MiB +T}:T{ +[10 MiB, 12 MiB, 14 MiB, 16 MiB] +T} +:T{ +4 MiB +T}:T{ +[20 MiB, 24 MiB, 28 MiB, 32 MiB] +T} +:T{ +8 MiB +T}:T{ +[40 MiB, 48 MiB, 56 MiB, 64 MiB] +T} +:T{ +\&.\&.\&. +T}:T{ +\&.\&.\&. +T} +:T{ +512 PiB +T}:T{ +[2560 PiB, 3 EiB, 3584 PiB, 4 EiB] +T} +:T{ +1 EiB +T}:T{ +[5 EiB, 6 EiB, 7 EiB] +T} +.TE +.sp 1 +.SH "MALLCTL NAMESPACE" +.PP +The following names are defined in the namespace accessible via the +mallctl*() +functions\&. Value types are specified in parentheses, their readable/writable statuses are encoded as +rw, +r\-, +\-w, or +\-\-, and required build configuration flags follow, if any\&. A name element encoded as +<i> +or +<j> +indicates an integer component, where the integer varies from 0 to some upper value that must be determined via introspection\&. In the case of +stats\&.arenas\&.<i>\&.* +and +arena\&.<i>\&.{initialized,purge,decay,dss}, +<i> +equal to +\fBMALLCTL_ARENAS_ALL\fR +can be used to operate on all arenas or access the summation of statistics from all arenas; similarly +<i> +equal to +\fBMALLCTL_ARENAS_DESTROYED\fR +can be used to access the summation of statistics from all destroyed arenas\&. These constants can be utilized either via +mallctlnametomib() +followed by +mallctlbymib(), or via code such as the following: +.sp +.if n \{\ +.RS 4 +.\} +.nf +#define STRINGIFY_HELPER(x) #x +#define STRINGIFY(x) STRINGIFY_HELPER(x) + +mallctl("arena\&." STRINGIFY(MALLCTL_ARENAS_ALL) "\&.decay", + NULL, NULL, NULL, 0); +.fi +.if n \{\ +.RE +.\} +.sp +Take special note of the +epoch +mallctl, which controls refreshing of cached dynamic statistics\&. +.PP +version (\fBconst char *\fR) r\- +.RS 4 +Return the jemalloc version string\&. +.RE +.PP +epoch (\fBuint64_t\fR) rw +.RS 4 +If a value is passed in, refresh the data from which the +mallctl*() +functions report values, and increment the epoch\&. Return the current epoch\&. This is useful for detecting whether another thread caused a refresh\&. +.RE +.PP +background_thread (\fBbool\fR) rw +.RS 4 +Enable/disable internal background worker threads\&. When set to true, background threads are created on demand (the number of background threads will be no more than the number of CPUs or active arenas)\&. Threads run periodically, and handle +purging +asynchronously\&. When switching off, background threads are terminated synchronously\&. Note that after +\fBfork\fR(2) +function, the state in the child process will be disabled regardless the state in parent process\&. See +stats\&.background_thread +for related stats\&. +opt\&.background_thread +can be used to set the default option\&. This option is only available on selected pthread\-based platforms\&. +.RE +.PP +max_background_threads (\fBsize_t\fR) rw +.RS 4 +Maximum number of background worker threads that will be created\&. This value is capped at +opt\&.max_background_threads +at startup\&. +.RE +.PP +config\&.cache_oblivious (\fBbool\fR) r\- +.RS 4 +\fB\-\-enable\-cache\-oblivious\fR +was specified during build configuration\&. +.RE +.PP +config\&.debug (\fBbool\fR) r\- +.RS 4 +\fB\-\-enable\-debug\fR +was specified during build configuration\&. +.RE +.PP +config\&.fill (\fBbool\fR) r\- +.RS 4 +\fB\-\-enable\-fill\fR +was specified during build configuration\&. +.RE +.PP +config\&.lazy_lock (\fBbool\fR) r\- +.RS 4 +\fB\-\-enable\-lazy\-lock\fR +was specified during build configuration\&. +.RE +.PP +config\&.malloc_conf (\fBconst char *\fR) r\- +.RS 4 +Embedded configure\-time\-specified run\-time options string, empty unless +\fB\-\-with\-malloc\-conf\fR +was specified during build configuration\&. +.RE +.PP +config\&.prof (\fBbool\fR) r\- +.RS 4 +\fB\-\-enable\-prof\fR +was specified during build configuration\&. +.RE +.PP +config\&.prof_libgcc (\fBbool\fR) r\- +.RS 4 +\fB\-\-disable\-prof\-libgcc\fR +was not specified during build configuration\&. +.RE +.PP +config\&.prof_libunwind (\fBbool\fR) r\- +.RS 4 +\fB\-\-enable\-prof\-libunwind\fR +was specified during build configuration\&. +.RE +.PP +config\&.stats (\fBbool\fR) r\- +.RS 4 +\fB\-\-enable\-stats\fR +was specified during build configuration\&. +.RE +.PP +config\&.utrace (\fBbool\fR) r\- +.RS 4 +\fB\-\-enable\-utrace\fR +was specified during build configuration\&. +.RE +.PP +config\&.xmalloc (\fBbool\fR) r\- +.RS 4 +\fB\-\-enable\-xmalloc\fR +was specified during build configuration\&. +.RE +.PP +opt\&.abort (\fBbool\fR) r\- +.RS 4 +Abort\-on\-warning enabled/disabled\&. If true, most warnings are fatal\&. Note that runtime option warnings are not included (see +opt\&.abort_conf +for that)\&. The process will call +\fBabort\fR(3) +in these cases\&. This option is disabled by default unless +\fB\-\-enable\-debug\fR +is specified during configuration, in which case it is enabled by default\&. +.RE +.PP +opt\&.confirm_conf (\fBbool\fR) r\- +.RS 4 +Confirm\-runtime\-options\-when\-program\-starts enabled/disabled\&. If true, the string specified via +\fB\-\-with\-malloc\-conf\fR, the string pointed to by the global variable +\fImalloc_conf\fR, the +\(lqname\(rq +of the file referenced by the symbolic link named +/etc/malloc\&.conf, and the value of the environment variable +\fBMALLOC_CONF\fR, will be printed in order\&. Then, each option being set will be individually printed\&. This option is disabled by default\&. +.RE +.PP +opt\&.abort_conf (\fBbool\fR) r\- +.RS 4 +Abort\-on\-invalid\-configuration enabled/disabled\&. If true, invalid runtime options are fatal\&. The process will call +\fBabort\fR(3) +in these cases\&. This option is disabled by default unless +\fB\-\-enable\-debug\fR +is specified during configuration, in which case it is enabled by default\&. +.RE +.PP +opt\&.metadata_thp (\fBconst char *\fR) r\- +.RS 4 +Controls whether to allow jemalloc to use transparent huge page (THP) for internal metadata (see +stats\&.metadata)\&. +\(lqalways\(rq +allows such usage\&. +\(lqauto\(rq +uses no THP initially, but may begin to do so when metadata usage reaches certain level\&. The default is +\(lqdisabled\(rq\&. +.RE +.PP +opt\&.retain (\fBbool\fR) r\- +.RS 4 +If true, retain unused virtual memory for later reuse rather than discarding it by calling +\fBmunmap\fR(2) +or equivalent (see +stats\&.retained +for related details)\&. It also makes jemalloc use +\fBmmap\fR(2) +or equivalent in a more greedy way, mapping larger chunks in one go\&. This option is disabled by default unless discarding virtual memory is known to trigger platform\-specific performance problems, namely 1) for [64\-bit] Linux, which has a quirk in its virtual memory allocation algorithm that causes semi\-permanent VM map holes under normal jemalloc operation; and 2) for [64\-bit] Windows, which disallows split / merged regions with +\fI\fBMEM_RELEASE\fR\fR\&. Although the same issues may present on 32\-bit platforms as well, retaining virtual memory for 32\-bit Linux and Windows is disabled by default due to the practical possibility of address space exhaustion\&. +.RE +.PP +opt\&.dss (\fBconst char *\fR) r\- +.RS 4 +dss (\fBsbrk\fR(2)) allocation precedence as related to +\fBmmap\fR(2) +allocation\&. The following settings are supported if +\fBsbrk\fR(2) +is supported by the operating system: +\(lqdisabled\(rq, +\(lqprimary\(rq, and +\(lqsecondary\(rq; otherwise only +\(lqdisabled\(rq +is supported\&. The default is +\(lqsecondary\(rq +if +\fBsbrk\fR(2) +is supported by the operating system; +\(lqdisabled\(rq +otherwise\&. +.RE +.PP +opt\&.narenas (\fBunsigned\fR) r\- +.RS 4 +Maximum number of arenas to use for automatic multiplexing of threads and arenas\&. The default is four times the number of CPUs, or one if there is a single CPU\&. +.RE +.PP +opt\&.oversize_threshold (\fBsize_t\fR) r\- +.RS 4 +The threshold in bytes of which requests are considered oversize\&. Allocation requests with greater sizes are fulfilled from a dedicated arena (automatically managed, however not within +narenas), in order to reduce fragmentation by not mixing huge allocations with small ones\&. In addition, the decay API guarantees on the extents greater than the specified threshold may be overridden\&. Note that requests with arena index specified via +\fBMALLOCX_ARENA\fR, or threads associated with explicit arenas will not be considered\&. The default threshold is 8MiB\&. Values not within large size classes disables this feature\&. +.RE +.PP +opt\&.percpu_arena (\fBconst char *\fR) r\- +.RS 4 +Per CPU arena mode\&. Use the +\(lqpercpu\(rq +setting to enable this feature, which uses number of CPUs to determine number of arenas, and bind threads to arenas dynamically based on the CPU the thread runs on currently\&. +\(lqphycpu\(rq +setting uses one arena per physical CPU, which means the two hyper threads on the same CPU share one arena\&. Note that no runtime checking regarding the availability of hyper threading is done at the moment\&. When set to +\(lqdisabled\(rq, narenas and thread to arena association will not be impacted by this option\&. The default is +\(lqdisabled\(rq\&. +.RE +.PP +opt\&.background_thread (\fBbool\fR) r\- +.RS 4 +Internal background worker threads enabled/disabled\&. Because of potential circular dependencies, enabling background thread using this option may cause crash or deadlock during initialization\&. For a reliable way to use this feature, see +background_thread +for dynamic control options and details\&. This option is disabled by default\&. +.RE +.PP +opt\&.max_background_threads (\fBsize_t\fR) r\- +.RS 4 +Maximum number of background threads that will be created if +background_thread +is set\&. Defaults to number of cpus\&. +.RE +.PP +opt\&.dirty_decay_ms (\fBssize_t\fR) r\- +.RS 4 +Approximate time in milliseconds from the creation of a set of unused dirty pages until an equivalent set of unused dirty pages is purged (i\&.e\&. converted to muzzy via e\&.g\&. +madvise(\fI\&.\&.\&.\fR\fI\fBMADV_FREE\fR\fR) +if supported by the operating system, or converted to clean otherwise) and/or reused\&. Dirty pages are defined as previously having been potentially written to by the application, and therefore consuming physical memory, yet having no current use\&. The pages are incrementally purged according to a sigmoidal decay curve that starts and ends with zero purge rate\&. A decay time of 0 causes all unused dirty pages to be purged immediately upon creation\&. A decay time of \-1 disables purging\&. The default decay time is 10 seconds\&. See +arenas\&.dirty_decay_ms +and +arena\&.<i>\&.dirty_decay_ms +for related dynamic control options\&. See +opt\&.muzzy_decay_ms +for a description of muzzy pages\&.for a description of muzzy pages\&. Note that when the +oversize_threshold +feature is enabled, the arenas reserved for oversize requests may have its own default decay settings\&. +.RE +.PP +opt\&.muzzy_decay_ms (\fBssize_t\fR) r\- +.RS 4 +Approximate time in milliseconds from the creation of a set of unused muzzy pages until an equivalent set of unused muzzy pages is purged (i\&.e\&. converted to clean) and/or reused\&. Muzzy pages are defined as previously having been unused dirty pages that were subsequently purged in a manner that left them subject to the reclamation whims of the operating system (e\&.g\&. +madvise(\fI\&.\&.\&.\fR\fI\fBMADV_FREE\fR\fR)), and therefore in an indeterminate state\&. The pages are incrementally purged according to a sigmoidal decay curve that starts and ends with zero purge rate\&. A decay time of 0 causes all unused muzzy pages to be purged immediately upon creation\&. A decay time of \-1 disables purging\&. The default decay time is 10 seconds\&. See +arenas\&.muzzy_decay_ms +and +arena\&.<i>\&.muzzy_decay_ms +for related dynamic control options\&. +.RE +.PP +opt\&.lg_extent_max_active_fit (\fBsize_t\fR) r\- +.RS 4 +When reusing dirty extents, this determines the (log base 2 of the) maximum ratio between the size of the active extent selected (to split off from) and the size of the requested allocation\&. This prevents the splitting of large active extents for smaller allocations, which can reduce fragmentation over the long run (especially for non\-active extents)\&. Lower value may reduce fragmentation, at the cost of extra active extents\&. The default value is 6, which gives a maximum ratio of 64 (2^6)\&. +.RE +.PP +opt\&.stats_print (\fBbool\fR) r\- +.RS 4 +Enable/disable statistics printing at exit\&. If enabled, the +malloc_stats_print() +function is called at program exit via an +\fBatexit\fR(3) +function\&. +opt\&.stats_print_opts +can be combined to specify output options\&. If +\fB\-\-enable\-stats\fR +is specified during configuration, this has the potential to cause deadlock for a multi\-threaded process that exits while one or more threads are executing in the memory allocation functions\&. Furthermore, +atexit() +may allocate memory during application initialization and then deadlock internally when jemalloc in turn calls +atexit(), so this option is not universally usable (though the application can register its own +atexit() +function with equivalent functionality)\&. Therefore, this option should only be used with care; it is primarily intended as a performance tuning aid during application development\&. This option is disabled by default\&. +.RE +.PP +opt\&.stats_print_opts (\fBconst char *\fR) r\- +.RS 4 +Options (the +\fIopts\fR +string) to pass to the +malloc_stats_print() +at exit (enabled through +opt\&.stats_print)\&. See available options in +malloc_stats_print()\&. Has no effect unless +opt\&.stats_print +is enabled\&. The default is +\(lq\(rq\&. +.RE +.PP +opt\&.junk (\fBconst char *\fR) r\- [\fB\-\-enable\-fill\fR] +.RS 4 +Junk filling\&. If set to +\(lqalloc\(rq, each byte of uninitialized allocated memory will be initialized to +0xa5\&. If set to +\(lqfree\(rq, all deallocated memory will be initialized to +0x5a\&. If set to +\(lqtrue\(rq, both allocated and deallocated memory will be initialized, and if set to +\(lqfalse\(rq, junk filling be disabled entirely\&. This is intended for debugging and will impact performance negatively\&. This option is +\(lqfalse\(rq +by default unless +\fB\-\-enable\-debug\fR +is specified during configuration, in which case it is +\(lqtrue\(rq +by default\&. +.RE +.PP +opt\&.zero (\fBbool\fR) r\- [\fB\-\-enable\-fill\fR] +.RS 4 +Zero filling enabled/disabled\&. If enabled, each byte of uninitialized allocated memory will be initialized to 0\&. Note that this initialization only happens once for each byte, so +realloc() +and +rallocx() +calls do not zero memory that was previously allocated\&. This is intended for debugging and will impact performance negatively\&. This option is disabled by default\&. +.RE +.PP +opt\&.utrace (\fBbool\fR) r\- [\fB\-\-enable\-utrace\fR] +.RS 4 +Allocation tracing based on +\fButrace\fR(2) +enabled/disabled\&. This option is disabled by default\&. +.RE +.PP +opt\&.xmalloc (\fBbool\fR) r\- [\fB\-\-enable\-xmalloc\fR] +.RS 4 +Abort\-on\-out\-of\-memory enabled/disabled\&. If enabled, rather than returning failure for any allocation function, display a diagnostic message on +\fBSTDERR_FILENO\fR +and cause the program to drop core (using +\fBabort\fR(3))\&. If an application is designed to depend on this behavior, set the option at compile time by including the following in the source code: +.sp +.if n \{\ +.RS 4 +.\} +.nf +malloc_conf = "xmalloc:true"; +.fi +.if n \{\ +.RE +.\} +.sp +This option is disabled by default\&. +.RE +.PP +opt\&.tcache (\fBbool\fR) r\- +.RS 4 +Thread\-specific caching (tcache) enabled/disabled\&. When there are multiple threads, each thread uses a tcache for objects up to a certain size\&. Thread\-specific caching allows many allocations to be satisfied without performing any thread synchronization, at the cost of increased memory use\&. See the +opt\&.lg_tcache_max +option for related tuning information\&. This option is enabled by default\&. +.RE +.PP +opt\&.lg_tcache_max (\fBsize_t\fR) r\- +.RS 4 +Maximum size class (log base 2) to cache in the thread\-specific cache (tcache)\&. At a minimum, all small size classes are cached, and at a maximum all large size classes are cached\&. The default maximum is 32 KiB (2^15)\&. +.RE +.PP +opt\&.thp (\fBconst char *\fR) r\- +.RS 4 +Transparent hugepage (THP) mode\&. Settings "always", "never" and "default" are available if THP is supported by the operating system\&. The "always" setting enables transparent hugepage for all user memory mappings with +\fI\fBMADV_HUGEPAGE\fR\fR; "never" ensures no transparent hugepage with +\fI\fBMADV_NOHUGEPAGE\fR\fR; the default setting "default" makes no changes\&. Note that: this option does not affect THP for jemalloc internal metadata (see +opt\&.metadata_thp); in addition, for arenas with customized +extent_hooks, this option is bypassed as it is implemented as part of the default extent hooks\&. +.RE +.PP +opt\&.prof (\fBbool\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Memory profiling enabled/disabled\&. If enabled, profile memory allocation activity\&. See the +opt\&.prof_active +option for on\-the\-fly activation/deactivation\&. See the +opt\&.lg_prof_sample +option for probabilistic sampling control\&. See the +opt\&.prof_accum +option for control of cumulative sample reporting\&. See the +opt\&.lg_prof_interval +option for information on interval\-triggered profile dumping, the +opt\&.prof_gdump +option for information on high\-water\-triggered profile dumping, and the +opt\&.prof_final +option for final profile dumping\&. Profile output is compatible with the +\fBjeprof\fR +command, which is based on the +\fBpprof\fR +that is developed as part of the +\m[blue]\fBgperftools package\fR\m[]\&\s-2\u[3]\d\s+2\&. See +HEAP PROFILE FORMAT +for heap profile format documentation\&. +.RE +.PP +opt\&.prof_prefix (\fBconst char *\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Filename prefix for profile dumps\&. If the prefix is set to the empty string, no automatic dumps will occur; this is primarily useful for disabling the automatic final heap dump (which also disables leak reporting, if enabled)\&. The default prefix is +jeprof\&. +.RE +.PP +opt\&.prof_active (\fBbool\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Profiling activated/deactivated\&. This is a secondary control mechanism that makes it possible to start the application with profiling enabled (see the +opt\&.prof +option) but inactive, then toggle profiling at any time during program execution with the +prof\&.active +mallctl\&. This option is enabled by default\&. +.RE +.PP +opt\&.prof_thread_active_init (\fBbool\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Initial setting for +thread\&.prof\&.active +in newly created threads\&. The initial setting for newly created threads can also be changed during execution via the +prof\&.thread_active_init +mallctl\&. This option is enabled by default\&. +.RE +.PP +opt\&.lg_prof_sample (\fBsize_t\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Average interval (log base 2) between allocation samples, as measured in bytes of allocation activity\&. Increasing the sampling interval decreases profile fidelity, but also decreases the computational overhead\&. The default sample interval is 512 KiB (2^19 B)\&. +.RE +.PP +opt\&.prof_accum (\fBbool\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Reporting of cumulative object/byte counts in profile dumps enabled/disabled\&. If this option is enabled, every unique backtrace must be stored for the duration of execution\&. Depending on the application, this can impose a large memory overhead, and the cumulative counts are not always of interest\&. This option is disabled by default\&. +.RE +.PP +opt\&.lg_prof_interval (\fBssize_t\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Average interval (log base 2) between memory profile dumps, as measured in bytes of allocation activity\&. The actual interval between dumps may be sporadic because decentralized allocation counters are used to avoid synchronization bottlenecks\&. Profiles are dumped to files named according to the pattern +<prefix>\&.<pid>\&.<seq>\&.i<iseq>\&.heap, where +<prefix> +is controlled by the +opt\&.prof_prefix +option\&. By default, interval\-triggered profile dumping is disabled (encoded as \-1)\&. +.RE +.PP +opt\&.prof_gdump (\fBbool\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Set the initial state of +prof\&.gdump, which when enabled triggers a memory profile dump every time the total virtual memory exceeds the previous maximum\&. This option is disabled by default\&. +.RE +.PP +opt\&.prof_final (\fBbool\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Use an +\fBatexit\fR(3) +function to dump final memory usage to a file named according to the pattern +<prefix>\&.<pid>\&.<seq>\&.f\&.heap, where +<prefix> +is controlled by the +opt\&.prof_prefix +option\&. Note that +atexit() +may allocate memory during application initialization and then deadlock internally when jemalloc in turn calls +atexit(), so this option is not universally usable (though the application can register its own +atexit() +function with equivalent functionality)\&. This option is disabled by default\&. +.RE +.PP +opt\&.prof_leak (\fBbool\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Leak reporting enabled/disabled\&. If enabled, use an +\fBatexit\fR(3) +function to report memory leaks detected by allocation sampling\&. See the +opt\&.prof +option for information on analyzing heap profile output\&. This option is disabled by default\&. +.RE +.PP +thread\&.arena (\fBunsigned\fR) rw +.RS 4 +Get or set the arena associated with the calling thread\&. If the specified arena was not initialized beforehand (see the +arena\&.i\&.initialized +mallctl), it will be automatically initialized as a side effect of calling this interface\&. +.RE +.PP +thread\&.allocated (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Get the total number of bytes ever allocated by the calling thread\&. This counter has the potential to wrap around; it is up to the application to appropriately interpret the counter in such cases\&. +.RE +.PP +thread\&.allocatedp (\fBuint64_t *\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Get a pointer to the the value that is returned by the +thread\&.allocated +mallctl\&. This is useful for avoiding the overhead of repeated +mallctl*() +calls\&. +.RE +.PP +thread\&.deallocated (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Get the total number of bytes ever deallocated by the calling thread\&. This counter has the potential to wrap around; it is up to the application to appropriately interpret the counter in such cases\&. +.RE +.PP +thread\&.deallocatedp (\fBuint64_t *\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Get a pointer to the the value that is returned by the +thread\&.deallocated +mallctl\&. This is useful for avoiding the overhead of repeated +mallctl*() +calls\&. +.RE +.PP +thread\&.tcache\&.enabled (\fBbool\fR) rw +.RS 4 +Enable/disable calling thread\*(Aqs tcache\&. The tcache is implicitly flushed as a side effect of becoming disabled (see +thread\&.tcache\&.flush)\&. +.RE +.PP +thread\&.tcache\&.flush (\fBvoid\fR) \-\- +.RS 4 +Flush calling thread\*(Aqs thread\-specific cache (tcache)\&. This interface releases all cached objects and internal data structures associated with the calling thread\*(Aqs tcache\&. Ordinarily, this interface need not be called, since automatic periodic incremental garbage collection occurs, and the thread cache is automatically discarded when a thread exits\&. However, garbage collection is triggered by allocation activity, so it is possible for a thread that stops allocating/deallocating to retain its cache indefinitely, in which case the developer may find manual flushing useful\&. +.RE +.PP +thread\&.prof\&.name (\fBconst char *\fR) r\- or \-w [\fB\-\-enable\-prof\fR] +.RS 4 +Get/set the descriptive name associated with the calling thread in memory profile dumps\&. An internal copy of the name string is created, so the input string need not be maintained after this interface completes execution\&. The output string of this interface should be copied for non\-ephemeral uses, because multiple implementation details can cause asynchronous string deallocation\&. Furthermore, each invocation of this interface can only read or write; simultaneous read/write is not supported due to string lifetime limitations\&. The name string must be nil\-terminated and comprised only of characters in the sets recognized by +\fBisgraph\fR(3) +and +\fBisblank\fR(3)\&. +.RE +.PP +thread\&.prof\&.active (\fBbool\fR) rw [\fB\-\-enable\-prof\fR] +.RS 4 +Control whether sampling is currently active for the calling thread\&. This is an activation mechanism in addition to +prof\&.active; both must be active for the calling thread to sample\&. This flag is enabled by default\&. +.RE +.PP +tcache\&.create (\fBunsigned\fR) r\- +.RS 4 +Create an explicit thread\-specific cache (tcache) and return an identifier that can be passed to the +\fBMALLOCX_TCACHE(\fR\fB\fItc\fR\fR\fB)\fR +macro to explicitly use the specified cache rather than the automatically managed one that is used by default\&. Each explicit cache can be used by only one thread at a time; the application must assure that this constraint holds\&. +.RE +.PP +tcache\&.flush (\fBunsigned\fR) \-w +.RS 4 +Flush the specified thread\-specific cache (tcache)\&. The same considerations apply to this interface as to +thread\&.tcache\&.flush, except that the tcache will never be automatically discarded\&. +.RE +.PP +tcache\&.destroy (\fBunsigned\fR) \-w +.RS 4 +Flush the specified thread\-specific cache (tcache) and make the identifier available for use during a future tcache creation\&. +.RE +.PP +arena\&.<i>\&.initialized (\fBbool\fR) r\- +.RS 4 +Get whether the specified arena\*(Aqs statistics are initialized (i\&.e\&. the arena was initialized prior to the current epoch)\&. This interface can also be nominally used to query whether the merged statistics corresponding to +\fBMALLCTL_ARENAS_ALL\fR +are initialized (always true)\&. +.RE +.PP +arena\&.<i>\&.decay (\fBvoid\fR) \-\- +.RS 4 +Trigger decay\-based purging of unused dirty/muzzy pages for arena <i>, or for all arenas if <i> equals +\fBMALLCTL_ARENAS_ALL\fR\&. The proportion of unused dirty/muzzy pages to be purged depends on the current time; see +opt\&.dirty_decay_ms +and +opt\&.muzy_decay_ms +for details\&. +.RE +.PP +arena\&.<i>\&.purge (\fBvoid\fR) \-\- +.RS 4 +Purge all unused dirty pages for arena <i>, or for all arenas if <i> equals +\fBMALLCTL_ARENAS_ALL\fR\&. +.RE +.PP +arena\&.<i>\&.reset (\fBvoid\fR) \-\- +.RS 4 +Discard all of the arena\*(Aqs extant allocations\&. This interface can only be used with arenas explicitly created via +arenas\&.create\&. None of the arena\*(Aqs discarded/cached allocations may accessed afterward\&. As part of this requirement, all thread caches which were used to allocate/deallocate in conjunction with the arena must be flushed beforehand\&. +.RE +.PP +arena\&.<i>\&.destroy (\fBvoid\fR) \-\- +.RS 4 +Destroy the arena\&. Discard all of the arena\*(Aqs extant allocations using the same mechanism as for +arena\&.<i>\&.reset +(with all the same constraints and side effects), merge the arena stats into those accessible at arena index +\fBMALLCTL_ARENAS_DESTROYED\fR, and then completely discard all metadata associated with the arena\&. Future calls to +arenas\&.create +may recycle the arena index\&. Destruction will fail if any threads are currently associated with the arena as a result of calls to +thread\&.arena\&. +.RE +.PP +arena\&.<i>\&.dss (\fBconst char *\fR) rw +.RS 4 +Set the precedence of dss allocation as related to mmap allocation for arena <i>, or for all arenas if <i> equals +\fBMALLCTL_ARENAS_ALL\fR\&. See +opt\&.dss +for supported settings\&. +.RE +.PP +arena\&.<i>\&.dirty_decay_ms (\fBssize_t\fR) rw +.RS 4 +Current per\-arena approximate time in milliseconds from the creation of a set of unused dirty pages until an equivalent set of unused dirty pages is purged and/or reused\&. Each time this interface is set, all currently unused dirty pages are considered to have fully decayed, which causes immediate purging of all unused dirty pages unless the decay time is set to \-1 (i\&.e\&. purging disabled)\&. See +opt\&.dirty_decay_ms +for additional information\&. +.RE +.PP +arena\&.<i>\&.muzzy_decay_ms (\fBssize_t\fR) rw +.RS 4 +Current per\-arena approximate time in milliseconds from the creation of a set of unused muzzy pages until an equivalent set of unused muzzy pages is purged and/or reused\&. Each time this interface is set, all currently unused muzzy pages are considered to have fully decayed, which causes immediate purging of all unused muzzy pages unless the decay time is set to \-1 (i\&.e\&. purging disabled)\&. See +opt\&.muzzy_decay_ms +for additional information\&. +.RE +.PP +arena\&.<i>\&.retain_grow_limit (\fBsize_t\fR) rw +.RS 4 +Maximum size to grow retained region (only relevant when +opt\&.retain +is enabled)\&. This controls the maximum increment to expand virtual memory, or allocation through +arena\&.<i>extent_hooks\&. In particular, if customized extent hooks reserve physical memory (e\&.g\&. 1G huge pages), this is useful to control the allocation hook\*(Aqs input size\&. The default is no limit\&. +.RE +.PP +arena\&.<i>\&.extent_hooks (\fBextent_hooks_t *\fR) rw +.RS 4 +Get or set the extent management hook functions for arena <i>\&. The functions must be capable of operating on all extant extents associated with arena <i>, usually by passing unknown extents to the replaced functions\&. In practice, it is feasible to control allocation for arenas explicitly created via +arenas\&.create +such that all extents originate from an application\-supplied extent allocator (by specifying the custom extent hook functions during arena creation)\&. However, the API guarantees for the automatically created arenas may be relaxed \-\- hooks set there may be called in a "best effort" fashion; in addition there may be extents created prior to the application having an opportunity to take over extent allocation\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +typedef extent_hooks_s extent_hooks_t; +struct extent_hooks_s { + extent_alloc_t *alloc; + extent_dalloc_t *dalloc; + extent_destroy_t *destroy; + extent_commit_t *commit; + extent_decommit_t *decommit; + extent_purge_t *purge_lazy; + extent_purge_t *purge_forced; + extent_split_t *split; + extent_merge_t *merge; +}; +.fi +.if n \{\ +.RE +.\} +.sp +The +\fBextent_hooks_t\fR +structure comprises function pointers which are described individually below\&. jemalloc uses these functions to manage extent lifetime, which starts off with allocation of mapped committed memory, in the simplest case followed by deallocation\&. However, there are performance and platform reasons to retain extents for later reuse\&. Cleanup attempts cascade from deallocation to decommit to forced purging to lazy purging, which gives the extent management functions opportunities to reject the most permanent cleanup operations in favor of less permanent (and often less costly) operations\&. All operations except allocation can be universally opted out of by setting the hook pointers to +\fBNULL\fR, or selectively opted out of by returning failure\&. Note that once the extent hook is set, the structure is accessed directly by the associated arenas, so it must remain valid for the entire lifetime of the arenas\&. +.HP \w'typedef\ void\ *(extent_alloc_t)('u +.BI "typedef void *(extent_alloc_t)(extent_hooks_t\ *" "extent_hooks" ", void\ *" "new_addr" ", size_t\ " "size" ", size_t\ " "alignment" ", bool\ *" "zero" ", bool\ *" "commit" ", unsigned\ " "arena_ind" ");" +.sp +.if n \{\ +.RS 4 +.\} +.nf +.fi +.if n \{\ +.RE +.\} +.sp +An extent allocation function conforms to the +\fBextent_alloc_t\fR +type and upon success returns a pointer to +\fIsize\fR +bytes of mapped memory on behalf of arena +\fIarena_ind\fR +such that the extent\*(Aqs base address is a multiple of +\fIalignment\fR, as well as setting +\fI*zero\fR +to indicate whether the extent is zeroed and +\fI*commit\fR +to indicate whether the extent is committed\&. Upon error the function returns +\fBNULL\fR +and leaves +\fI*zero\fR +and +\fI*commit\fR +unmodified\&. The +\fIsize\fR +parameter is always a multiple of the page size\&. The +\fIalignment\fR +parameter is always a power of two at least as large as the page size\&. Zeroing is mandatory if +\fI*zero\fR +is true upon function entry\&. Committing is mandatory if +\fI*commit\fR +is true upon function entry\&. If +\fInew_addr\fR +is not +\fBNULL\fR, the returned pointer must be +\fInew_addr\fR +on success or +\fBNULL\fR +on error\&. Committed memory may be committed in absolute terms as on a system that does not overcommit, or in implicit terms as on a system that overcommits and satisfies physical memory needs on demand via soft page faults\&. Note that replacing the default extent allocation function makes the arena\*(Aqs +arena\&.<i>\&.dss +setting irrelevant\&. +.HP \w'typedef\ bool\ (extent_dalloc_t)('u +.BI "typedef bool (extent_dalloc_t)(extent_hooks_t\ *" "extent_hooks" ", void\ *" "addr" ", size_t\ " "size" ", bool\ " "committed" ", unsigned\ " "arena_ind" ");" +.sp +.if n \{\ +.RS 4 +.\} +.nf +.fi +.if n \{\ +.RE +.\} +.sp +An extent deallocation function conforms to the +\fBextent_dalloc_t\fR +type and deallocates an extent at given +\fIaddr\fR +and +\fIsize\fR +with +\fIcommitted\fR/decommited memory as indicated, on behalf of arena +\fIarena_ind\fR, returning false upon success\&. If the function returns true, this indicates opt\-out from deallocation; the virtual memory mapping associated with the extent remains mapped, in the same commit state, and available for future use, in which case it will be automatically retained for later reuse\&. +.HP \w'typedef\ void\ (extent_destroy_t)('u +.BI "typedef void (extent_destroy_t)(extent_hooks_t\ *" "extent_hooks" ", void\ *" "addr" ", size_t\ " "size" ", bool\ " "committed" ", unsigned\ " "arena_ind" ");" +.sp +.if n \{\ +.RS 4 +.\} +.nf +.fi +.if n \{\ +.RE +.\} +.sp +An extent destruction function conforms to the +\fBextent_destroy_t\fR +type and unconditionally destroys an extent at given +\fIaddr\fR +and +\fIsize\fR +with +\fIcommitted\fR/decommited memory as indicated, on behalf of arena +\fIarena_ind\fR\&. This function may be called to destroy retained extents during arena destruction (see +arena\&.<i>\&.destroy)\&. +.HP \w'typedef\ bool\ (extent_commit_t)('u +.BI "typedef bool (extent_commit_t)(extent_hooks_t\ *" "extent_hooks" ", void\ *" "addr" ", size_t\ " "size" ", size_t\ " "offset" ", size_t\ " "length" ", unsigned\ " "arena_ind" ");" +.sp +.if n \{\ +.RS 4 +.\} +.nf +.fi +.if n \{\ +.RE +.\} +.sp +An extent commit function conforms to the +\fBextent_commit_t\fR +type and commits zeroed physical memory to back pages within an extent at given +\fIaddr\fR +and +\fIsize\fR +at +\fIoffset\fR +bytes, extending for +\fIlength\fR +on behalf of arena +\fIarena_ind\fR, returning false upon success\&. Committed memory may be committed in absolute terms as on a system that does not overcommit, or in implicit terms as on a system that overcommits and satisfies physical memory needs on demand via soft page faults\&. If the function returns true, this indicates insufficient physical memory to satisfy the request\&. +.HP \w'typedef\ bool\ (extent_decommit_t)('u +.BI "typedef bool (extent_decommit_t)(extent_hooks_t\ *" "extent_hooks" ", void\ *" "addr" ", size_t\ " "size" ", size_t\ " "offset" ", size_t\ " "length" ", unsigned\ " "arena_ind" ");" +.sp +.if n \{\ +.RS 4 +.\} +.nf +.fi +.if n \{\ +.RE +.\} +.sp +An extent decommit function conforms to the +\fBextent_decommit_t\fR +type and decommits any physical memory that is backing pages within an extent at given +\fIaddr\fR +and +\fIsize\fR +at +\fIoffset\fR +bytes, extending for +\fIlength\fR +on behalf of arena +\fIarena_ind\fR, returning false upon success, in which case the pages will be committed via the extent commit function before being reused\&. If the function returns true, this indicates opt\-out from decommit; the memory remains committed and available for future use, in which case it will be automatically retained for later reuse\&. +.HP \w'typedef\ bool\ (extent_purge_t)('u +.BI "typedef bool (extent_purge_t)(extent_hooks_t\ *" "extent_hooks" ", void\ *" "addr" ", size_t\ " "size" ", size_t\ " "offset" ", size_t\ " "length" ", unsigned\ " "arena_ind" ");" +.sp +.if n \{\ +.RS 4 +.\} +.nf +.fi +.if n \{\ +.RE +.\} +.sp +An extent purge function conforms to the +\fBextent_purge_t\fR +type and discards physical pages within the virtual memory mapping associated with an extent at given +\fIaddr\fR +and +\fIsize\fR +at +\fIoffset\fR +bytes, extending for +\fIlength\fR +on behalf of arena +\fIarena_ind\fR\&. A lazy extent purge function (e\&.g\&. implemented via +madvise(\fI\&.\&.\&.\fR\fI\fBMADV_FREE\fR\fR)) can delay purging indefinitely and leave the pages within the purged virtual memory range in an indeterminite state, whereas a forced extent purge function immediately purges, and the pages within the virtual memory range will be zero\-filled the next time they are accessed\&. If the function returns true, this indicates failure to purge\&. +.HP \w'typedef\ bool\ (extent_split_t)('u +.BI "typedef bool (extent_split_t)(extent_hooks_t\ *" "extent_hooks" ", void\ *" "addr" ", size_t\ " "size" ", size_t\ " "size_a" ", size_t\ " "size_b" ", bool\ " "committed" ", unsigned\ " "arena_ind" ");" +.sp +.if n \{\ +.RS 4 +.\} +.nf +.fi +.if n \{\ +.RE +.\} +.sp +An extent split function conforms to the +\fBextent_split_t\fR +type and optionally splits an extent at given +\fIaddr\fR +and +\fIsize\fR +into two adjacent extents, the first of +\fIsize_a\fR +bytes, and the second of +\fIsize_b\fR +bytes, operating on +\fIcommitted\fR/decommitted memory as indicated, on behalf of arena +\fIarena_ind\fR, returning false upon success\&. If the function returns true, this indicates that the extent remains unsplit and therefore should continue to be operated on as a whole\&. +.HP \w'typedef\ bool\ (extent_merge_t)('u +.BI "typedef bool (extent_merge_t)(extent_hooks_t\ *" "extent_hooks" ", void\ *" "addr_a" ", size_t\ " "size_a" ", void\ *" "addr_b" ", size_t\ " "size_b" ", bool\ " "committed" ", unsigned\ " "arena_ind" ");" +.sp +.if n \{\ +.RS 4 +.\} +.nf +.fi +.if n \{\ +.RE +.\} +.sp +An extent merge function conforms to the +\fBextent_merge_t\fR +type and optionally merges adjacent extents, at given +\fIaddr_a\fR +and +\fIsize_a\fR +with given +\fIaddr_b\fR +and +\fIsize_b\fR +into one contiguous extent, operating on +\fIcommitted\fR/decommitted memory as indicated, on behalf of arena +\fIarena_ind\fR, returning false upon success\&. If the function returns true, this indicates that the extents remain distinct mappings and therefore should continue to be operated on independently\&. +.RE +.PP +arenas\&.narenas (\fBunsigned\fR) r\- +.RS 4 +Current limit on number of arenas\&. +.RE +.PP +arenas\&.dirty_decay_ms (\fBssize_t\fR) rw +.RS 4 +Current default per\-arena approximate time in milliseconds from the creation of a set of unused dirty pages until an equivalent set of unused dirty pages is purged and/or reused, used to initialize +arena\&.<i>\&.dirty_decay_ms +during arena creation\&. See +opt\&.dirty_decay_ms +for additional information\&. +.RE +.PP +arenas\&.muzzy_decay_ms (\fBssize_t\fR) rw +.RS 4 +Current default per\-arena approximate time in milliseconds from the creation of a set of unused muzzy pages until an equivalent set of unused muzzy pages is purged and/or reused, used to initialize +arena\&.<i>\&.muzzy_decay_ms +during arena creation\&. See +opt\&.muzzy_decay_ms +for additional information\&. +.RE +.PP +arenas\&.quantum (\fBsize_t\fR) r\- +.RS 4 +Quantum size\&. +.RE +.PP +arenas\&.page (\fBsize_t\fR) r\- +.RS 4 +Page size\&. +.RE +.PP +arenas\&.tcache_max (\fBsize_t\fR) r\- +.RS 4 +Maximum thread\-cached size class\&. +.RE +.PP +arenas\&.nbins (\fBunsigned\fR) r\- +.RS 4 +Number of bin size classes\&. +.RE +.PP +arenas\&.nhbins (\fBunsigned\fR) r\- +.RS 4 +Total number of thread cache bin size classes\&. +.RE +.PP +arenas\&.bin\&.<i>\&.size (\fBsize_t\fR) r\- +.RS 4 +Maximum size supported by size class\&. +.RE +.PP +arenas\&.bin\&.<i>\&.nregs (\fBuint32_t\fR) r\- +.RS 4 +Number of regions per slab\&. +.RE +.PP +arenas\&.bin\&.<i>\&.slab_size (\fBsize_t\fR) r\- +.RS 4 +Number of bytes per slab\&. +.RE +.PP +arenas\&.nlextents (\fBunsigned\fR) r\- +.RS 4 +Total number of large size classes\&. +.RE +.PP +arenas\&.lextent\&.<i>\&.size (\fBsize_t\fR) r\- +.RS 4 +Maximum size supported by this large size class\&. +.RE +.PP +arenas\&.create (\fBunsigned\fR, \fBextent_hooks_t *\fR) rw +.RS 4 +Explicitly create a new arena outside the range of automatically managed arenas, with optionally specified extent hooks, and return the new arena index\&. +.RE +.PP +arenas\&.lookup (\fBunsigned\fR, \fBvoid*\fR) rw +.RS 4 +Index of the arena to which an allocation belongs to\&. +.RE +.PP +prof\&.thread_active_init (\fBbool\fR) rw [\fB\-\-enable\-prof\fR] +.RS 4 +Control the initial setting for +thread\&.prof\&.active +in newly created threads\&. See the +opt\&.prof_thread_active_init +option for additional information\&. +.RE +.PP +prof\&.active (\fBbool\fR) rw [\fB\-\-enable\-prof\fR] +.RS 4 +Control whether sampling is currently active\&. See the +opt\&.prof_active +option for additional information, as well as the interrelated +thread\&.prof\&.active +mallctl\&. +.RE +.PP +prof\&.dump (\fBconst char *\fR) \-w [\fB\-\-enable\-prof\fR] +.RS 4 +Dump a memory profile to the specified file, or if NULL is specified, to a file according to the pattern +<prefix>\&.<pid>\&.<seq>\&.m<mseq>\&.heap, where +<prefix> +is controlled by the +opt\&.prof_prefix +option\&. +.RE +.PP +prof\&.gdump (\fBbool\fR) rw [\fB\-\-enable\-prof\fR] +.RS 4 +When enabled, trigger a memory profile dump every time the total virtual memory exceeds the previous maximum\&. Profiles are dumped to files named according to the pattern +<prefix>\&.<pid>\&.<seq>\&.u<useq>\&.heap, where +<prefix> +is controlled by the +opt\&.prof_prefix +option\&. +.RE +.PP +prof\&.reset (\fBsize_t\fR) \-w [\fB\-\-enable\-prof\fR] +.RS 4 +Reset all memory profile statistics, and optionally update the sample rate (see +opt\&.lg_prof_sample +and +prof\&.lg_sample)\&. +.RE +.PP +prof\&.lg_sample (\fBsize_t\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Get the current sample rate (see +opt\&.lg_prof_sample)\&. +.RE +.PP +prof\&.interval (\fBuint64_t\fR) r\- [\fB\-\-enable\-prof\fR] +.RS 4 +Average number of bytes allocated between interval\-based profile dumps\&. See the +opt\&.lg_prof_interval +option for additional information\&. +.RE +.PP +stats\&.allocated (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Total number of bytes allocated by the application\&. +.RE +.PP +stats\&.active (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Total number of bytes in active pages allocated by the application\&. This is a multiple of the page size, and greater than or equal to +stats\&.allocated\&. This does not include +stats\&.arenas\&.<i>\&.pdirty, +stats\&.arenas\&.<i>\&.pmuzzy, nor pages entirely devoted to allocator metadata\&. +.RE +.PP +stats\&.metadata (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Total number of bytes dedicated to metadata, which comprise base allocations used for bootstrap\-sensitive allocator metadata structures (see +stats\&.arenas\&.<i>\&.base) and internal allocations (see +stats\&.arenas\&.<i>\&.internal)\&. Transparent huge page (enabled with +opt\&.metadata_thp) usage is not considered\&. +.RE +.PP +stats\&.metadata_thp (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of transparent huge pages (THP) used for metadata\&. See +stats\&.metadata +and +opt\&.metadata_thp) for details\&. +.RE +.PP +stats\&.resident (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Maximum number of bytes in physically resident data pages mapped by the allocator, comprising all pages dedicated to allocator metadata, pages backing active allocations, and unused dirty pages\&. This is a maximum rather than precise because pages may not actually be physically resident if they correspond to demand\-zeroed virtual memory that has not yet been touched\&. This is a multiple of the page size, and is larger than +stats\&.active\&. +.RE +.PP +stats\&.mapped (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Total number of bytes in active extents mapped by the allocator\&. This is larger than +stats\&.active\&. This does not include inactive extents, even those that contain unused dirty pages, which means that there is no strict ordering between this and +stats\&.resident\&. +.RE +.PP +stats\&.retained (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Total number of bytes in virtual memory mappings that were retained rather than being returned to the operating system via e\&.g\&. +\fBmunmap\fR(2) +or similar\&. Retained virtual memory is typically untouched, decommitted, or purged, so it has no strongly associated physical memory (see +extent hooks +for details)\&. Retained memory is excluded from mapped memory statistics, e\&.g\&. +stats\&.mapped\&. +.RE +.PP +stats\&.background_thread\&.num_threads (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of +background threads +running currently\&. +.RE +.PP +stats\&.background_thread\&.num_runs (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Total number of runs from all +background threads\&. +.RE +.PP +stats\&.background_thread\&.run_interval (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Average run interval in nanoseconds of +background threads\&. +.RE +.PP +stats\&.mutexes\&.ctl\&.{counter}; (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIctl\fR +mutex (global scope; mallctl related)\&. +{counter} +is one of the counters below: +.PP +.RS 4 +\fInum_ops\fR +(\fBuint64_t\fR): Total number of lock acquisition operations on this mutex\&. +.sp +\fInum_spin_acq\fR +(\fBuint64_t\fR): Number of times the mutex was spin\-acquired\&. When the mutex is currently locked and cannot be acquired immediately, a short period of spin\-retry within jemalloc will be performed\&. Acquired through spin generally means the contention was lightweight and not causing context switches\&. +.sp +\fInum_wait\fR +(\fBuint64_t\fR): Number of times the mutex was wait\-acquired, which means the mutex contention was not solved by spin\-retry, and blocking operation was likely involved in order to acquire the mutex\&. This event generally implies higher cost / longer delay, and should be investigated if it happens often\&. +.sp +\fImax_wait_time\fR +(\fBuint64_t\fR): Maximum length of time in nanoseconds spent on a single wait\-acquired lock operation\&. Note that to avoid profiling overhead on the common path, this does not consider spin\-acquired cases\&. +.sp +\fItotal_wait_time\fR +(\fBuint64_t\fR): Cumulative time in nanoseconds spent on wait\-acquired lock operations\&. Similarly, spin\-acquired cases are not considered\&. +.sp +\fImax_num_thds\fR +(\fBuint32_t\fR): Maximum number of threads waiting on this mutex simultaneously\&. Similarly, spin\-acquired cases are not considered\&. +.sp +\fInum_owner_switch\fR +(\fBuint64_t\fR): Number of times the current mutex owner is different from the previous one\&. This event does not generally imply an issue; rather it is an indicator of how often the protected data are accessed by different threads\&. +.RE +.RE +.PP +stats\&.mutexes\&.background_thread\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIbackground_thread\fR +mutex (global scope; +background_thread +related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP +stats\&.mutexes\&.prof\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIprof\fR +mutex (global scope; profiling related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP +stats\&.mutexes\&.reset (\fBvoid\fR) \-\- [\fB\-\-enable\-stats\fR] +.RS 4 +Reset all mutex profile statistics, including global mutexes, arena mutexes and bin mutexes\&. +.RE +.PP +stats\&.arenas\&.<i>\&.dss (\fBconst char *\fR) r\- +.RS 4 +dss (\fBsbrk\fR(2)) allocation precedence as related to +\fBmmap\fR(2) +allocation\&. See +opt\&.dss +for details\&. +.RE +.PP +stats\&.arenas\&.<i>\&.dirty_decay_ms (\fBssize_t\fR) r\- +.RS 4 +Approximate time in milliseconds from the creation of a set of unused dirty pages until an equivalent set of unused dirty pages is purged and/or reused\&. See +opt\&.dirty_decay_ms +for details\&. +.RE +.PP +stats\&.arenas\&.<i>\&.muzzy_decay_ms (\fBssize_t\fR) r\- +.RS 4 +Approximate time in milliseconds from the creation of a set of unused muzzy pages until an equivalent set of unused muzzy pages is purged and/or reused\&. See +opt\&.muzzy_decay_ms +for details\&. +.RE +.PP +stats\&.arenas\&.<i>\&.nthreads (\fBunsigned\fR) r\- +.RS 4 +Number of threads currently assigned to arena\&. +.RE +.PP +stats\&.arenas\&.<i>\&.uptime (\fBuint64_t\fR) r\- +.RS 4 +Time elapsed (in nanoseconds) since the arena was created\&. If <i> equals +\fB0\fR +or +\fBMALLCTL_ARENAS_ALL\fR, this is the uptime since malloc initialization\&. +.RE +.PP +stats\&.arenas\&.<i>\&.pactive (\fBsize_t\fR) r\- +.RS 4 +Number of pages in active extents\&. +.RE +.PP +stats\&.arenas\&.<i>\&.pdirty (\fBsize_t\fR) r\- +.RS 4 +Number of pages within unused extents that are potentially dirty, and for which +madvise() +or similar has not been called\&. See +opt\&.dirty_decay_ms +for a description of dirty pages\&. +.RE +.PP +stats\&.arenas\&.<i>\&.pmuzzy (\fBsize_t\fR) r\- +.RS 4 +Number of pages within unused extents that are muzzy\&. See +opt\&.muzzy_decay_ms +for a description of muzzy pages\&. +.RE +.PP +stats\&.arenas\&.<i>\&.mapped (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of mapped bytes\&. +.RE +.PP +stats\&.arenas\&.<i>\&.retained (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of retained bytes\&. See +stats\&.retained +for details\&. +.RE +.PP +stats\&.arenas\&.<i>\&.extent_avail (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of allocated (but unused) extent structs in this arena\&. +.RE +.PP +stats\&.arenas\&.<i>\&.base (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of bytes dedicated to bootstrap\-sensitive allocator metadata structures\&. +.RE +.PP +stats\&.arenas\&.<i>\&.internal (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of bytes dedicated to internal allocations\&. Internal allocations differ from application\-originated allocations in that they are for internal use, and that they are omitted from heap profiles\&. +.RE +.PP +stats\&.arenas\&.<i>\&.metadata_thp (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of transparent huge pages (THP) used for metadata\&. See +opt\&.metadata_thp +for details\&. +.RE +.PP +stats\&.arenas\&.<i>\&.resident (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Maximum number of bytes in physically resident data pages mapped by the arena, comprising all pages dedicated to allocator metadata, pages backing active allocations, and unused dirty pages\&. This is a maximum rather than precise because pages may not actually be physically resident if they correspond to demand\-zeroed virtual memory that has not yet been touched\&. This is a multiple of the page size\&. +.RE +.PP +stats\&.arenas\&.<i>\&.dirty_npurge (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of dirty page purge sweeps performed\&. +.RE +.PP +stats\&.arenas\&.<i>\&.dirty_nmadvise (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of +madvise() +or similar calls made to purge dirty pages\&. +.RE +.PP +stats\&.arenas\&.<i>\&.dirty_purged (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of dirty pages purged\&. +.RE +.PP +stats\&.arenas\&.<i>\&.muzzy_npurge (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of muzzy page purge sweeps performed\&. +.RE +.PP +stats\&.arenas\&.<i>\&.muzzy_nmadvise (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of +madvise() +or similar calls made to purge muzzy pages\&. +.RE +.PP +stats\&.arenas\&.<i>\&.muzzy_purged (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of muzzy pages purged\&. +.RE +.PP +stats\&.arenas\&.<i>\&.small\&.allocated (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of bytes currently allocated by small objects\&. +.RE +.PP +stats\&.arenas\&.<i>\&.small\&.nmalloc (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of times a small allocation was requested from the arena\*(Aqs bins, whether to fill the relevant tcache if +opt\&.tcache +is enabled, or to directly satisfy an allocation request otherwise\&. +.RE +.PP +stats\&.arenas\&.<i>\&.small\&.ndalloc (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of times a small allocation was returned to the arena\*(Aqs bins, whether to flush the relevant tcache if +opt\&.tcache +is enabled, or to directly deallocate an allocation otherwise\&. +.RE +.PP +stats\&.arenas\&.<i>\&.small\&.nrequests (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of allocation requests satisfied by all bin size classes\&. +.RE +.PP +stats\&.arenas\&.<i>\&.small\&.nfills (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of tcache fills by all small size classes\&. +.RE +.PP +stats\&.arenas\&.<i>\&.small\&.nflushes (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of tcache flushes by all small size classes\&. +.RE +.PP +stats\&.arenas\&.<i>\&.large\&.allocated (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of bytes currently allocated by large objects\&. +.RE +.PP +stats\&.arenas\&.<i>\&.large\&.nmalloc (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of times a large extent was allocated from the arena, whether to fill the relevant tcache if +opt\&.tcache +is enabled and the size class is within the range being cached, or to directly satisfy an allocation request otherwise\&. +.RE +.PP +stats\&.arenas\&.<i>\&.large\&.ndalloc (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of times a large extent was returned to the arena, whether to flush the relevant tcache if +opt\&.tcache +is enabled and the size class is within the range being cached, or to directly deallocate an allocation otherwise\&. +.RE +.PP +stats\&.arenas\&.<i>\&.large\&.nrequests (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of allocation requests satisfied by all large size classes\&. +.RE +.PP +stats\&.arenas\&.<i>\&.large\&.nfills (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of tcache fills by all large size classes\&. +.RE +.PP +stats\&.arenas\&.<i>\&.large\&.nflushes (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of tcache flushes by all large size classes\&. +.RE +.PP +stats\&.arenas\&.<i>\&.bins\&.<j>\&.nmalloc (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of times a bin region of the corresponding size class was allocated from the arena, whether to fill the relevant tcache if +opt\&.tcache +is enabled, or to directly satisfy an allocation request otherwise\&. +.RE +.PP +stats\&.arenas\&.<i>\&.bins\&.<j>\&.ndalloc (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of times a bin region of the corresponding size class was returned to the arena, whether to flush the relevant tcache if +opt\&.tcache +is enabled, or to directly deallocate an allocation otherwise\&. +.RE +.PP +stats\&.arenas\&.<i>\&.bins\&.<j>\&.nrequests (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of allocation requests satisfied by bin regions of the corresponding size class\&. +.RE +.PP +stats\&.arenas\&.<i>\&.bins\&.<j>\&.curregs (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Current number of regions for this size class\&. +.RE +.PP +stats\&.arenas\&.<i>\&.bins\&.<j>\&.nfills (\fBuint64_t\fR) r\- +.RS 4 +Cumulative number of tcache fills\&. +.RE +.PP +stats\&.arenas\&.<i>\&.bins\&.<j>\&.nflushes (\fBuint64_t\fR) r\- +.RS 4 +Cumulative number of tcache flushes\&. +.RE +.PP +stats\&.arenas\&.<i>\&.bins\&.<j>\&.nslabs (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of slabs created\&. +.RE +.PP +stats\&.arenas\&.<i>\&.bins\&.<j>\&.nreslabs (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of times the current slab from which to allocate changed\&. +.RE +.PP +stats\&.arenas\&.<i>\&.bins\&.<j>\&.curslabs (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Current number of slabs\&. +.RE +.PP +stats\&.arenas\&.<i>\&.bins\&.<j>\&.nonfull_slabs (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Current number of nonfull slabs\&. +.RE +.PP +stats\&.arenas\&.<i>\&.bins\&.<j>\&.mutex\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIarena\&.<i>\&.bins\&.<j>\fR +mutex (arena bin scope; bin operation related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP +stats\&.arenas\&.<i>\&.extents\&.<j>\&.n{extent_type} (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Number of extents of the given type in this arena in the bucket corresponding to page size index <j>\&. The extent type is one of dirty, muzzy, or retained\&. +.RE +.PP +stats\&.arenas\&.<i>\&.extents\&.<j>\&.{extent_type}_bytes (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Sum of the bytes managed by extents of the given type in this arena in the bucket corresponding to page size index <j>\&. The extent type is one of dirty, muzzy, or retained\&. +.RE +.PP +stats\&.arenas\&.<i>\&.lextents\&.<j>\&.nmalloc (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of times a large extent of the corresponding size class was allocated from the arena, whether to fill the relevant tcache if +opt\&.tcache +is enabled and the size class is within the range being cached, or to directly satisfy an allocation request otherwise\&. +.RE +.PP +stats\&.arenas\&.<i>\&.lextents\&.<j>\&.ndalloc (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of times a large extent of the corresponding size class was returned to the arena, whether to flush the relevant tcache if +opt\&.tcache +is enabled and the size class is within the range being cached, or to directly deallocate an allocation otherwise\&. +.RE +.PP +stats\&.arenas\&.<i>\&.lextents\&.<j>\&.nrequests (\fBuint64_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Cumulative number of allocation requests satisfied by large extents of the corresponding size class\&. +.RE +.PP +stats\&.arenas\&.<i>\&.lextents\&.<j>\&.curlextents (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Current number of large allocations for this size class\&. +.RE +.PP +stats\&.arenas\&.<i>\&.mutexes\&.large\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIarena\&.<i>\&.large\fR +mutex (arena scope; large allocation related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP +stats\&.arenas\&.<i>\&.mutexes\&.extent_avail\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIarena\&.<i>\&.extent_avail \fR +mutex (arena scope; extent avail related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP +stats\&.arenas\&.<i>\&.mutexes\&.extents_dirty\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIarena\&.<i>\&.extents_dirty \fR +mutex (arena scope; dirty extents related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP +stats\&.arenas\&.<i>\&.mutexes\&.extents_muzzy\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIarena\&.<i>\&.extents_muzzy \fR +mutex (arena scope; muzzy extents related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP +stats\&.arenas\&.<i>\&.mutexes\&.extents_retained\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIarena\&.<i>\&.extents_retained \fR +mutex (arena scope; retained extents related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP +stats\&.arenas\&.<i>\&.mutexes\&.decay_dirty\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIarena\&.<i>\&.decay_dirty \fR +mutex (arena scope; decay for dirty pages related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP +stats\&.arenas\&.<i>\&.mutexes\&.decay_muzzy\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIarena\&.<i>\&.decay_muzzy \fR +mutex (arena scope; decay for muzzy pages related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP +stats\&.arenas\&.<i>\&.mutexes\&.base\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIarena\&.<i>\&.base\fR +mutex (arena scope; base allocator related)\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.PP +stats\&.arenas\&.<i>\&.mutexes\&.tcache_list\&.{counter} (\fBcounter specific type\fR) r\- [\fB\-\-enable\-stats\fR] +.RS 4 +Statistics on +\fIarena\&.<i>\&.tcache_list\fR +mutex (arena scope; tcache to arena association related)\&. This mutex is expected to be accessed less often\&. +{counter} +is one of the counters in +mutex profiling counters\&. +.RE +.SH "HEAP PROFILE FORMAT" +.PP +Although the heap profiling functionality was originally designed to be compatible with the +\fBpprof\fR +command that is developed as part of the +\m[blue]\fBgperftools package\fR\m[]\&\s-2\u[3]\d\s+2, the addition of per thread heap profiling functionality required a different heap profile format\&. The +\fBjeprof\fR +command is derived from +\fBpprof\fR, with enhancements to support the heap profile format described here\&. +.PP +In the following hypothetical heap profile, +\fB[\&.\&.\&.]\fR +indicates elision for the sake of compactness\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +heap_v2/524288 + t*: 28106: 56637512 [0: 0] + [\&.\&.\&.] + t3: 352: 16777344 [0: 0] + [\&.\&.\&.] + t99: 17754: 29341640 [0: 0] + [\&.\&.\&.] +@ 0x5f86da8 0x5f5a1dc [\&.\&.\&.] 0x29e4d4e 0xa200316 0xabb2988 [\&.\&.\&.] + t*: 13: 6688 [0: 0] + t3: 12: 6496 [0: ] + t99: 1: 192 [0: 0] +[\&.\&.\&.] + +MAPPED_LIBRARIES: +[\&.\&.\&.] +.fi +.if n \{\ +.RE +.\} +.sp +The following matches the above heap profile, but most tokens are replaced with +\fB<description>\fR +to indicate descriptions of the corresponding fields\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +<heap_profile_format_version>/<mean_sample_interval> + <aggregate>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>] + [\&.\&.\&.] + <thread_3_aggregate>: <curobjs>: <curbytes>[<cumobjs>: <cumbytes>] + [\&.\&.\&.] + <thread_99_aggregate>: <curobjs>: <curbytes>[<cumobjs>: <cumbytes>] + [\&.\&.\&.] +@ <top_frame> <frame> [\&.\&.\&.] <frame> <frame> <frame> [\&.\&.\&.] + <backtrace_aggregate>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>] + <backtrace_thread_3>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>] + <backtrace_thread_99>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>] +[\&.\&.\&.] + +MAPPED_LIBRARIES: +</proc/<pid>/maps> +.fi +.if n \{\ +.RE +.\} +.SH "DEBUGGING MALLOC PROBLEMS" +.PP +When debugging, it is a good idea to configure/build jemalloc with the +\fB\-\-enable\-debug\fR +and +\fB\-\-enable\-fill\fR +options, and recompile the program with suitable options and symbols for debugger support\&. When so configured, jemalloc incorporates a wide variety of run\-time assertions that catch application errors such as double\-free, write\-after\-free, etc\&. +.PP +Programs often accidentally depend on +\(lquninitialized\(rq +memory actually being filled with zero bytes\&. Junk filling (see the +opt\&.junk +option) tends to expose such bugs in the form of obviously incorrect results and/or coredumps\&. Conversely, zero filling (see the +opt\&.zero +option) eliminates the symptoms of such bugs\&. Between these two options, it is usually possible to quickly detect, diagnose, and eliminate such bugs\&. +.PP +This implementation does not provide much detail about the problems it detects, because the performance impact for storing such information would be prohibitive\&. +.SH "DIAGNOSTIC MESSAGES" +.PP +If any of the memory allocation/deallocation functions detect an error or warning condition, a message will be printed to file descriptor +\fBSTDERR_FILENO\fR\&. Errors will result in the process dumping core\&. If the +opt\&.abort +option is set, most warnings are treated as errors\&. +.PP +The +\fImalloc_message\fR +variable allows the programmer to override the function which emits the text strings forming the errors and warnings if for some reason the +\fBSTDERR_FILENO\fR +file descriptor is not suitable for this\&. +malloc_message() +takes the +\fIcbopaque\fR +pointer argument that is +\fBNULL\fR +unless overridden by the arguments in a call to +malloc_stats_print(), followed by a string pointer\&. Please note that doing anything which tries to allocate memory in this function is likely to result in a crash or deadlock\&. +.PP +All messages are prefixed by +\(lq<jemalloc>: \(rq\&. +.SH "RETURN VALUES" +.SS "Standard API" +.PP +The +malloc() +and +calloc() +functions return a pointer to the allocated memory if successful; otherwise a +\fBNULL\fR +pointer is returned and +\fIerrno\fR +is set to +ENOMEM\&. +.PP +The +posix_memalign() +function returns the value 0 if successful; otherwise it returns an error value\&. The +posix_memalign() +function will fail if: +.PP +EINVAL +.RS 4 +The +\fIalignment\fR +parameter is not a power of 2 at least as large as +sizeof(\fBvoid *\fR)\&. +.RE +.PP +ENOMEM +.RS 4 +Memory allocation error\&. +.RE +.PP +The +aligned_alloc() +function returns a pointer to the allocated memory if successful; otherwise a +\fBNULL\fR +pointer is returned and +\fIerrno\fR +is set\&. The +aligned_alloc() +function will fail if: +.PP +EINVAL +.RS 4 +The +\fIalignment\fR +parameter is not a power of 2\&. +.RE +.PP +ENOMEM +.RS 4 +Memory allocation error\&. +.RE +.PP +The +realloc() +function returns a pointer, possibly identical to +\fIptr\fR, to the allocated memory if successful; otherwise a +\fBNULL\fR +pointer is returned, and +\fIerrno\fR +is set to +ENOMEM +if the error was the result of an allocation failure\&. The +realloc() +function always leaves the original buffer intact when an error occurs\&. +.PP +The +free() +function returns no value\&. +.SS "Non\-standard API" +.PP +The +mallocx() +and +rallocx() +functions return a pointer to the allocated memory if successful; otherwise a +\fBNULL\fR +pointer is returned to indicate insufficient contiguous memory was available to service the allocation request\&. +.PP +The +xallocx() +function returns the real size of the resulting resized allocation pointed to by +\fIptr\fR, which is a value less than +\fIsize\fR +if the allocation could not be adequately grown in place\&. +.PP +The +sallocx() +function returns the real size of the allocation pointed to by +\fIptr\fR\&. +.PP +The +nallocx() +returns the real size that would result from a successful equivalent +mallocx() +function call, or zero if insufficient memory is available to perform the size computation\&. +.PP +The +mallctl(), +mallctlnametomib(), and +mallctlbymib() +functions return 0 on success; otherwise they return an error value\&. The functions will fail if: +.PP +EINVAL +.RS 4 +\fInewp\fR +is not +\fBNULL\fR, and +\fInewlen\fR +is too large or too small\&. Alternatively, +\fI*oldlenp\fR +is too large or too small; in this case as much data as possible are read despite the error\&. +.RE +.PP +ENOENT +.RS 4 +\fIname\fR +or +\fImib\fR +specifies an unknown/invalid value\&. +.RE +.PP +EPERM +.RS 4 +Attempt to read or write void value, or attempt to write read\-only value\&. +.RE +.PP +EAGAIN +.RS 4 +A memory allocation failure occurred\&. +.RE +.PP +EFAULT +.RS 4 +An interface with side effects failed in some way not directly related to +mallctl*() +read/write processing\&. +.RE +.PP +The +malloc_usable_size() +function returns the usable size of the allocation pointed to by +\fIptr\fR\&. +.SH "ENVIRONMENT" +.PP +The following environment variable affects the execution of the allocation functions: +.PP +\fBMALLOC_CONF\fR +.RS 4 +If the environment variable +\fBMALLOC_CONF\fR +is set, the characters it contains will be interpreted as options\&. +.RE +.SH "EXAMPLES" +.PP +To dump core whenever a problem occurs: +.sp +.if n \{\ +.RS 4 +.\} +.nf +ln \-s \*(Aqabort:true\*(Aq /etc/malloc\&.conf +.fi +.if n \{\ +.RE +.\} +.PP +To specify in the source that only one arena should be automatically created: +.sp +.if n \{\ +.RS 4 +.\} +.nf +malloc_conf = "narenas:1"; +.fi +.if n \{\ +.RE +.\} +.SH "SEE ALSO" +.PP +\fBmadvise\fR(2), +\fBmmap\fR(2), +\fBsbrk\fR(2), +\fButrace\fR(2), +\fBalloca\fR(3), +\fBatexit\fR(3), +\fBgetpagesize\fR(3) +.SH "STANDARDS" +.PP +The +malloc(), +calloc(), +realloc(), and +free() +functions conform to ISO/IEC 9899:1990 (\(lqISO C90\(rq)\&. +.PP +The +posix_memalign() +function conforms to IEEE Std 1003\&.1\-2001 (\(lqPOSIX\&.1\(rq)\&. +.SH "HISTORY" +.PP +The +malloc_usable_size() +and +posix_memalign() +functions first appeared in FreeBSD 7\&.0\&. +.PP +The +aligned_alloc(), +malloc_stats_print(), and +mallctl*() +functions first appeared in FreeBSD 10\&.0\&. +.PP +The +*allocx() +functions first appeared in FreeBSD 11\&.0\&. +.SH "AUTHOR" +.PP +\fBJason Evans\fR +.RS 4 +.RE +.SH "NOTES" +.IP " 1." 4 +jemalloc website +.RS 4 +\%http://jemalloc.net/ +.RE +.IP " 2." 4 +JSON format +.RS 4 +\%http://www.json.org/ +.RE +.IP " 3." 4 +gperftools package +.RS 4 +\%http://code.google.com/p/gperftools/ +.RE diff --git a/lib/libc/stdlib/memory.3 b/lib/libc/stdlib/memory.3 new file mode 100644 index 000000000000..b7703cf44bd5 --- /dev/null +++ b/lib/libc/stdlib/memory.3 @@ -0,0 +1,103 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. 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. +.\" 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. +.\" +.Dd October 18, 2023 +.Dt MEMORY 3 +.Os +.Sh NAME +.Nm aligned_alloc , +.Nm alloca , +.Nm calloc , +.Nm free , +.Nm malloc , +.Nm posix_memalign , +.Nm realloc , +.Nm reallocf , +.Nm valloc , +.Nm mmap , +.Nm munmap +.Nd memory management functions +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft void * +.Fn aligned_alloc "size_t alignment" "size_t size" +.Ft void * +.Fn alloca "size_t size" +.Ft void * +.Fn calloc "size_t nelem" "size_t elsize" +.Ft void +.Fn free "void *ptr" +.Ft void * +.Fn malloc "size_t size" +.Ft int +.Fn posix_memalign "void **ptr" "size_t alignment" "size_t size" +.Ft void * +.Fn realloc "void *ptr" "size_t size" +.Ft void * +.Fn reallocf "void *ptr" "size_t size" +.Ft void * +.Fn valloc "size_t size" +.In sys/types.h +.In sys/mman.h +.Ft void * +.Fn mmap "void * addr" "size_t len" "int prot" "int flags" "int fd" "off_t offset" +.Ft int +.Fn munmap "void *addr" "size_t len" +.Sh DESCRIPTION +These functions allocate and free memory for the calling process. +They are described in the +individual manual pages. +.Sh SEE ALSO +.Xr mmap 2 , +.Xr aligned_alloc 3 , +.Xr alloca 3 , +.Xr calloc 3 , +.Xr free 3 , +.Xr malloc 3 , +.Xr posix_memalign 3 , +.Xr realloc 3 , +.Xr reallocf 3 , +.Xr valloc 3 +.Sh STANDARDS +The +.Fn calloc , +.Fn free , +.Fn malloc , +and +.Fn realloc +functions conform to +.St -isoC . +.Pp +The +.Fn mmap , +.Fn munmap , +and +.Fn posix_memalign +functions conform to +.St -p1003.1-2001 . diff --git a/lib/libc/stdlib/merge.c b/lib/libc/stdlib/merge.c new file mode 100644 index 000000000000..e70938088589 --- /dev/null +++ b/lib/libc/stdlib/merge.c @@ -0,0 +1,349 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Peter McIlroy. + * + * 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. + */ + +/* + * Hybrid exponential search/linear search merge sort with hybrid + * natural/pairwise first pass. Requires about .3% more comparisons + * for random data than LSMS with pairwise first pass alone. + * It works for objects as small as two bytes. + */ + +#define NATURAL +#define THRESHOLD 16 /* Best choice for natural merge cut-off. */ + +/* #define NATURAL to get hybrid natural merge. + * (The default is pairwise merging.) + */ + +#include <sys/param.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#ifdef I_AM_MERGESORT_B +#include "block_abi.h" +#define DECLARE_CMP DECLARE_BLOCK(int, cmp, const void *, const void *) +typedef DECLARE_BLOCK(int, cmp_t, const void *, const void *); +#define CMP(x, y) CALL_BLOCK(cmp, x, y) +#else +typedef int (*cmp_t)(const void *, const void *); +#define CMP(x, y) cmp(x, y) +#endif + +static void setup(u_char *, u_char *, size_t, size_t, cmp_t); +static void insertionsort(u_char *, size_t, size_t, cmp_t); + +#define ISIZE sizeof(int) +#define PSIZE sizeof(u_char *) +#define ICOPY_LIST(src, dst, last) \ + do \ + *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \ + while(src < last) +#define ICOPY_ELT(src, dst, i) \ + do \ + *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \ + while (i -= ISIZE) + +#define CCOPY_LIST(src, dst, last) \ + do \ + *dst++ = *src++; \ + while (src < last) +#define CCOPY_ELT(src, dst, i) \ + do \ + *dst++ = *src++; \ + while (i -= 1) + +/* + * Find the next possible pointer head. (Trickery for forcing an array + * to do double duty as a linked list when objects do not align with word + * boundaries. + */ +/* Assumption: PSIZE is a power of 2. */ +#define EVAL(p) (u_char **)roundup2((uintptr_t)p, PSIZE) + +#ifdef I_AM_MERGESORT_B +int mergesort_b(void *, size_t, size_t, cmp_t); +#else +int mergesort(void *, size_t, size_t, cmp_t); +#endif + +/* + * Arguments are as for qsort. + */ +int +#ifdef I_AM_MERGESORT_B +mergesort_b(void *base, size_t nmemb, size_t size, cmp_t cmp) +#else +mergesort(void *base, size_t nmemb, size_t size, cmp_t cmp) +#endif +{ + size_t i; + int sense; + int big, iflag; + u_char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2; + u_char *list2, *list1, *p2, *p, *last, **p1; + + if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */ + errno = EINVAL; + return (-1); + } + + if (nmemb == 0) + return (0); + + iflag = 0; + if (__is_aligned(size, ISIZE) && __is_aligned(base, ISIZE)) + iflag = 1; + + if ((list2 = malloc(nmemb * size + PSIZE)) == NULL) + return (-1); + + list1 = base; + setup(list1, list2, nmemb, size, cmp); + last = list2 + nmemb * size; + i = big = 0; + while (*EVAL(list2) != last) { + l2 = list1; + p1 = EVAL(list1); + for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) { + p2 = *EVAL(p2); + f1 = l2; + f2 = l1 = list1 + (p2 - list2); + if (p2 != last) + p2 = *EVAL(p2); + l2 = list1 + (p2 - list2); + while (f1 < l1 && f2 < l2) { + if (CMP(f1, f2) <= 0) { + q = f2; + b = f1, t = l1; + sense = -1; + } else { + q = f1; + b = f2, t = l2; + sense = 0; + } + if (!big) { /* here i = 0 */ + while ((b += size) < t && CMP(q, b) >sense) + if (++i == 6) { + big = 1; + goto EXPONENTIAL; + } + } else { +EXPONENTIAL: for (i = size; ; i <<= 1) + if ((p = (b + i)) >= t) { + if ((p = t - size) > b && + CMP(q, p) <= sense) + t = p; + else + b = p; + break; + } else if (CMP(q, p) <= sense) { + t = p; + if (i == size) + big = 0; + goto FASTCASE; + } else + b = p; + while (t > b+size) { + i = (((t - b) / size) >> 1) * size; + if (CMP(q, p = b + i) <= sense) + t = p; + else + b = p; + } + goto COPY; +FASTCASE: while (i > size) + if (CMP(q, + p = b + (i >>= 1)) <= sense) + t = p; + else + b = p; +COPY: b = t; + } + i = size; + if (q == f1) { + if (iflag) { + ICOPY_LIST(f2, tp2, b); + ICOPY_ELT(f1, tp2, i); + } else { + CCOPY_LIST(f2, tp2, b); + CCOPY_ELT(f1, tp2, i); + } + } else { + if (iflag) { + ICOPY_LIST(f1, tp2, b); + ICOPY_ELT(f2, tp2, i); + } else { + CCOPY_LIST(f1, tp2, b); + CCOPY_ELT(f2, tp2, i); + } + } + } + if (f2 < l2) { + if (iflag) + ICOPY_LIST(f2, tp2, l2); + else + CCOPY_LIST(f2, tp2, l2); + } else if (f1 < l1) { + if (iflag) + ICOPY_LIST(f1, tp2, l1); + else + CCOPY_LIST(f1, tp2, l1); + } + *p1 = l2; + } + tp2 = list1; /* swap list1, list2 */ + list1 = list2; + list2 = tp2; + last = list2 + nmemb*size; + } + if (base == list2) { + memmove(list2, list1, nmemb*size); + list2 = list1; + } + free(list2); + return (0); +} + +#define swap(a, b) { \ + s = b; \ + i = size; \ + do { \ + tmp = *a; *a++ = *s; *s++ = tmp; \ + } while (--i); \ + a -= size; \ + } +#define reverse(bot, top) { \ + s = top; \ + do { \ + i = size; \ + do { \ + tmp = *bot; *bot++ = *s; *s++ = tmp; \ + } while (--i); \ + s -= size2; \ + } while(bot < s); \ +} + +/* + * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of + * increasing order, list2 in a corresponding linked list. Checks for runs + * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL + * is defined. Otherwise simple pairwise merging is used.) + */ +void +setup(u_char *list1, u_char *list2, size_t n, size_t size, cmp_t cmp) +{ + int i, length, size2, tmp, sense; + u_char *f1, *f2, *s, *l2, *last, *p2; + + size2 = size*2; + if (n <= 5) { + insertionsort(list1, n, size, cmp); + *EVAL(list2) = (u_char*) list2 + n*size; + return; + } + /* + * Avoid running pointers out of bounds; limit n to evens + * for simplicity. + */ + i = 4 + (n & 1); + insertionsort(list1 + (n - i) * size, i, size, cmp); + last = list1 + size * (n - i); + *EVAL(list2 + (last - list1)) = list2 + n * size; + +#ifdef NATURAL + p2 = list2; + f1 = list1; + sense = (CMP(f1, f1 + size) > 0); + for (; f1 < last; sense = !sense) { + length = 2; + /* Find pairs with same sense. */ + for (f2 = f1 + size2; f2 < last; f2 += size2) { + if ((CMP(f2, f2+ size) > 0) != sense) + break; + length += 2; + } + if (length < THRESHOLD) { /* Pairwise merge */ + do { + p2 = *EVAL(p2) = f1 + size2 - list1 + list2; + if (sense > 0) + swap (f1, f1 + size); + } while ((f1 += size2) < f2); + } else { /* Natural merge */ + l2 = f2; + for (f2 = f1 + size2; f2 < l2; f2 += size2) { + if ((CMP(f2-size, f2) > 0) != sense) { + p2 = *EVAL(p2) = f2 - list1 + list2; + if (sense > 0) + reverse(f1, f2-size); + f1 = f2; + } + } + if (sense > 0) + reverse (f1, f2-size); + f1 = f2; + if (f2 < last || CMP(f2 - size, f2) > 0) + p2 = *EVAL(p2) = f2 - list1 + list2; + else + p2 = *EVAL(p2) = list2 + n*size; + } + } +#else /* pairwise merge only. */ + for (f1 = list1, p2 = list2; f1 < last; f1 += size2) { + p2 = *EVAL(p2) = p2 + size2; + if (CMP (f1, f1 + size) > 0) + swap(f1, f1 + size); + } +#endif /* NATURAL */ +} + +/* + * This is to avoid out-of-bounds addresses in sorting the + * last 4 elements. + */ +static void +insertionsort(u_char *a, size_t n, size_t size, cmp_t cmp) +{ + u_char *ai, *s, *t, *u, tmp; + int i; + + for (ai = a+size; --n >= 1; ai += size) + for (t = ai; t > a; t -= size) { + u = t - size; + if (CMP(u, t) <= 0) + break; + swap(u, t); + } +} diff --git a/lib/libc/stdlib/mergesort_b.c b/lib/libc/stdlib/mergesort_b.c new file mode 100644 index 000000000000..0b9582b37d65 --- /dev/null +++ b/lib/libc/stdlib/mergesort_b.c @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2014 David Chisnall + * 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 AUTHOR 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 AUTHOR 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. + */ +#define I_AM_MERGESORT_B +#include "merge.c" diff --git a/lib/libc/stdlib/ptsname.3 b/lib/libc/stdlib/ptsname.3 new file mode 100644 index 000000000000..df23e9ae6129 --- /dev/null +++ b/lib/libc/stdlib/ptsname.3 @@ -0,0 +1,197 @@ +.\" +.\" Copyright (c) 2002 The FreeBSD Project, Inc. +.\" All rights reserved. +.\" +.\" This software includes code contributed to the FreeBSD Project +.\" by Ryan Younce of North Carolina State University. +.\" +.\" 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 FreeBSD Project 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 FREEBSD PROJECT 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 FREEBSD PROJECT +.\" OR ITS 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. +.\" +.Dd October 14, 2023 +.Dt PTSNAME 3 +.Os +.Sh NAME +.Nm grantpt , +.Nm ptsname , +.Nm ptsname_r , +.Nm unlockpt +.Nd pseudo-terminal access functions +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft int +.Fn grantpt "int fildes" +.Ft "char *" +.Fn ptsname "int fildes" +.Ft "int" +.Fn ptsname_r "int fildes" "char *buffer" "size_t buflen" +.Ft int +.Fn unlockpt "int fildes" +.Sh DESCRIPTION +The +.Fn grantpt , +.Fn ptsname , +and +.Fn unlockpt +functions allow access to pseudo-terminal devices. +These three functions accept a file descriptor that references the +master half of a pseudo-terminal pair. +This file descriptor is created with +.Xr posix_openpt 2 . +.Pp +The +.Fn grantpt +function is used to establish ownership and permissions +of the slave device counterpart to the master device +specified with +.Fa fildes . +The slave device's ownership is set to the real user ID +of the calling process, and the permissions are set to +user readable-writable and group writable. +The group owner of the slave device is also set to the +group +.Dq Li tty . +.Pp +The +.Fn ptsname +function returns the full pathname of the slave device +counterpart to the master device specified with +.Fa fildes . +This value can be used +to subsequently open the appropriate slave after +.Xr posix_openpt 2 +and +.Fn grantpt +have been called. +.Pp +The +.Fn ptsname_r +function is the thread-safe version of +.Fn ptsname . +The caller must provide storage for the results of the full pathname of +the slave device in the +.Fa buffer +and +.Fa bufsize +arguments. +.Pp +The +.Fn unlockpt +function clears the lock held on the pseudo-terminal pair +for the master device specified with +.Fa fildes . +.Sh RETURN VALUES +.Rv -std grantpt unlockpt +.Pp +The +.Fn ptsname +function returns a pointer to the name +of the slave device on success; otherwise a +.Dv NULL +pointer is returned. +.Pp +The +.Fn ptsname_r +function returns the value 0 if successful; +otherwise a nonzero value is returned and the global variable +.Va errno +is set to indicate the error. +Note: +.Fn ptsname_r +was previously documented as returning -1 on error. +In the future it will be changed to return an error number, for POSIX +compatibility. +Therefore, callers should not check for -1. +.Sh ERRORS +The +.Fn grantpt , +.Fn ptsname , +.Fn ptsname_r +and +.Fn unlockpt +functions may fail and set +.Va errno +to: +.Bl -tag -width Er +.It Bq Er EBADF +.Fa fildes +is not a valid open file descriptor. +.It Bq Er EINVAL +.Fa fildes +is not a master pseudo-terminal device. +.El +.Pp +In addition, the +.Fn ptsname_r +function may set +.Va errno +to: +.Bl -tag -width Er +.It Bq Er ERANGE +The buffer was too small. +.El +.Pp +In addition, the +.Fn grantpt +function may set +.Va errno +to: +.Bl -tag -width Er +.It Bq Er EACCES +The slave pseudo-terminal device could not be accessed. +.El +.Sh SEE ALSO +.Xr posix_openpt 2 , +.Xr pts 4 , +.Xr tty 4 +.Sh STANDARDS +The +.Fn ptsname +function conforms to +.St -p1003.1-2008 . +.Pp +This implementation of +.Fn grantpt +and +.Fn unlockpt +does not conform to +.St -p1003.1-2008 , +because it depends on +.Xr posix_openpt 2 +to create the pseudo-terminal device with proper permissions in place. +It only validates whether +.Fa fildes +is a valid pseudo-terminal master device. +Future revisions of the specification will likely allow this behaviour, +as stated by the Austin Group. +.Sh HISTORY +The +.Fn grantpt , +.Fn ptsname +and +.Fn unlockpt +functions appeared in +.Fx 5.0 . diff --git a/lib/libc/stdlib/ptsname.c b/lib/libc/stdlib/ptsname.c new file mode 100644 index 000000000000..adbf0e1692a4 --- /dev/null +++ b/lib/libc/stdlib/ptsname.c @@ -0,0 +1,114 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Portions of this software were developed under sponsorship from Snow + * B.V., the Netherlands. + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/ioctl.h> + +#include <errno.h> +#include <paths.h> +#include <stdlib.h> +#include <string.h> +#include "un-namespace.h" + +/* + * __isptmaster(): return whether the file descriptor refers to a + * pseudo-terminal master device. + */ +static int +__isptmaster(int fildes) +{ + + if (_ioctl(fildes, TIOCPTMASTER) == 0) + return (0); + + if (errno != EBADF) + errno = EINVAL; + + return (-1); +} + +/* + * In our implementation, grantpt() and unlockpt() don't actually have + * any use, because PTY's are created on the fly and already have proper + * permissions upon creation. + * + * Just make sure `fildes' actually points to a real PTY master device. + */ +__strong_reference(__isptmaster, grantpt); +__strong_reference(__isptmaster, unlockpt); + +/* + * ptsname_r(): return the pathname of the slave pseudo-terminal device + * associated with the specified master. + */ +int +__ptsname_r(int fildes, char *buffer, size_t buflen) +{ + + if (buflen <= sizeof(_PATH_DEV)) { + errno = ERANGE; + return (-1); + } + + /* Make sure fildes points to a master device. */ + if (__isptmaster(fildes) != 0) + return (-1); + + memcpy(buffer, _PATH_DEV, sizeof(_PATH_DEV)); + buffer += sizeof(_PATH_DEV) - 1; + buflen -= sizeof(_PATH_DEV) - 1; + + if (fdevname_r(fildes, buffer, buflen) == NULL) { + if (errno == EINVAL) + errno = ERANGE; + return (-1); + } + + return (0); +} + +__strong_reference(__ptsname_r, ptsname_r); + +/* + * ptsname(): return the pathname of the slave pseudo-terminal device + * associated with the specified master. + */ +char * +ptsname(int fildes) +{ + static char pt_slave[sizeof(_PATH_DEV) + SPECNAMELEN]; + + if (__ptsname_r(fildes, pt_slave, sizeof(pt_slave)) == 0) + return (pt_slave); + + return (NULL); +} diff --git a/lib/libc/stdlib/qsort.3 b/lib/libc/stdlib/qsort.3 new file mode 100644 index 000000000000..e2e29e7cf04f --- /dev/null +++ b/lib/libc/stdlib/qsort.3 @@ -0,0 +1,446 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd October 25, 2024 +.Dt QSORT 3 +.Os +.Sh NAME +.Nm qsort , +.Nm qsort_b , +.Nm qsort_r , +.Nm heapsort , +.Nm heapsort_b , +.Nm mergesort , +.Nm mergesort_b +.Nd sort functions +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft void +.Fo qsort +.Fa "void *base" +.Fa "size_t nmemb" +.Fa "size_t size" +.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]" +.Fc +.Ft void +.Fo qsort_b +.Fa "void *base" +.Fa "size_t nmemb" +.Fa "size_t size" +.Fa "int \*[lp]^compar\*[rp]\*[lp]const void *, const void *\*[rp]" +.Fc +.Ft void +.Fo qsort_r +.Fa "void *base" +.Fa "size_t nmemb" +.Fa "size_t size" +.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *, void *\*[rp]" +.Fa "void *thunk" +.Fc +.Ft int +.Fo heapsort +.Fa "void *base" +.Fa "size_t nmemb" +.Fa "size_t size" +.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]" +.Fc +.Ft int +.Fo heapsort_b +.Fa "void *base" +.Fa "size_t nmemb" +.Fa "size_t size" +.Fa "int \*[lp]^compar\*[rp]\*[lp]const void *, const void *\*[rp]" +.Fc +.Ft int +.Fo mergesort +.Fa "void *base" +.Fa "size_t nmemb" +.Fa "size_t size" +.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]" +.Fc +.Ft int +.Fo mergesort_b +.Fa "void *base" +.Fa "size_t nmemb" +.Fa "size_t size" +.Fa "int \*[lp]^compar\*[rp]\*[lp]const void *, const void *\*[rp]" +.Fc +.Fd #define __STDC_WANT_LIB_EXT1__ 1 +.Ft errno_t +.Fo qsort_s +.Fa "void *base" +.Fa "rsize_t nmemb" +.Fa "rsize_t size" +.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *, void *\*[rp]" +.Fa "void *thunk" +.Fc +.Sh DESCRIPTION +The +.Fn qsort +function is a modified partition-exchange sort, or quicksort. +The +.Fn heapsort +function is a modified selection sort. +The +.Fn mergesort +function is a modified merge sort with exponential search +intended for sorting data with pre-existing order. +.Pp +The +.Fn qsort +and +.Fn heapsort +functions sort an array of +.Fa nmemb +objects, the initial member of which is pointed to by +.Fa base . +The size of each object is specified by +.Fa size . +The +.Fn mergesort +function +behaves similarly, but +.Em requires +that +.Fa size +be greater than +.Dq "sizeof(void *) / 2" . +.Pp +The contents of the array +.Fa base +are sorted in ascending order according to +a comparison function pointed to by +.Fa compar , +which requires two arguments pointing to the objects being +compared. +.Pp +The comparison function must return an integer less than, equal to, or +greater than zero if the first argument is considered to be respectively +less than, equal to, or greater than the second. +.Pp +The +.Fn qsort_r +function behaves identically to +.Fn qsort , +except that it takes an additional argument, +.Fa thunk , +which is passed unchanged as the last argument to function pointed to +.Fa compar . +This allows the comparison function to access additional +data without using global variables, and thus +.Fn qsort_r +is suitable for use in functions which must be reentrant. +The +.Fn qsort_b +function behaves identically to +.Fn qsort , +except that it takes a block, rather than a function pointer. +.Pp +The algorithms implemented by +.Fn qsort , +.Fn qsort_r , +and +.Fn heapsort +are +.Em not +stable, that is, if two members compare as equal, their order in +the sorted array is undefined. +The +.Fn heapsort_b +function behaves identically to +.Fn heapsort , +except that it takes a block, rather than a function pointer. +The +.Fn mergesort +algorithm is stable. +The +.Fn mergesort_b +function behaves identically to +.Fn mergesort , +except that it takes a block, rather than a function pointer. +.Pp +The +.Fn qsort +and +.Fn qsort_r +functions are an implementation of C.A.R. +Hoare's +.Dq quicksort +algorithm, +a variant of partition-exchange sorting; in particular, see +.An D.E. Knuth Ns 's +.%T "Algorithm Q" . +.Sy Quicksort +takes O N lg N average time. +This implementation uses median selection to avoid its +O N**2 worst-case behavior. +.Pp +The +.Fn heapsort +function is an implementation of +.An "J.W.J. William" Ns 's +.Dq heapsort +algorithm, +a variant of selection sorting; in particular, see +.An "D.E. Knuth" Ns 's +.%T "Algorithm H" . +.Sy Heapsort +takes O N lg N worst-case time. +Its +.Em only +advantage over +.Fn qsort +is that it uses almost no additional memory; while +.Fn qsort +does not allocate memory, it is implemented using recursion. +.Pp +The function +.Fn mergesort +requires additional memory of size +.Fa nmemb * +.Fa size +bytes; it should be used only when space is not at a premium. +The +.Fn mergesort +function +is optimized for data with pre-existing order; its worst case +time is O N lg N; its best case is O N. +.Pp +Normally, +.Fn qsort +is faster than +.Fn mergesort +is faster than +.Fn heapsort . +Memory availability and pre-existing order in the data can make this +untrue. +.Pp +The +.Fn qsort_s +function behaves the same as +.Fn qsort_r , +except that if +.Fa nmemb +or +.Fa size +are greater than +.Dv RSIZE_MAX , +or +.Fa nmemb +is not zero and +.Fa compar +is +.Dv NULL +or +.Fa size +is zero, then the runtime-constraint handler is called, and +.Fn qsort_s +returns an error. +Note that the handler is called before +.Fn qsort_s +returns the error, and the handler function might not return. +.Sh RETURN VALUES +The +.Fn qsort +and +.Fn qsort_r +functions +return no value. +The +.Fn qsort_s +function returns zero on success, non-zero on error. +.Pp +.Rv -std heapsort mergesort +.Sh EXAMPLES +A sample program that sorts an array of +.Vt int +values in place using +.Fn qsort , +and then prints the sorted array to standard output is: +.Bd -literal +#include <stdio.h> +#include <stdlib.h> + +/* + * Custom comparison function that compares 'int' values through pointers + * passed by qsort(3). + */ +static int +int_compare(const void *p1, const void *p2) +{ + int left = *(const int *)p1; + int right = *(const int *)p2; + + return ((left > right) - (left < right)); +} + +/* + * Sort an array of 'int' values and print it to standard output. + */ +int +main(void) +{ + int int_array[] = { 4, 5, 9, 3, 0, 1, 7, 2, 8, 6 }; + size_t array_size = sizeof(int_array) / sizeof(int_array[0]); + size_t k; + + qsort(&int_array, array_size, sizeof(int_array[0]), int_compare); + for (k = 0; k < array_size; k++) + printf(" %d", int_array[k]); + puts(""); + return (EXIT_SUCCESS); +} +.Ed +.Sh COMPATIBILITY +The order of arguments for the comparison function used with +.Fn qsort_r +is historically different from the one used by +.Fn qsort_s +and the GNU libc implementation of +.Fn qsort_r . +However, as of +.Fx 14.0 , +the +.Fn qsort_r +has been updated so that the +.Fa thunk +parameter appears last to match +.St -p1003.1-2024 . +Both the historical and the updated interfaces are now accepted +via C11 generic selection and C++ polymorphism, +but the updated interface is recommended for portable applications. +.Pp +.Fn qsort_s +is part of the +.Em optional +Annex K portion of +.St -isoC-2011 +and may not be portable to other standards-conforming platforms. +.Pp +Previous versions of +.Fn qsort +did not permit the comparison routine itself to call +.Fn qsort 3 . +This is no longer true. +.Sh ERRORS +The +.Fn heapsort +and +.Fn mergesort +functions succeed unless: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa size +argument is zero, or, +the +.Fa size +argument to +.Fn mergesort +is less than +.Dq "sizeof(void *) / 2" . +.It Bq Er ENOMEM +The +.Fn heapsort +or +.Fn mergesort +functions +were unable to allocate memory. +.El +.Sh SEE ALSO +.Xr sort 1 , +.Xr radixsort 3 +.Rs +.%A Hoare, C.A.R. +.%D 1962 +.%T "Quicksort" +.%J "The Computer Journal" +.%V 5:1 +.%P pp. 10-15 +.Re +.Rs +.%A Williams, J.W.J +.%D 1964 +.%T "Heapsort" +.%J "Communications of the ACM" +.%V 7:1 +.%P pp. 347-348 +.Re +.Rs +.%A Knuth, D.E. +.%D 1968 +.%B "The Art of Computer Programming" +.%V Vol. 3 +.%T "Sorting and Searching" +.%P pp. 114-123, 145-149 +.Re +.Rs +.%A McIlroy, P.M. +.%T "Optimistic Sorting and Information Theoretic Complexity" +.%J "Fourth Annual ACM-SIAM Symposium on Discrete Algorithms" +.%V January 1992 +.Re +.Rs +.%A Bentley, J.L. +.%A McIlroy, M.D. +.%T "Engineering a Sort Function" +.%J "Software--Practice and Experience" +.%V Vol. 23(11) +.%P pp. 1249-1265 +.%D November\ 1993 +.Re +.Sh STANDARDS +The +.Fn qsort +function conforms to +.St -isoC . +The +.Fn qsort_r +function conforms to +.St -p1003.1-2024 . +The +.Fn qsort_s +function conforms to +.St -isoC-2011 +K.3.6.3.2. +.Sh HISTORY +The variants of these functions that take blocks as arguments first appeared in +Mac OS X. +This implementation was created by David Chisnall. +.Pp +In +.Fx 14.0 , +the prototype of +.Fn qsort_r +was updated to match +.St -p1003.1-2024 . diff --git a/lib/libc/stdlib/qsort.c b/lib/libc/stdlib/qsort.c new file mode 100644 index 000000000000..400124593d07 --- /dev/null +++ b/lib/libc/stdlib/qsort.c @@ -0,0 +1,248 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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. + * 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. + */ + +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include "libc_private.h" + +#if defined(I_AM_QSORT_R) +typedef int cmp_t(const void *, const void *, void *); +#elif defined(I_AM_QSORT_R_COMPAT) +typedef int cmp_t(void *, const void *, const void *); +#elif defined(I_AM_QSORT_S) +typedef int cmp_t(const void *, const void *, void *); +#else +typedef int cmp_t(const void *, const void *); +#endif +static inline char *med3(char *, char *, char *, cmp_t *, void *); + +#define MIN(a, b) ((a) < (b) ? a : b) + +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ + +static inline void +swapfunc(char *a, char *b, size_t es) +{ + char t; + + do { + t = *a; + *a++ = *b; + *b++ = t; + } while (--es > 0); +} + +#define vecswap(a, b, n) \ + if ((n) > 0) swapfunc(a, b, n) + +#if defined(I_AM_QSORT_R) +#define CMP(t, x, y) (cmp((x), (y), (t))) +#elif defined(I_AM_QSORT_R_COMPAT) +#define CMP(t, x, y) (cmp((t), (x), (y))) +#elif defined(I_AM_QSORT_S) +#define CMP(t, x, y) (cmp((x), (y), (t))) +#else +#define CMP(t, x, y) (cmp((x), (y))) +#endif + +static inline char * +med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk +#if !defined(I_AM_QSORT_R) && !defined(I_AM_QSORT_R_COMPAT) && !defined(I_AM_QSORT_S) +__unused +#endif +) +{ + return CMP(thunk, a, b) < 0 ? + (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a )) + :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c )); +} + +/* + * The actual qsort() implementation is static to avoid preemptible calls when + * recursing. Also give them different names for improved debugging. + */ +#if defined(I_AM_QSORT_R) +#define local_qsort local_qsort_r +#elif defined(I_AM_QSORT_R_COMPAT) +#define local_qsort local_qsort_r_compat +#elif defined(I_AM_QSORT_S) +#define local_qsort local_qsort_s +#endif +static void +local_qsort(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + size_t d1, d2; + int cmp_result; + + /* if there are less than 2 elements, then sorting is not needed */ + if (__predict_false(n < 2)) + return; +loop: + if (n < 7) { + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; + pl > (char *)a && CMP(thunk, pl - es, pl) > 0; + pl -= es) + swapfunc(pl, pl - es, es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + size_t d = (n / 8) * es; + + pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk); + pm = med3(pm - d, pm, pm + d, cmp, thunk); + pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk); + } + pm = med3(pl, pm, pn, cmp, thunk); + } + swapfunc(a, pm, es); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) { + if (cmp_result == 0) { + swapfunc(pa, pb, es); + pa += es; + } + pb += es; + } + while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) { + if (cmp_result == 0) { + swapfunc(pc, pd, es); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swapfunc(pb, pc, es); + pb += es; + pc -= es; + } + + pn = (char *)a + n * es; + d1 = MIN(pa - (char *)a, pb - pa); + vecswap(a, pb - d1, d1); + /* + * Cast es to preserve signedness of right-hand side of MIN() + * expression, to avoid sign ambiguity in the implied comparison. es + * is safely within [0, SSIZE_MAX]. + */ + d1 = MIN(pd - pc, pn - pd - (ssize_t)es); + vecswap(pb, pn - d1, d1); + + d1 = pb - pa; + d2 = pd - pc; + if (d1 <= d2) { + /* Recurse on left partition, then iterate on right partition */ + if (d1 > es) { + local_qsort(a, d1 / es, es, cmp, thunk); + } + if (d2 > es) { + /* Iterate rather than recurse to save stack space */ + /* qsort(pn - d2, d2 / es, es, cmp); */ + a = pn - d2; + n = d2 / es; + goto loop; + } + } else { + /* Recurse on right partition, then iterate on left partition */ + if (d2 > es) { + local_qsort(pn - d2, d2 / es, es, cmp, thunk); + } + if (d1 > es) { + /* Iterate rather than recurse to save stack space */ + /* qsort(a, d1 / es, es, cmp); */ + n = d1 / es; + goto loop; + } + } +} + +#if defined(I_AM_QSORT_R) +void +(qsort_r)(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk) +{ + local_qsort_r(a, n, es, cmp, thunk); +} +#elif defined(I_AM_QSORT_R_COMPAT) +void +__qsort_r_compat(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp) +{ + local_qsort_r_compat(a, n, es, cmp, thunk); +} +#elif defined(I_AM_QSORT_S) +errno_t +qsort_s(void *a, rsize_t n, rsize_t es, cmp_t *cmp, void *thunk) +{ + if (n > RSIZE_MAX) { + __throw_constraint_handler_s("qsort_s : n > RSIZE_MAX", EINVAL); + return (EINVAL); + } else if (es > RSIZE_MAX) { + __throw_constraint_handler_s("qsort_s : es > RSIZE_MAX", + EINVAL); + return (EINVAL); + } else if (n != 0) { + if (a == NULL) { + __throw_constraint_handler_s("qsort_s : a == NULL", + EINVAL); + return (EINVAL); + } else if (cmp == NULL) { + __throw_constraint_handler_s("qsort_s : cmp == NULL", + EINVAL); + return (EINVAL); + } else if (es <= 0) { + __throw_constraint_handler_s("qsort_s : es <= 0", + EINVAL); + return (EINVAL); + } + } + + local_qsort_s(a, n, es, cmp, thunk); + return (0); +} +#else +void +qsort(void *a, size_t n, size_t es, cmp_t *cmp) +{ + local_qsort(a, n, es, cmp, NULL); +} +#endif diff --git a/lib/libc/stdlib/qsort_r.c b/lib/libc/stdlib/qsort_r.c new file mode 100644 index 000000000000..b382b40e91f6 --- /dev/null +++ b/lib/libc/stdlib/qsort_r.c @@ -0,0 +1,6 @@ +/* + * This file is in the public domain. Originally written by Garrett + * A. Wollman. + */ +#define I_AM_QSORT_R +#include "qsort.c" diff --git a/lib/libc/stdlib/qsort_r_compat.c b/lib/libc/stdlib/qsort_r_compat.c new file mode 100644 index 000000000000..2471c53b068f --- /dev/null +++ b/lib/libc/stdlib/qsort_r_compat.c @@ -0,0 +1,19 @@ +/* + * This file is in the public domain. Originally written by Garrett + * A. Wollman. + */ +#include "block_abi.h" +#define I_AM_QSORT_R_COMPAT +#include "qsort.c" + +typedef DECLARE_BLOCK(int, qsort_block, const void *, const void *); + +void +qsort_b(void *base, size_t nel, size_t width, qsort_block compar) +{ + __qsort_r_compat(base, nel, width, compar, + (int (*)(void *, const void *, const void *)) + GET_BLOCK_FUNCTION(compar)); +} + +__sym_compat(qsort_r, __qsort_r_compat, FBSD_1.0); diff --git a/lib/libc/stdlib/qsort_s.c b/lib/libc/stdlib/qsort_s.c new file mode 100644 index 000000000000..af8ec3128031 --- /dev/null +++ b/lib/libc/stdlib/qsort_s.c @@ -0,0 +1,6 @@ +/* + * This file is in the public domain. Originally written by Garrett + * A. Wollman. + */ +#define I_AM_QSORT_S +#include "qsort.c" diff --git a/lib/libc/stdlib/quick_exit.3 b/lib/libc/stdlib/quick_exit.3 new file mode 100644 index 000000000000..185c1013b0a9 --- /dev/null +++ b/lib/libc/stdlib/quick_exit.3 @@ -0,0 +1,67 @@ +.\" Copyright (c) 2011 David Chisnall +.\" 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 AUTHOR 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 AUTHOR 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. +.\" +.Dd November 4, 2017 +.Dt QUICK_EXIT 3 +.Os +.Sh NAME +.Nm quick_exit +.Nd exits a program quickly, running minimal cleanup +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft _Noreturn void +.Fn quick_exit "int status" +.Sh DESCRIPTION +The +.Fn quick_exit +function exits the program quickly calling any cleanup functions registered +with +.Xr at_quick_exit 3 +but not any C++ destructors or cleanup code registered with +.Xr atexit 3 . +The +.Xr stdio 3 +file buffers are not flushed. +.Pp +The function +.Fn quick_exit +is +.Em async-signal safe +when the functions registered with +.Xr at_quick_exit 3 +are. +.Sh RETURN VALUES +The +.Fn quick_exit +function does not return. +.Sh SEE ALSO +.Xr at_quick_exit 3 , +.Xr exit 3 +.Sh STANDARDS +The +.Fn quick_exit +function conforms to +.St -isoC-2011 . diff --git a/lib/libc/stdlib/quick_exit.c b/lib/libc/stdlib/quick_exit.c new file mode 100644 index 000000000000..4dee7b20bd2b --- /dev/null +++ b/lib/libc/stdlib/quick_exit.c @@ -0,0 +1,77 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2011 David Chisnall + * Copyright (c) 2023 Klara, Inc. + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <sys/types.h> + +#include <stdatomic.h> +#include <stdlib.h> + +/** + * Linked list of quick exit handlers. These will be invoked in reverse + * order of insertion when quick_exit() is called. This is simpler than + * the atexit() version, because it is not required to support C++ + * destructors or DSO-specific cleanups. + */ +struct quick_exit_handler { + struct quick_exit_handler *next; + void (*cleanup)(void); +}; + +static _Atomic(struct quick_exit_handler *) handlers; + +int +at_quick_exit(void (*func)(void)) +{ + struct quick_exit_handler *h; + + if ((h = calloc(1, sizeof(*h))) == NULL) { + return (-1); + } + h->cleanup = func; + while (!atomic_compare_exchange_strong(&handlers, &h->next, h)) { + /* nothing */ ; + } + return (0); +} + +void +quick_exit(int status) +{ + struct quick_exit_handler *h; + + /* + * XXX: The C++ spec requires us to call std::terminate if there is an + * exception here. + */ + for (h = atomic_load_explicit(&handlers, memory_order_acquire); + h != NULL; h = h->next) { + h->cleanup(); + } + _Exit(status); +} diff --git a/lib/libc/stdlib/radixsort.3 b/lib/libc/stdlib/radixsort.3 new file mode 100644 index 000000000000..8ae4008a946e --- /dev/null +++ b/lib/libc/stdlib/radixsort.3 @@ -0,0 +1,157 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. 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. +.\" 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. +.\" +.Dd January 27, 1994 +.Dt RADIXSORT 3 +.Os +.Sh NAME +.Nm radixsort , sradixsort +.Nd radix sort +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In limits.h +.In stdlib.h +.Ft int +.Fn radixsort "const unsigned char **base" "int nmemb" "const unsigned char *table" "unsigned endbyte" +.Ft int +.Fn sradixsort "const unsigned char **base" "int nmemb" "const unsigned char *table" "unsigned endbyte" +.Sh DESCRIPTION +The +.Fn radixsort +and +.Fn sradixsort +functions +are implementations of radix sort. +.Pp +These functions sort an array of pointers to byte strings, the initial +member of which is referenced by +.Fa base . +The byte strings may contain any values; the end of each string +is denoted by the user-specified value +.Fa endbyte . +.Pp +Applications may specify a sort order by providing the +.Fa table +argument. +If +.Pf non- Dv NULL , +.Fa table +must reference an array of +.Dv UCHAR_MAX ++ 1 bytes which contains the sort +weight of each possible byte value. +The end-of-string byte must have a sort weight of 0 or 255 +(for sorting in reverse order). +More than one byte may have the same sort weight. +The +.Fa table +argument +is useful for applications which wish to sort different characters +equally, for example, providing a table with the same weights +for A-Z as for a-z will result in a case-insensitive sort. +If +.Fa table +is NULL, the contents of the array are sorted in ascending order +according to the +.Tn ASCII +order of the byte strings they reference and +.Fa endbyte +has a sorting weight of 0. +.Pp +The +.Fn sradixsort +function is stable, that is, if two elements compare as equal, their +order in the sorted array is unchanged. +The +.Fn sradixsort +function uses additional memory sufficient to hold +.Fa nmemb +pointers. +.Pp +The +.Fn radixsort +function is not stable, but uses no additional memory. +.Pp +These functions are variants of most-significant-byte radix sorting; in +particular, see +.An "D.E. Knuth" Ns 's +.%T "Algorithm R" +and section 5.2.5, exercise 10. +They take linear time relative to the number of bytes in the strings. +.Sh RETURN VALUES +.Rv -std radixsort +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er EINVAL +The value of the +.Fa endbyte +element of +.Fa table +is not 0 or 255. +.El +.Pp +Additionally, the +.Fn sradixsort +function +may fail and set +.Va errno +for any of the errors specified for the library routine +.Xr malloc 3 . +.Sh SEE ALSO +.Xr sort 1 , +.Xr qsort 3 +.Pp +.Rs +.%A Knuth, D.E. +.%D 1968 +.%B "The Art of Computer Programming" +.%T "Sorting and Searching" +.%V Vol. 3 +.%P pp. 170-178 +.Re +.Rs +.%A Paige, R. +.%D 1987 +.%T "Three Partition Refinement Algorithms" +.%J "SIAM J. Comput." +.%V Vol. 16 +.%N No. 6 +.Re +.Rs +.%A McIlroy, P. +.%D 1993 +.%B "Engineering Radix Sort" +.%T "Computing Systems" +.%V Vol. 6:1 +.%P pp. 5-27 +.Re +.Sh HISTORY +The +.Fn radixsort +function first appeared in +.Bx 4.4 . diff --git a/lib/libc/stdlib/radixsort.c b/lib/libc/stdlib/radixsort.c new file mode 100644 index 000000000000..4193df4d66d1 --- /dev/null +++ b/lib/libc/stdlib/radixsort.c @@ -0,0 +1,307 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Peter McIlroy and by Dan Bernstein at New York University, + * + * 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. + */ + +/* + * Radixsort routines. + * + * Program r_sort_a() is unstable but uses O(logN) extra memory for a stack. + * Use radixsort(a, n, trace, endchar) for this case. + * + * For stable sorting (using N extra pointers) use sradixsort(), which calls + * r_sort_b(). + * + * For a description of this code, see D. McIlroy, P. McIlroy, K. Bostic, + * "Engineering Radix Sort". + */ + +#include <sys/types.h> +#include <stdlib.h> +#include <stddef.h> +#include <errno.h> + +typedef struct { + const u_char **sa; + int sn, si; +} stack; + +static inline void simplesort +(const u_char **, int, int, const u_char *, u_int); +static void r_sort_a(const u_char **, int, int, const u_char *, u_int); +static void r_sort_b(const u_char **, const u_char **, int, int, + const u_char *, u_int); + +#define THRESHOLD 20 /* Divert to simplesort(). */ +#define SIZE 512 /* Default stack size. */ + +#define SETUP { \ + if (tab == NULL) { \ + tr = tr0; \ + for (c = 0; c < endch; c++) \ + tr0[c] = c + 1; \ + tr0[c] = 0; \ + for (c++; c < 256; c++) \ + tr0[c] = c; \ + endch = 0; \ + } else { \ + endch = tab[endch]; \ + tr = tab; \ + if (endch != 0 && endch != 255) { \ + errno = EINVAL; \ + return (-1); \ + } \ + } \ +} + +int +radixsort(const u_char **a, int n, const u_char *tab, u_int endch) +{ + const u_char *tr; + int c; + u_char tr0[256]; + + SETUP; + r_sort_a(a, n, 0, tr, endch); + return (0); +} + +int +sradixsort(const u_char **a, int n, const u_char *tab, u_int endch) +{ + const u_char *tr, **ta; + int c; + u_char tr0[256]; + + SETUP; + if (n < THRESHOLD) + simplesort(a, n, 0, tr, endch); + else { + if ((ta = malloc(n * sizeof(a))) == NULL) + return (-1); + r_sort_b(a, ta, n, 0, tr, endch); + free(ta); + } + return (0); +} + +#define empty(s) (s >= sp) +#define pop(a, n, i) a = (--sp)->sa, n = sp->sn, i = sp->si +#define push(a, n, i) sp->sa = a, sp->sn = n, (sp++)->si = i +#define swap(a, b, t) t = a, a = b, b = t + +/* Unstable, in-place sort. */ +static void +r_sort_a(const u_char **a, int n, int i, const u_char *tr, u_int endch) +{ + static int count[256], nc, bmin; + int c; + const u_char **ak, *r; + stack s[SIZE], *sp, *sp0, *sp1, temp; + int *cp, bigc; + const u_char **an, *t, **aj, **top[256]; + + /* Set up stack. */ + sp = s; + push(a, n, i); + while (!empty(s)) { + pop(a, n, i); + if (n < THRESHOLD) { + simplesort(a, n, i, tr, endch); + continue; + } + an = a + n; + + /* Make character histogram. */ + if (nc == 0) { + bmin = 255; /* First occupied bin, excluding eos. */ + for (ak = a; ak < an;) { + c = tr[(*ak++)[i]]; + if (++count[c] == 1 && c != endch) { + if (c < bmin) + bmin = c; + nc++; + } + } + if (sp + nc > s + SIZE) { /* Get more stack. */ + r_sort_a(a, n, i, tr, endch); + continue; + } + } + + /* + * Special case: if all strings have the same + * character at position i, move on to the next + * character. + */ + if (nc == 1 && count[bmin] == n) { + push(a, n, i+1); + nc = count[bmin] = 0; + continue; + } + + /* + * Set top[]; push incompletely sorted bins onto stack. + * top[] = pointers to last out-of-place element in bins. + * count[] = counts of elements in bins. + * Before permuting: top[c-1] + count[c] = top[c]; + * during deal: top[c] counts down to top[c-1]. + */ + sp0 = sp1 = sp; /* Stack position of biggest bin. */ + bigc = 2; /* Size of biggest bin. */ + if (endch == 0) /* Special case: set top[eos]. */ + top[0] = ak = a + count[0]; + else { + ak = a; + top[255] = an; + } + for (cp = count + bmin; nc > 0; cp++) { + while (*cp == 0) /* Find next non-empty pile. */ + cp++; + if (*cp > 1) { + if (*cp > bigc) { + bigc = *cp; + sp1 = sp; + } + push(ak, *cp, i+1); + } + top[cp-count] = ak += *cp; + nc--; + } + swap(*sp0, *sp1, temp); /* Play it safe -- biggest bin last. */ + + /* + * Permute misplacements home. Already home: everything + * before aj, and in bin[c], items from top[c] on. + * Inner loop: + * r = next element to put in place; + * ak = top[r[i]] = location to put the next element. + * aj = bottom of 1st disordered bin. + * Outer loop: + * Once the 1st disordered bin is done, ie. aj >= ak, + * aj<-aj + count[c] connects the bins in a linked list; + * reset count[c]. + */ + for (aj = a; aj < an; *aj = r, aj += count[c], count[c] = 0) + for (r = *aj; aj < (ak = --top[c = tr[r[i]]]);) + swap(*ak, r, t); + } +} + +/* Stable sort, requiring additional memory. */ +static void +r_sort_b(const u_char **a, const u_char **ta, int n, int i, const u_char *tr, + u_int endch) +{ + static int count[256], nc, bmin; + int c; + const u_char **ak, **ai; + stack s[512], *sp, *sp0, *sp1, temp; + const u_char **top[256]; + int *cp, bigc; + + sp = s; + push(a, n, i); + while (!empty(s)) { + pop(a, n, i); + if (n < THRESHOLD) { + simplesort(a, n, i, tr, endch); + continue; + } + + if (nc == 0) { + bmin = 255; + for (ak = a + n; --ak >= a;) { + c = tr[(*ak)[i]]; + if (++count[c] == 1 && c != endch) { + if (c < bmin) + bmin = c; + nc++; + } + } + if (sp + nc > s + SIZE) { + r_sort_b(a, ta, n, i, tr, endch); + continue; + } + } + + sp0 = sp1 = sp; + bigc = 2; + if (endch == 0) { + top[0] = ak = a + count[0]; + count[0] = 0; + } else { + ak = a; + top[255] = a + n; + count[255] = 0; + } + for (cp = count + bmin; nc > 0; cp++) { + while (*cp == 0) + cp++; + if ((c = *cp) > 1) { + if (c > bigc) { + bigc = c; + sp1 = sp; + } + push(ak, c, i+1); + } + top[cp-count] = ak += c; + *cp = 0; /* Reset count[]. */ + nc--; + } + swap(*sp0, *sp1, temp); + + for (ak = ta + n, ai = a+n; ak > ta;) /* Copy to temp. */ + *--ak = *--ai; + for (ak = ta+n; --ak >= ta;) /* Deal to piles. */ + *--top[tr[(*ak)[i]]] = *ak; + } +} + +/* insertion sort */ +static inline void +simplesort(const u_char **a, int n, int b, const u_char *tr, u_int endch) +{ + u_char ch; + const u_char **ak, **ai, *s, *t; + + for (ak = a+1; --n >= 1; ak++) + for (ai = ak; ai > a; ai--) { + for (s = ai[0] + b, t = ai[-1] + b; + (ch = tr[*s]) != endch; s++, t++) + if (ch != tr[*t]) + break; + if (ch >= tr[*t]) + break; + swap(ai[0], ai[-1], s); + } +} diff --git a/lib/libc/stdlib/rand.3 b/lib/libc/stdlib/rand.3 new file mode 100644 index 000000000000..33eaa191b4fe --- /dev/null +++ b/lib/libc/stdlib/rand.3 @@ -0,0 +1,146 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd February 1, 2020 +.Dt RAND 3 +.Os +.Sh NAME +.Nm rand , +.Nm srand , +.Nm rand_r +.Nd bad random number generator +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft void +.Fn srand "unsigned seed" +.Ft int +.Fn rand void +.Ft int +.Fn rand_r "unsigned *ctx" +.Sh DESCRIPTION +.Bf -symbolic +The functions described in this manual page are not cryptographically +secure. +Applications which require unpredictable random numbers should use +.Xr arc4random 3 +instead. +.Ef +.Pp +The +.Fn rand +function computes a sequence of pseudo-random integers in the range +of 0 to +.Dv RAND_MAX , +inclusive. +.Pp +The +.Fn srand +function seeds the algorithm with the +.Fa seed +parameter. +Repeatable sequences of +.Fn rand +output may be obtained by calling +.Fn srand +with the same +.Fa seed . +.Fn rand +is implicitly initialized as if +.Fn srand "1" +had been invoked explicitly. +.Pp +In +.Fx 13 , +.Fn rand +is implemented using the same 128-byte state LFSR generator algorithm as +.Xr random 3 . +However, the legacy +.Fn rand_r +function is not (and can not be, because of its limited +.Fa *ctx +size). +.Fn rand_r +implements the historical, poor-quality Park-Miller 32-bit LCG and should not +be used in new designs. +.Sh IMPLEMENTATION NOTES +Since +.Fx 13 , +.Fn rand +is implemented with the same generator as +.Xr random 3 , +so the low-order bits should no longer be significantly worse than the +high-order bits. +.Sh SEE ALSO +.Xr arc4random 3 , +.Xr random 3 , +.Xr random 4 +.Sh STANDARDS +The +.Fn rand +and +.Fn srand +functions +conform to +.St -isoC . +.Pp +The +.Fn rand_r +function is not part of +.St -isoC +and is marked obsolescent in +.St -p1003.1-2008 . +It may be removed in a future revision of POSIX. +.Sh CAVEATS +Prior to +.Fx 13 , +.Fn rand +used the historical Park-Miller generator with 32 bits of state and produced +poor quality output, especially in the lower bits. +.Fn rand +in earlier versions of +.Fx , +as well as other standards-conforming implementations, may continue to produce +poor quality output. +.Pp +.Em These functions should not be used in portable applications that want a +.Em high quality or high performance pseudorandom number generator . +One possible replacement, +.Xr random 3 , +is portable to Linux — but it is not especially fast, nor standardized. +.Pp +If broader portability or better performance is desired, any of the widely +available and permissively licensed SFC64/32, JSF64/32, PCG64/32, or SplitMix64 +algorithm implementations may be embedded in your application. +These algorithms have the benefit of requiring less space than +.Xr random 3 +and being quite fast (in header inline implementations). diff --git a/lib/libc/stdlib/rand.c b/lib/libc/stdlib/rand.c new file mode 100644 index 000000000000..31b51b327a0d --- /dev/null +++ b/lib/libc/stdlib/rand.c @@ -0,0 +1,162 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. + * 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. + * + * Posix rand_r function added May 1999 by Wes Peters <wes@softweyr.com>. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/sysctl.h> +#include <assert.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdlib.h> +#include <syslog.h> +#include "un-namespace.h" + +#include "libc_private.h" +#include "random.h" + +/* + * Implement rand(3), the standard C PRNG API, using the non-standard but + * higher quality random(3) implementation and the same size 128-byte state + * LFSR as the random(3) default. + * + * It turns out there are portable applications that want a PRNG but are too + * lazy to use better-but-nonstandard interfaces like random(3), when + * available, and too lazy to import higher-quality and faster PRNGs into their + * codebase (such as any of SFC, JSF, 128-bit LCGs, PCG, or Splitmix64). + * + * Since we're stuck with rand(3) due to the C standard, we can at least have + * it produce a relatively good PRNG sequence using our existing random(3) + * LFSR. The random(3) design is not particularly fast nor compact, but it has + * the advantage of being the one already in the tree. + */ +static struct __random_state *rand3_state; +static pthread_once_t rand3_state_once = PTHREAD_ONCE_INIT; + +static void +initialize_rand3(void) +{ + int error; + + rand3_state = allocatestate(TYPE_3); + error = initstate_r(rand3_state, 1, rand3_state->rst_randtbl, BREAK_3); + assert(error == 0); +} + +int +rand(void) +{ + _once(&rand3_state_once, initialize_rand3); + return ((int)random_r(rand3_state)); +} + +void +srand(unsigned seed) +{ + _once(&rand3_state_once, initialize_rand3); + srandom_r(rand3_state, seed); +} + +/* + * FreeBSD 12 and prior compatibility implementation of rand(3). + */ +static int +do_rand(unsigned long *ctx) +{ +/* + * Compute x = (7^5 * x) mod (2^31 - 1) + * without overflowing 31 bits: + * (2^31 - 1) = 127773 * (7^5) + 2836 + * From "Random number generators: good ones are hard to find", + * Park and Miller, Communications of the ACM, vol. 31, no. 10, + * October 1988, p. 1195. + */ + long hi, lo, x; + + /* Transform to [1, 0x7ffffffe] range. */ + x = (*ctx % 0x7ffffffe) + 1; + hi = x / 127773; + lo = x % 127773; + x = 16807 * lo - 2836 * hi; + if (x < 0) + x += 0x7fffffff; + /* Transform to [0, 0x7ffffffd] range. */ + x--; + *ctx = x; + return (x); +} + +/* + * Can't fix this garbage; too little state. + */ +int +rand_r(unsigned *ctx) +{ + u_long val; + int r; + + val = *ctx; + r = do_rand(&val); + *ctx = (unsigned)val; + return (r); +} + +static u_long next = 1; + +int __rand_fbsd12(void); +int +__rand_fbsd12(void) +{ + return (do_rand(&next)); +} +__sym_compat(rand, __rand_fbsd12, FBSD_1.0); + +void __srand_fbsd12(unsigned seed); +void +__srand_fbsd12(unsigned seed) +{ + next = seed; +} +__sym_compat(srand, __srand_fbsd12, FBSD_1.0); + +void __sranddev_fbsd12(void); +void +__sranddev_fbsd12(void) +{ + static bool warned = false; + + if (!warned) { + syslog(LOG_DEBUG, "Deprecated function sranddev() called"); + warned = true; + } +} +__sym_compat(sranddev, __sranddev_fbsd12, FBSD_1.0); diff --git a/lib/libc/stdlib/random.3 b/lib/libc/stdlib/random.3 new file mode 100644 index 000000000000..b29536d4371d --- /dev/null +++ b/lib/libc/stdlib/random.3 @@ -0,0 +1,175 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. 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. +.\" 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. +.\" +.Dd February 1, 2020 +.Dt RANDOM 3 +.Os +.Sh NAME +.Nm random , +.Nm srandom , +.Nm srandomdev , +.Nm initstate , +.Nm setstate +.Nd non-cryptographic pseudorandom number generator; routines for changing generators +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft long +.Fn random void +.Ft void +.Fn srandom "unsigned int seed" +.Ft void +.Fn srandomdev void +.Ft char * +.Fn initstate "unsigned int seed" "char *state" "size_t n" +.Ft char * +.Fn setstate "char *state" +.Sh DESCRIPTION +.Bf -symbolic +The functions described in this manual page are not secure. +Applications which require unpredictable random numbers should use +.Xr arc4random 3 +instead. +.Ef +.Pp +Unless initialized with less than 32 bytes of state, the +.Fn random +function +uses a non-linear additive feedback random number generator employing a +default table of size 31 long integers to return successive pseudo-random +numbers in the range from 0 to +.if t 2\u\s731\s10\d\(mi1. +.if n (2**31)\(mi1. +The period of this random number generator is very large, approximately +.if t 16\(mu(2\u\s731\s10\d\(mi1). +.if n 16*((2**31)\(mi1). +.Pp +If initialized with less than 32 bytes of state, +.Fn random +uses the poor-quality 32-bit Park-Miller LCG. +.Pp +The +.Fn random +and +.Fn srandom +functions are analagous to +.Xr rand 3 +and +.Xr srand 3 . +.Pp +Like +.Xr rand 3 , +.Fn random +is implicitly initialized as if +.Fn srandom "1" +had been invoked explicitly. +.Pp +The +.Fn srandomdev +routine initializes the state array using random numbers obtained from the +kernel. +This can generate states which are impossible to reproduce by calling +.Fn srandom , +because the succeeding terms in the state buffer are no longer derived from the +Park-Miller LCG algorithm applied to a fixed seed. +.Pp +The +.Fn initstate +routine initializes the provided state array of +.Vt uint32_t +values and uses it in future +.Fn random +invocations. +(Despite the +.Vt char * +type of +.Fa state , +the underlying object must be a naturally aligned array of 32-bit values.) +The size of the state array (in bytes) is used by +.Fn initstate +to decide how sophisticated a random number generator it should use \(em the +more state, the better the random numbers will be. +(Current "optimal" values for the amount of state information are +8, 32, 64, 128, and 256 bytes; other amounts will be rounded down to +the nearest known amount. +Using less than 8 bytes will cause an error.) +The +.Fa seed +is used as in +.Fn srandom . +The +.Fn initstate +function +returns a pointer to the previous state information array. +.Pp +The +.Fn setstate +routine switches +.Fn random +to using the provided state. +It returns a pointer to the previous state. +.Pp +Once a state array has been initialized, it may be restarted at a +different point either by calling +.Fn initstate +(with the desired seed, the state array, and its size) or by calling +both +.Fn setstate +(with the state array) and +.Fn srandom +(with the desired seed). +The advantage of calling both +.Fn setstate +and +.Fn srandom +is that the size of the state array does not have to be remembered after +it is initialized. +.Pp +With 256 bytes of state information, the period of the random number +generator is greater than +.if t 2\u\s769\s10\d, +.if n 2**69 +which should be sufficient for most purposes. +.Sh DIAGNOSTICS +If +.Fn initstate +is called with less than 8 bytes of state information, or if +.Fn setstate +detects that the state information has been garbled, +NULL is returned. +.Sh SEE ALSO +.Xr arc4random 3 , +.Xr lrand48 3 , +.Xr rand 3 , +.Xr random 4 +.Sh HISTORY +These +functions appeared in +.Bx 4.2 . +.Sh AUTHORS +.An Earl T. Cohen diff --git a/lib/libc/stdlib/random.c b/lib/libc/stdlib/random.c new file mode 100644 index 000000000000..6e9702229da8 --- /dev/null +++ b/lib/libc/stdlib/random.c @@ -0,0 +1,501 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. 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. + * 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. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/sysctl.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include "un-namespace.h" + +#include "random.h" + +/* + * random.c: + * + * An improved random number generation package. In addition to the standard + * rand()/srand() like interface, this package also has a special state info + * interface. The initstate() routine is called with a seed, an array of + * bytes, and a count of how many bytes are being passed in; this array is + * then initialized to contain information for random number generation with + * that much state information. Good sizes for the amount of state + * information are 32, 64, 128, and 256 bytes. The state can be switched by + * calling the setstate() routine with the same array as was initiallized + * with initstate(). By default, the package runs with 128 bytes of state + * information and generates far better random numbers than a linear + * congruential generator. If the amount of state information is less than + * 32 bytes, a simple linear congruential R.N.G. is used. + * + * Internally, the state information is treated as an array of uint32_t's; the + * zeroeth element of the array is the type of R.N.G. being used (small + * integer); the remainder of the array is the state information for the + * R.N.G. Thus, 32 bytes of state information will give 7 ints worth of + * state information, which will allow a degree seven polynomial. (Note: + * the zeroeth word of state information also has some other information + * stored in it -- see setstate() for details). + * + * The random number generation technique is a linear feedback shift register + * approach, employing trinomials (since there are fewer terms to sum up that + * way). In this approach, the least significant bit of all the numbers in + * the state table will act as a linear feedback shift register, and will + * have period 2^deg - 1 (where deg is the degree of the polynomial being + * used, assuming that the polynomial is irreducible and primitive). The + * higher order bits will have longer periods, since their values are also + * influenced by pseudo-random carries out of the lower bits. The total + * period of the generator is approximately deg*(2**deg - 1); thus doubling + * the amount of state information has a vast influence on the period of the + * generator. Note: the deg*(2**deg - 1) is an approximation only good for + * large deg, when the period of the shift is the dominant factor. + * With deg equal to seven, the period is actually much longer than the + * 7*(2**7 - 1) predicted by this formula. + * + * Modified 28 December 1994 by Jacob S. Rosenberg. + * The following changes have been made: + * All references to the type u_int have been changed to unsigned long. + * All references to type int have been changed to type long. Other + * cleanups have been made as well. A warning for both initstate and + * setstate has been inserted to the effect that on Sparc platforms + * the 'arg_state' variable must be forced to begin on word boundaries. + * This can be easily done by casting a long integer array to char *. + * The overall logic has been left STRICTLY alone. This software was + * tested on both a VAX and Sun SpacsStation with exactly the same + * results. The new version and the original give IDENTICAL results. + * The new version is somewhat faster than the original. As the + * documentation says: "By default, the package runs with 128 bytes of + * state information and generates far better random numbers than a linear + * congruential generator. If the amount of state information is less than + * 32 bytes, a simple linear congruential R.N.G. is used." For a buffer of + * 128 bytes, this new version runs about 19 percent faster and for a 16 + * byte buffer it is about 5 percent faster. + */ + +#define NSHUFF 50 /* to drop some "seed -> 1st value" linearity */ + +static const int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; +static const int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; +static const int breaks[MAX_TYPES] = { + BREAK_0, BREAK_1, BREAK_2, BREAK_3, BREAK_4 +}; + +/* + * Initially, everything is set up as if from: + * + * initstate(1, randtbl, 128); + * + * Note that this initialization takes advantage of the fact that srandom() + * advances the front and rear pointers 10*rand_deg times, and hence the + * rear pointer which starts at 0 will also end up at zero; thus the zeroeth + * element of the state information, which contains info about the current + * position of the rear pointer is just + * + * MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3. + */ +static struct __random_state implicit = { + .rst_randtbl = { + TYPE_3, + 0x2cf41758, 0x27bb3711, 0x4916d4d1, 0x7b02f59f, 0x9b8e28eb, 0xc0e80269, + 0x696f5c16, 0x878f1ff5, 0x52d9c07f, 0x916a06cd, 0xb50b3a20, 0x2776970a, + 0xee4eb2a6, 0xe94640ec, 0xb1d65612, 0x9d1ed968, 0x1043f6b7, 0xa3432a76, + 0x17eacbb9, 0x3c09e2eb, 0x4f8c2b3, 0x708a1f57, 0xee341814, 0x95d0e4d2, + 0xb06f216c, 0x8bd2e72e, 0x8f7c38d7, 0xcfc6a8fc, 0x2a59495, 0xa20d2a69, + 0xe29d12d1 + }, + + /* + * fptr and rptr are two pointers into the state info, a front and a rear + * pointer. These two pointers are always rand_sep places aparts, as they + * cycle cyclically through the state information. (Yes, this does mean we + * could get away with just one pointer, but the code for random() is more + * efficient this way). The pointers are left positioned as they would be + * from the call + * + * initstate(1, randtbl, 128); + * + * (The position of the rear pointer, rptr, is really 0 (as explained above + * in the initialization of randtbl) because the state table pointer is set + * to point to randtbl[1] (as explained below). + */ + .rst_fptr = &implicit.rst_randtbl[SEP_3 + 1], + .rst_rptr = &implicit.rst_randtbl[1], + + /* + * The following things are the pointer to the state information table, the + * type of the current generator, the degree of the current polynomial being + * used, and the separation between the two pointers. Note that for efficiency + * of random(), we remember the first location of the state information, not + * the zeroeth. Hence it is valid to access state[-1], which is used to + * store the type of the R.N.G. Also, we remember the last location, since + * this is more efficient than indexing every time to find the address of + * the last element to see if the front and rear pointers have wrapped. + */ + .rst_state = &implicit.rst_randtbl[1], + .rst_type = TYPE_3, + .rst_deg = DEG_3, + .rst_sep = SEP_3, + .rst_end_ptr = &implicit.rst_randtbl[DEG_3 + 1], +}; + +/* + * This is the same low quality PRNG used in rand(3) in FreeBSD 12 and prior. + * It may be sufficient for distributing bits and expanding a small seed + * integer into a larger state. + */ +static inline uint32_t +parkmiller32(uint32_t ctx) +{ +/* + * Compute x = (7^5 * x) mod (2^31 - 1) + * wihout overflowing 31 bits: + * (2^31 - 1) = 127773 * (7^5) + 2836 + * From "Random number generators: good ones are hard to find", + * Park and Miller, Communications of the ACM, vol. 31, no. 10, + * October 1988, p. 1195. + */ + int32_t hi, lo, x; + + /* Transform to [1, 0x7ffffffe] range. */ + x = (ctx % 0x7ffffffe) + 1; + hi = x / 127773; + lo = x % 127773; + x = 16807 * lo - 2836 * hi; + if (x < 0) + x += 0x7fffffff; + /* Transform to [0, 0x7ffffffd] range. */ + return (x - 1); +} + +/* + * srandom: + * + * Initialize the random number generator based on the given seed. If the + * type is the trivial no-state-information type, just remember the seed. + * Otherwise, initializes state[] based on the given "seed" via a linear + * congruential generator. Then, the pointers are set to known locations + * that are exactly rand_sep places apart. Lastly, it cycles the state + * information a given number of times to get rid of any initial dependencies + * introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + * for default usage relies on values produced by this routine. + */ +void +srandom_r(struct __random_state *estate, unsigned x) +{ + int i, lim; + + estate->rst_state[0] = (uint32_t)x; + if (estate->rst_type == TYPE_0) + lim = NSHUFF; + else { + for (i = 1; i < estate->rst_deg; i++) + estate->rst_state[i] = + parkmiller32(estate->rst_state[i - 1]); + estate->rst_fptr = &estate->rst_state[estate->rst_sep]; + estate->rst_rptr = &estate->rst_state[0]; + lim = 10 * estate->rst_deg; + } + for (i = 0; i < lim; i++) + (void)random_r(estate); +} + +void +srandom(unsigned x) +{ + srandom_r(&implicit, x); +} + +/* + * srandomdev: + * + * Many programs choose the seed value in a totally predictable manner. + * This often causes problems. We seed the generator using pseudo-random + * data from the kernel. + * + * Note that this particular seeding procedure can generate states + * which are impossible to reproduce by calling srandom() with any + * value, since the succeeding terms in the state buffer are no longer + * derived from the LC algorithm applied to a fixed seed. + */ +void +srandomdev_r(struct __random_state *estate) +{ + int mib[2]; + size_t expected, len; + + if (estate->rst_type == TYPE_0) + len = sizeof(estate->rst_state[0]); + else + len = estate->rst_deg * sizeof(estate->rst_state[0]); + expected = len; + + mib[0] = CTL_KERN; + mib[1] = KERN_ARND; + if (sysctl(mib, 2, estate->rst_state, &len, NULL, 0) == -1 || + len != expected) { + /* + * The sysctl cannot fail. If it does fail on some FreeBSD + * derivative or after some future change, just abort so that + * the problem will be found and fixed. abort is not normally + * suitable for a library but makes sense here. + */ + abort(); + } + + if (estate->rst_type != TYPE_0) { + estate->rst_fptr = &estate->rst_state[estate->rst_sep]; + estate->rst_rptr = &estate->rst_state[0]; + } +} + +void +srandomdev(void) +{ + srandomdev_r(&implicit); +} + +/* + * initstate_r: + * + * Initialize the state information in the given array of n bytes for future + * random number generation. Based on the number of bytes we are given, and + * the break values for the different R.N.G.'s, we choose the best (largest) + * one we can and set things up for it. srandom() is then called to + * initialize the state information. + * + * Returns zero on success, or an error number on failure. + * + * Note: There is no need for a setstate_r(); just use a new context. + */ +int +initstate_r(struct __random_state *estate, unsigned seed, uint32_t *arg_state, + size_t sz) +{ + if (sz < BREAK_0) + return (EINVAL); + + if (sz < BREAK_1) { + estate->rst_type = TYPE_0; + estate->rst_deg = DEG_0; + estate->rst_sep = SEP_0; + } else if (sz < BREAK_2) { + estate->rst_type = TYPE_1; + estate->rst_deg = DEG_1; + estate->rst_sep = SEP_1; + } else if (sz < BREAK_3) { + estate->rst_type = TYPE_2; + estate->rst_deg = DEG_2; + estate->rst_sep = SEP_2; + } else if (sz < BREAK_4) { + estate->rst_type = TYPE_3; + estate->rst_deg = DEG_3; + estate->rst_sep = SEP_3; + } else { + estate->rst_type = TYPE_4; + estate->rst_deg = DEG_4; + estate->rst_sep = SEP_4; + } + estate->rst_state = arg_state + 1; + estate->rst_end_ptr = &estate->rst_state[estate->rst_deg]; + srandom_r(estate, seed); + return (0); +} + +/* + * initstate: + * + * Note: the first thing we do is save the current state, if any, just like + * setstate() so that it doesn't matter when initstate is called. + * + * Note that on return from initstate_r(), we set state[-1] to be the type + * multiplexed with the current value of the rear pointer; this is so + * successive calls to initstate() won't lose this information and will be able + * to restart with setstate(). + * + * Returns a pointer to the old state. + * + * Despite the misleading "char *" type, arg_state must alias an array of + * 32-bit unsigned integer values. Naturally, such an array is 32-bit aligned. + * Usually objects are naturally aligned to at least 32-bits on all platforms, + * but if you treat the provided 'state' as char* you may inadvertently + * misalign it. Don't do that. + */ +char * +initstate(unsigned int seed, char *arg_state, size_t n) +{ + char *ostate = (char *)(&implicit.rst_state[-1]); + uint32_t *int_arg_state = (uint32_t *)arg_state; + int error; + + /* + * Persist rptr offset and rst_type in the first word of the prior + * state we are replacing. + */ + if (implicit.rst_type == TYPE_0) + implicit.rst_state[-1] = implicit.rst_type; + else + implicit.rst_state[-1] = MAX_TYPES * + (implicit.rst_rptr - implicit.rst_state) + + implicit.rst_type; + + error = initstate_r(&implicit, seed, int_arg_state, n); + if (error != 0) + return (NULL); + + /* + * Persist rptr offset and rst_type of the new state in its first word. + */ + if (implicit.rst_type == TYPE_0) + int_arg_state[0] = implicit.rst_type; + else + int_arg_state[0] = MAX_TYPES * + (implicit.rst_rptr - implicit.rst_state) + + implicit.rst_type; + + return (ostate); +} + +/* + * setstate: + * + * Restore the state from the given state array. + * + * Note: it is important that we also remember the locations of the pointers + * in the current state information, and restore the locations of the pointers + * from the old state information. This is done by multiplexing the pointer + * location into the zeroeth word of the state information. + * + * Note that due to the order in which things are done, it is OK to call + * setstate() with the same state as the current state. + * + * Returns a pointer to the old state information. + * + * Note: The Sparc platform requires that arg_state begin on an int + * word boundary; otherwise a bus error will occur. Even so, lint will + * complain about mis-alignment, but you should disregard these messages. + */ +char * +setstate(char *arg_state) +{ + uint32_t *new_state = (uint32_t *)arg_state; + uint32_t type = new_state[0] % MAX_TYPES; + uint32_t rear = new_state[0] / MAX_TYPES; + char *ostate = (char *)(&implicit.rst_state[-1]); + + if (type != TYPE_0 && rear >= degrees[type]) + return (NULL); + if (implicit.rst_type == TYPE_0) + implicit.rst_state[-1] = implicit.rst_type; + else + implicit.rst_state[-1] = MAX_TYPES * + (implicit.rst_rptr - implicit.rst_state) + + implicit.rst_type; + implicit.rst_type = type; + implicit.rst_deg = degrees[type]; + implicit.rst_sep = seps[type]; + implicit.rst_state = new_state + 1; + if (implicit.rst_type != TYPE_0) { + implicit.rst_rptr = &implicit.rst_state[rear]; + implicit.rst_fptr = &implicit.rst_state[ + (rear + implicit.rst_sep) % implicit.rst_deg]; + } + implicit.rst_end_ptr = &implicit.rst_state[implicit.rst_deg]; + return (ostate); +} + +/* + * random: + * + * If we are using the trivial TYPE_0 R.N.G., just do the old linear + * congruential bit. Otherwise, we do our fancy trinomial stuff, which is + * the same in all the other cases due to all the global variables that have + * been set up. The basic operation is to add the number at the rear pointer + * into the one at the front pointer. Then both pointers are advanced to + * the next location cyclically in the table. The value returned is the sum + * generated, reduced to 31 bits by throwing away the "least random" low bit. + * + * Note: the code takes advantage of the fact that both the front and + * rear pointers can't wrap on the same call by not testing the rear + * pointer if the front one has wrapped. + * + * Returns a 31-bit random number. + */ +long +random_r(struct __random_state *estate) +{ + uint32_t i; + uint32_t *f, *r; + + if (estate->rst_type == TYPE_0) { + i = estate->rst_state[0]; + i = parkmiller32(i); + estate->rst_state[0] = i; + } else { + /* + * Use local variables rather than static variables for speed. + */ + f = estate->rst_fptr; + r = estate->rst_rptr; + *f += *r; + i = *f >> 1; /* chucking least random bit */ + if (++f >= estate->rst_end_ptr) { + f = estate->rst_state; + ++r; + } + else if (++r >= estate->rst_end_ptr) { + r = estate->rst_state; + } + + estate->rst_fptr = f; + estate->rst_rptr = r; + } + return ((long)i); +} + +long +random(void) +{ + return (random_r(&implicit)); +} + +struct __random_state * +allocatestate(unsigned type) +{ + size_t asize; + + /* No point using this interface to get the Park-Miller LCG. */ + if (type < TYPE_1) + abort(); + /* Clamp to widest supported variant. */ + if (type > (MAX_TYPES - 1)) + type = (MAX_TYPES - 1); + + asize = sizeof(struct __random_state) + (size_t)breaks[type]; + return (malloc(asize)); +} diff --git a/lib/libc/stdlib/random.h b/lib/libc/stdlib/random.h new file mode 100644 index 000000000000..c7d4f2c18b77 --- /dev/null +++ b/lib/libc/stdlib/random.h @@ -0,0 +1,83 @@ +/*- + * Copyright 2020 Conrad Meyer <cem@FreeBSD.org>. 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 AUTHOR 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 AUTHOR 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. + */ + +#pragma once + +/* + * For each of the currently supported random number generators, we have a + * break value on the amount of state information (you need at least this + * many bytes of state info to support this random number generator), a degree + * for the polynomial (actually a trinomial) that the R.N.G. is based on, and + * the separation between the two lower order coefficients of the trinomial. + */ +#define TYPE_0 0 /* linear congruential */ +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +#define TYPE_1 1 /* x**7 + x**3 + 1 */ +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +#define TYPE_2 2 /* x**15 + x + 1 */ +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +#define TYPE_3 3 /* x**31 + x**3 + 1 */ +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +#define TYPE_4 4 /* x**63 + x + 1 */ +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + +/* + * Array versions of the above information to make code run faster -- + * relies on fact that TYPE_i == i. + */ +#define MAX_TYPES 5 /* max number of types above */ + +/* A full instance of the random(3) generator. */ +struct __random_state { + uint32_t *rst_fptr; + uint32_t *rst_rptr; + uint32_t *rst_state; + int rst_type; + int rst_deg; + int rst_sep; + uint32_t *rst_end_ptr; + /* Flexible array member must be last. */ + uint32_t rst_randtbl[]; +}; + +struct __random_state *allocatestate(unsigned type); +int initstate_r(struct __random_state *, unsigned, uint32_t *, size_t); +long random_r(struct __random_state *); +void srandom_r(struct __random_state *, unsigned); +void srandomdev_r(struct __random_state *); diff --git a/lib/libc/stdlib/reallocarray.3 b/lib/libc/stdlib/reallocarray.3 new file mode 100644 index 000000000000..9a2ab5c7a840 --- /dev/null +++ b/lib/libc/stdlib/reallocarray.3 @@ -0,0 +1,179 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd October 2, 2025 +.Dt REALLOCARRAY 3 +.Os +.Sh NAME +.Nm reallocarray +.Nd memory reallocation function +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft void * +.Fn reallocarray "void *ptr" "size_t nmemb" "size_t size" +.Ft void * +.Fn recallocarray "void *ptr" "size_t oldnmeb" "size_t nmemb" size_t size" +.Sh DESCRIPTION +The +.Fn reallocarray +function is similar to the +.Fn realloc +function +except it operates on +.Fa nmemb +members of size +.Fa size +and checks for integer overflow in the calculation +.Fa nmemb +* +.Fa size . +.Pp +The +.Fn recallocarray +function is similar to the +.Fn reallocarray +function +except it ensures newly allocated memory is cleared similar to +.Fn calloc . +If +.Fa ptr +is +.Dv NULL , +.Fa oldnmemb +is ignored and the call is equivalent to +.Fn calloc . +If +.Fa ptr +is not +.Dv NULL , +.Fa oldnmemb +must be a value such that +.Fa oldnmemb +* +.Fa size +is the size of the earlier allocation that returned +.Fa ptr , +otherwise the behaviour is undefined. +.Sh RETURN VALUES +The +.Fn reallocarray +function returns a pointer to the allocated space; otherwise, a +.Dv NULL +pointer is returned and +.Va errno +is set to +.Er ENOMEM . +.Sh EXAMPLES +Consider +.Fn reallocarray +when there is multiplication in the +.Fa size +argument of +.Fn malloc +or +.Fn realloc . +For example, avoid this common idiom as it may lead to integer overflow: +.Bd -literal -offset indent +if ((p = malloc(num * size)) == NULL) + err(1, "malloc"); +.Ed +.Pp +A drop-in replacement is the +.Ox +extension +.Fn reallocarray : +.Bd -literal -offset indent +if ((p = reallocarray(NULL, num, size)) == NULL) + err(1, "reallocarray"); +.Ed +.Pp +When using +.Fn realloc , +be careful to avoid the following idiom: +.Bd -literal -offset indent +size += 50; +if ((p = realloc(p, size)) == NULL) + return (NULL); +.Ed +.Pp +Do not adjust the variable describing how much memory has been allocated +until the allocation has been successful. +This can cause aberrant program behavior if the incorrect size value is used. +In most cases, the above sample will also result in a leak of memory. +As stated earlier, a return value of +.Dv NULL +indicates that the old object still remains allocated. +Better code looks like this: +.Bd -literal -offset indent +newsize = size + 50; +if ((newp = realloc(p, newsize)) == NULL) { + free(p); + p = NULL; + size = 0; + return (NULL); +} +p = newp; +size = newsize; +.Ed +.Pp +As with +.Fn malloc , +it is important to ensure the new size value will not overflow; +i.e. avoid allocations like the following: +.Bd -literal -offset indent +if ((newp = realloc(p, num * size)) == NULL) { + ... +.Ed +.Pp +Instead, use +.Fn reallocarray : +.Bd -literal -offset indent +if ((newp = reallocarray(p, num, size)) == NULL) { + ... +.Ed +.Sh SEE ALSO +.Xr realloc 3 +.Sh STANDARDS +.Fn reallocarray +conforms to +.St -p1003.1-2024 . +.Sh HISTORY +The +.Fn reallocarray +function first appeared in +.Ox 5.6 +and +.Fx 11.0 . +The +.Fn recallocarray +function first appeared in +.Ox 6.1 +and +.Fx 16.0 . diff --git a/lib/libc/stdlib/reallocarray.c b/lib/libc/stdlib/reallocarray.c new file mode 100644 index 000000000000..3632734c84de --- /dev/null +++ b/lib/libc/stdlib/reallocarray.c @@ -0,0 +1,35 @@ +/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */ +/* + * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <errno.h> +#include <stdckdint.h> +#include <stdint.h> +#include <stdlib.h> + +void * +reallocarray(void *optr, size_t nmemb, size_t size) +{ + size_t nbytes; + + if (ckd_mul(&nbytes, nmemb, size)) { + errno = ENOMEM; + return (NULL); + } + + return (realloc(optr, nbytes)); +} diff --git a/lib/libc/stdlib/reallocf.3 b/lib/libc/stdlib/reallocf.3 new file mode 100644 index 000000000000..647f213522f1 --- /dev/null +++ b/lib/libc/stdlib/reallocf.3 @@ -0,0 +1,79 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd January 31, 2010 +.Dt MALLOC 3 +.Os +.Sh NAME +.Nm reallocf +.Nd memory reallocation function +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft void * +.Fn reallocf "void *ptr" "size_t size" +.Sh DESCRIPTION +The +.Fn reallocf +function is identical to the +.Fn realloc +function, except that it +will free the passed pointer when the requested memory cannot be allocated. +This is a +.Fx +specific API designed to ease the problems with traditional coding styles +for +.Fn realloc +causing memory leaks in libraries. +.Sh RETURN VALUES +The +.Fn reallocf +function returns a pointer, possibly identical to +.Fa ptr , +to the allocated memory +if successful; otherwise a +.Dv NULL +pointer is returned, and +.Va errno +is set to +.Er ENOMEM +if the error was the result of an allocation failure. +The +.Fn reallocf +function deletes the original buffer when an error occurs. +.Sh SEE ALSO +.Xr realloc 3 +.Sh HISTORY +The +.Fn reallocf +function first appeared in +.Fx 3.0 . diff --git a/lib/libc/stdlib/reallocf.c b/lib/libc/stdlib/reallocf.c new file mode 100644 index 000000000000..3ab90bfdf471 --- /dev/null +++ b/lib/libc/stdlib/reallocf.c @@ -0,0 +1,46 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1998 M. Warner Losh <imp@FreeBSD.org> + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <stdlib.h> + +void * +reallocf(void *ptr, size_t size) +{ + void *nptr; + + nptr = realloc(ptr, size); + + /* + * When the System V compatibility option (malloc "V" flag) is + * in effect, realloc(ptr, 0) frees the memory and returns NULL. + * So, to avoid double free, call free() only when size != 0. + * realloc(ptr, 0) can't fail when ptr != NULL. + */ + if (!nptr && ptr && size != 0) + free(ptr); + return (nptr); +} diff --git a/lib/libc/stdlib/realpath.3 b/lib/libc/stdlib/realpath.3 new file mode 100644 index 000000000000..065ba312c2ef --- /dev/null +++ b/lib/libc/stdlib/realpath.3 @@ -0,0 +1,132 @@ +.\" Copyright (c) 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Jan-Simon Pendry. +.\" +.\" 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. +.\" +.Dd May 11, 2012 +.Dt REALPATH 3 +.Os +.Sh NAME +.Nm realpath +.Nd returns the canonicalized absolute pathname +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft "char *" +.Fn realpath "const char * restrict pathname" "char * restrict resolved_path" +.Sh DESCRIPTION +The +.Fn realpath +function resolves all symbolic links, extra +.Dq / +characters and references to +.Pa /./ +and +.Pa /../ +in +.Fa pathname , +and copies the resulting absolute pathname into +the memory pointed to by +.Fa resolved_path . +The +.Fa resolved_path +argument +.Em must +point to a buffer capable of storing at least +.Dv PATH_MAX +characters, or be +.Dv NULL . +.Pp +The +.Fn realpath +function will resolve both absolute and relative paths +and return the absolute pathname corresponding to +.Fa pathname . +All components of +.Fa pathname +must exist when +.Fn realpath +is called, and all but the last component must name either directories or +symlinks pointing to the directories. +.Sh "RETURN VALUES" +The +.Fn realpath +function returns +.Fa resolved_path +on success. +If the function was supplied +.Dv NULL +as +.Fa resolved_path , +and operation did not cause errors, the returned value is +a null-terminated string in a buffer allocated by a call to +.Fn malloc 3 . +If an error occurs, +.Fn realpath +returns +.Dv NULL , +and if +.Fa resolved_path +is not +.Dv NULL , +the array that it points to contains the pathname which caused the problem. +.Sh ERRORS +The function +.Fn realpath +may fail and set the external variable +.Va errno +for any of the errors specified for the library functions +.Xr lstat 2 , +.Xr readlink 2 +and +.Xr getcwd 3 . +.Sh SEE ALSO +.Xr getcwd 3 +.\" .Sh STANDARDS +.\" The +.\" .Fn realpath +.\" function conforms to +.\" .St -p1003.1-2001 . +.Sh HISTORY +The +.Fn realpath +function first appeared in +.Bx 4.4 . +.Sh CAVEATS +This implementation of +.Fn realpath +differs slightly from the Solaris implementation. +The +.Bx 4.4 +version always returns absolute pathnames, +whereas the Solaris implementation will, +under certain circumstances, return a relative +.Fa resolved_path +when given a relative +.Fa pathname . diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c new file mode 100644 index 000000000000..4c52b73319ab --- /dev/null +++ b/lib/libc/stdlib/realpath.c @@ -0,0 +1,229 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru> + * + * 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. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <errno.h> +#include <fcntl.h> +#include <libsys.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ssp/ssp.h> + +/* + * Find the real name of path, by removing all ".", ".." and symlink + * components. Returns (resolved) on success, or (NULL) on failure, + * in which case the path which caused trouble is left in (resolved). + */ +static char * __noinline +realpath1(const char *path, char *resolved) +{ + struct stat sb; + char *p, *q; + size_t left_len, resolved_len, next_token_len; + unsigned symlinks; + ssize_t slen; + char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; + + symlinks = 0; + if (path[0] == '/') { + resolved[0] = '/'; + resolved[1] = '\0'; + if (path[1] == '\0') + return (resolved); + resolved_len = 1; + left_len = strlcpy(left, path + 1, sizeof(left)); + } else { + if (getcwd(resolved, PATH_MAX) == NULL) { + resolved[0] = '.'; + resolved[1] = '\0'; + return (NULL); + } + resolved_len = strlen(resolved); + left_len = strlcpy(left, path, sizeof(left)); + } + if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { + errno = ENAMETOOLONG; + return (NULL); + } + + /* + * Iterate over path components in `left'. + */ + while (left_len != 0) { + /* + * Extract the next path component and adjust `left' + * and its length. + */ + p = strchr(left, '/'); + + next_token_len = p != NULL ? (size_t)(p - left) : left_len; + memcpy(next_token, left, next_token_len); + next_token[next_token_len] = '\0'; + + if (p != NULL) { + left_len -= next_token_len + 1; + memmove(left, p + 1, left_len + 1); + } else { + left[0] = '\0'; + left_len = 0; + } + + if (resolved[resolved_len - 1] != '/') { + if (resolved_len + 1 >= PATH_MAX) { + errno = ENAMETOOLONG; + return (NULL); + } + resolved[resolved_len++] = '/'; + resolved[resolved_len] = '\0'; + } + if (next_token[0] == '\0') { + /* Handle consequential slashes. */ + continue; + } else if (strcmp(next_token, ".") == 0) { + continue; + } else if (strcmp(next_token, "..") == 0) { + /* + * Strip the last path component except when we have + * single "/" + */ + if (resolved_len > 1) { + resolved[resolved_len - 1] = '\0'; + q = strrchr(resolved, '/') + 1; + *q = '\0'; + resolved_len = q - resolved; + } + continue; + } + + /* + * Append the next path component and lstat() it. + */ + resolved_len = strlcat(resolved, next_token, PATH_MAX); + if (resolved_len >= PATH_MAX) { + errno = ENAMETOOLONG; + return (NULL); + } + if (lstat(resolved, &sb) != 0) + return (NULL); + if (S_ISLNK(sb.st_mode)) { + if (symlinks++ > MAXSYMLINKS) { + errno = ELOOP; + return (NULL); + } + slen = readlink(resolved, symlink, sizeof(symlink)); + if (slen < 0) + return (NULL); + if (slen == 0) { + errno = ENOENT; + return (NULL); + } + if ((size_t)slen >= sizeof(symlink)) { + errno = ENAMETOOLONG; + return (NULL); + } + symlink[slen] = '\0'; + if (symlink[0] == '/') { + resolved[1] = 0; + resolved_len = 1; + } else { + /* Strip the last path component. */ + q = strrchr(resolved, '/') + 1; + *q = '\0'; + resolved_len = q - resolved; + } + + /* + * If there are any path components left, then + * append them to symlink. The result is placed + * in `left'. + */ + if (p != NULL) { + if (symlink[slen - 1] != '/') { + if ((size_t)slen + 1 >= sizeof(symlink)) { + errno = ENAMETOOLONG; + return (NULL); + } + symlink[slen] = '/'; + symlink[slen + 1] = 0; + } + left_len = strlcat(symlink, left, + sizeof(symlink)); + if (left_len >= sizeof(symlink)) { + errno = ENAMETOOLONG; + return (NULL); + } + } + left_len = strlcpy(left, symlink, sizeof(left)); + } else if (!S_ISDIR(sb.st_mode) && p != NULL) { + errno = ENOTDIR; + return (NULL); + } + } + + /* + * Remove trailing slash except when the resolved pathname + * is a single "/". + */ + if (resolved_len > 1 && resolved[resolved_len - 1] == '/') + resolved[resolved_len - 1] = '\0'; + return (resolved); +} + +char * +__ssp_real(realpath)(const char * __restrict path, char * __restrict resolved) +{ + char *m, *res; + + if (path == NULL) { + errno = EINVAL; + return (NULL); + } + if (path[0] == '\0') { + errno = ENOENT; + return (NULL); + } + if (resolved != NULL) { + m = NULL; + } else { + m = resolved = malloc(PATH_MAX); + if (resolved == NULL) + return (NULL); + } + if (__sys___realpathat(AT_FDCWD, path, resolved, PATH_MAX, 0) == 0) { + return (resolved); + } + res = realpath1(path, resolved); + if (res == NULL) + free(m); + return (res); +} diff --git a/lib/libc/stdlib/recallocarray.c b/lib/libc/stdlib/recallocarray.c new file mode 100644 index 000000000000..cbf1fb2470cf --- /dev/null +++ b/lib/libc/stdlib/recallocarray.c @@ -0,0 +1,73 @@ +/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */ +/* + * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <errno.h> +#include <stdckdint.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +void *recallocarray(void *, size_t, size_t, size_t); + +void * +recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) +{ + size_t oldsize, newsize; + void *newptr; + + if (ptr == NULL) + return calloc(newnmemb, size); + + if (ckd_mul(&newsize, newnmemb, size)) { + errno = ENOMEM; + return NULL; + } + + if (ckd_mul(&oldsize, oldnmemb, size)) { + errno = EINVAL; + return NULL; + } + + /* + * Don't bother too much if we're shrinking just a bit, + * we do not shrink for series of small steps, oh well. + */ + if (newsize <= oldsize) { + size_t d = oldsize - newsize; + + if (d < oldsize / 2 && d < (size_t)getpagesize()) { + memset((char *)ptr + newsize, 0, d); + return ptr; + } + } + + newptr = malloc(newsize); + if (newptr == NULL) + return NULL; + + if (newsize > oldsize) { + memcpy(newptr, ptr, oldsize); + memset((char *)newptr + oldsize, 0, newsize - oldsize); + } else + memcpy(newptr, ptr, newsize); + + explicit_bzero(ptr, oldsize); + free(ptr); + + return newptr; +} diff --git a/lib/libc/stdlib/remque.c b/lib/libc/stdlib/remque.c new file mode 100644 index 000000000000..1b532ce11ff6 --- /dev/null +++ b/lib/libc/stdlib/remque.c @@ -0,0 +1,27 @@ +/* + * Initial implementation: + * Copyright (c) 2002 Robert Drehmel + * All rights reserved. + * + * As long as the above copyright statement and this notice remain + * unchanged, you can do what ever you want with this file. + */ +#define _SEARCH_PRIVATE +#include <search.h> +#include <stdlib.h> /* for NULL */ + +void +remque(void *element) +{ + struct que_elem *prev, *next, *elem; + + elem = (struct que_elem *)element; + + prev = elem->prev; + next = elem->next; + + if (prev != NULL) + prev->next = next; + if (next != NULL) + next->prev = prev; +} 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 000000000000..0860465c1eb6 --- /dev/null +++ b/lib/libc/stdlib/set_constraint_handler_s.3 @@ -0,0 +1,147 @@ +.\" 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. +.\" +.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 000000000000..298c4d94a4b9 --- /dev/null +++ b/lib/libc/stdlib/set_constraint_handler_s.c @@ -0,0 +1,98 @@ +/*- + * 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. + */ + +#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/lib/libc/stdlib/strfmon.3 b/lib/libc/stdlib/strfmon.3 new file mode 100644 index 000000000000..20cc560d401d --- /dev/null +++ b/lib/libc/stdlib/strfmon.3 @@ -0,0 +1,216 @@ +.\" Copyright (c) 2001 Jeroen Ruigrok van der Werven <asmodai@FreeBSD.org> +.\" 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. +.\" +.Dd December 6, 2023 +.Dt STRFMON 3 +.Os +.Sh NAME +.Nm strfmon , +.Nm strfmon_l +.Nd convert monetary value to string +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In monetary.h +.Ft ssize_t +.Fn strfmon "char * restrict s" "size_t maxsize" "const char * restrict format" "..." +.In monetary.h +.In xlocale.h +.Ft ssize_t +.Fn strfmon_l "char * restrict s" "size_t maxsize" "locale_t loc" "const char * restrict format" "..." +.Sh DESCRIPTION +The +.Fn strfmon +function places characters into the array pointed to by +.Fa s , +as controlled by the string pointed to by +.Fa format . +No more than +.Fa maxsize +bytes are placed into the array. +.Pp +The +.Fn strfmon_l +function takes an explicit locale argument, whereas the +.Fn strfmon +function uses the current global or per-thread locale. +.Pp +The format string is composed of zero or more directives: +ordinary characters (not +.Cm % ) , +which are copied unchanged to the output stream; and conversion +specifications, each of which results in fetching zero or more subsequent +arguments. +Each conversion specification is introduced by the +.Cm % +character. +After the +.Cm % , +the following appear in sequence: +.Bl -bullet +.It +Zero or more of the following flags: +.Bl -tag -width "XXX" +.It Cm = Ns Ar f +A +.Sq Cm = +character followed by another character +.Ar f +which is used as the numeric fill character. +.It Cm ^ +Do not use grouping characters, regardless of the current locale default. +.It Cm + +Represent positive values by prefixing them with a positive sign, +and negative values by prefixing them with a negative sign. +This is the default. +.It Cm \&( +Enclose negative values in parentheses. +.It Cm \&! +Do not include a currency symbol in the output. +.It Cm \- +Left justify the result. +Only valid when a field width is specified. +.El +.It +An optional minimum field width as a decimal number. +By default, there is no minimum width. +.It +A +.Sq Cm # +sign followed by a decimal number specifying the maximum +expected number of digits before the radix character. +When this option is used, values that do not exceed the +specified number of digits are formatted so they will be +correctly aligned with other values printed using the same +format. +This includes always leaving space for a possible sign +indicator, even if none is needed for a particular value. +.It +A +.Sq Cm \&. +character followed by a decimal number specifying the number +of digits after the radix character. +.It +One of the following conversion specifiers: +.Bl -tag -width "XXX" +.It Cm i +The +.Vt double +argument is formatted as an international monetary amount. +.It Cm n +The +.Vt double +argument is formatted as a national monetary amount. +.It Cm % +A +.Sq Li % +character is written. +.El +.El +.Sh RETURN VALUES +If the total number of resulting bytes, including the terminating +.Dv NUL +byte, is not more than +.Fa maxsize , +.Fn strfmon +and +.Fn strfmon_l +return the number of bytes placed into the array pointed to by +.Fa s , +not including the terminating +.Dv NUL +byte. +Otherwise, \-1 is returned, +the contents of the array are indeterminate, +and +.Va errno +is set to indicate the error. +.Sh EXAMPLES +The following example will format the value +.Dq Li 1234567.89 +to the string +.Dq Li $1,234,567.89 : +.Bd -literal -offset indent +#include <stdio.h> +#include <monetary.h> +#include <locale.h> + +int +main(void) +{ + char string[100]; + double money = 1234567.89; + + if (setlocale(LC_MONETARY, "en_US.UTF-8") == NULL) { + fprintf(stderr, "Unable to setlocale().\\n"); + return (1); + } + + strfmon(string, sizeof(string) - 1, "%n", money); + printf("%s\\n", string); + + return (0); +} +.Ed +.Sh ERRORS +The +.Fn strfmon +function will fail if: +.Bl -tag -width Er +.It Bq Er E2BIG +Conversion stopped due to lack of space in the buffer. +.It Bq Er EINVAL +The format string is invalid. +.It Bq Er ENOMEM +Not enough memory for temporary buffers. +.El +.Sh SEE ALSO +.Xr localeconv 3 , +.Xr xlocale 3 +.Sh STANDARDS +The +.Fn strfmon +function +conforms to +.St -p1003.1-2001 . +The +.Fn strfmon_l +function conforms to +.St -p1003.1-2008 . +.Sh AUTHORS +.An -nosplit +The +.Fn strfmon +function was implemented by +.An Alexey Zelkin Aq Mt phantom@FreeBSD.org . +.Pp +This manual page was written by +.An Jeroen Ruigrok van der Werven Aq Mt asmodai@FreeBSD.org +based on the standards' text. +.Sh BUGS +The +.Fn strfmon +function does not correctly handle multibyte characters in the +.Fa format +argument. diff --git a/lib/libc/stdlib/strfmon.c b/lib/libc/stdlib/strfmon.c new file mode 100644 index 000000000000..68a36a6d5567 --- /dev/null +++ b/lib/libc/stdlib/strfmon.c @@ -0,0 +1,667 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org> + * All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * 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 AUTHOR 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 AUTHOR 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. + * + */ + +#include <sys/types.h> + +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <locale.h> +#include <monetary.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "xlocale_private.h" + +/* internal flags */ +#define NEED_GROUPING 0x01 /* print digits grouped (default) */ +#define SIGN_POSN_USED 0x02 /* '+' or '(' usage flag */ +#define LOCALE_POSN 0x04 /* use locale defined +/- (default) */ +#define PARENTH_POSN 0x08 /* enclose negative amount in () */ +#define SUPPRESS_CURR_SYMBOL 0x10 /* suppress the currency from output */ +#define LEFT_JUSTIFY 0x20 /* left justify */ +#define USE_INTL_CURRENCY 0x40 /* use international currency symbol */ +#define IS_NEGATIVE 0x80 /* is argument value negative ? */ + +/* internal macros */ +#define PRINT(CH) do { \ + if (dst >= s + maxsize) \ + goto e2big_error; \ + *dst++ = CH; \ +} while (0) + +#define PRINTS(STR) do { \ + char *tmps = STR; \ + while (*tmps != '\0') \ + PRINT(*tmps++); \ +} while (0) + +#define GET_NUMBER(VAR, LOC) do { \ + VAR = 0; \ + while (isdigit_l((unsigned char)*fmt, LOC)) { \ + if (VAR > INT_MAX / 10) \ + goto e2big_error; \ + VAR *= 10; \ + VAR += *fmt - '0'; \ + if (VAR < 0) \ + goto e2big_error; \ + fmt++; \ + } \ +} while (0) + +#define GRPCPY(howmany) do { \ + int i = howmany; \ + while (i-- > 0) { \ + avalue_size--; \ + *--bufend = *(avalue + avalue_size + padded); \ + } \ +} while (0) + +#define GRPSEP do { \ + bufend -= thousands_sep_size; \ + memcpy(bufend, thousands_sep, thousands_sep_size); \ + groups++; \ +} while (0) + +static void __setup_vars(int, char *, char *, char *, char **, struct lconv *); +static int __calc_left_pad(int, char *, struct lconv *); +static char *__format_grouped_double(double, int *, int, int, int, + struct lconv *, locale_t); + +static ssize_t +vstrfmon_l(char *__restrict s, size_t maxsize, locale_t loc, + const char *__restrict format, va_list ap) +{ + char *dst; /* output destination pointer */ + const char *fmt; /* current format poistion pointer */ + struct lconv *lc; /* pointer to lconv structure */ + char *asciivalue; /* formatted double pointer */ + + int flags; /* formatting options */ + int pad_char; /* padding character */ + int pad_size; /* pad size */ + int width; /* field width */ + int left_prec; /* left precision */ + int right_prec; /* right precision */ + double value; /* just value */ + char space_char = ' '; /* space after currency */ + + char cs_precedes, /* values gathered from struct lconv */ + sep_by_space, + sign_posn, + *signstr, + *currency_symbol; + + char *tmpptr; /* temporary vars */ + int sverrno; + + FIX_LOCALE(loc); + + lc = localeconv_l(loc); + dst = s; + fmt = format; + asciivalue = NULL; + currency_symbol = NULL; + + while (*fmt != 0) { + /* pass nonformating characters AS IS */ + if (*fmt != '%') + goto literal; + + /* '%' found ! */ + + /* "%%" mean just '%' */ + if (*(fmt + 1) == '%') { + fmt++; +literal: + PRINT(*fmt++); + continue; + } + + /* set up initial values */ + flags = NEED_GROUPING | LOCALE_POSN; + pad_char = ' '; /* padding character is "space" */ + pad_size = 0; /* no padding initially */ + left_prec = -1; /* no left precision specified */ + right_prec = -1; /* no right precision specified */ + width = -1; /* no width specified */ + + /* Flags */ + while (1) { + switch (*++fmt) { + case '=': /* fill character */ + pad_char = *++fmt; + if (pad_char == '\0') + goto format_error; + continue; + case '^': /* not group currency */ + flags &= ~(NEED_GROUPING); + continue; + case '+': /* use locale defined signs */ + if (flags & SIGN_POSN_USED) + goto format_error; + flags |= (SIGN_POSN_USED | LOCALE_POSN); + continue; + case '(': /* enclose negatives with () */ + if (flags & SIGN_POSN_USED) + goto format_error; + flags |= (SIGN_POSN_USED | PARENTH_POSN); + continue; + case '!': /* suppress currency symbol */ + flags |= SUPPRESS_CURR_SYMBOL; + continue; + case '-': /* alignment (left) */ + flags |= LEFT_JUSTIFY; + continue; + default: + break; + } + break; + } + + /* field Width */ + if (isdigit_l((unsigned char)*fmt, loc)) { + GET_NUMBER(width, loc); + /* + * Do we have enough space to put number with + * required width ? + */ + if ((unsigned int)width >= maxsize - (dst - s)) + goto e2big_error; + } + + /* Left precision */ + if (*fmt == '#') { + if (!isdigit_l((unsigned char)*++fmt, loc)) + goto format_error; + GET_NUMBER(left_prec, loc); + if ((unsigned int)left_prec >= maxsize - (dst - s)) + goto e2big_error; + } + + /* Right precision */ + if (*fmt == '.') { + if (!isdigit_l((unsigned char)*++fmt, loc)) + goto format_error; + GET_NUMBER(right_prec, loc); + if ((unsigned int)right_prec >= + maxsize - (dst - s) - left_prec) + goto e2big_error; + } + + /* Conversion Characters */ + switch (*fmt++) { + case 'i': /* use international currency format */ + flags |= USE_INTL_CURRENCY; + break; + case 'n': /* use national currency format */ + flags &= ~(USE_INTL_CURRENCY); + break; + default: /* + * required character is missing or + * premature EOS + */ + goto format_error; + } + + if (currency_symbol != NULL) + free(currency_symbol); + if (flags & USE_INTL_CURRENCY) { + currency_symbol = strdup(lc->int_curr_symbol); + if (currency_symbol != NULL && + strlen(currency_symbol) > 3) { + space_char = currency_symbol[3]; + currency_symbol[3] = '\0'; + } + } else + currency_symbol = strdup(lc->currency_symbol); + + if (currency_symbol == NULL) + goto end_error; /* ENOMEM. */ + + /* value itself */ + value = va_arg(ap, double); + + /* detect sign */ + if (value < 0) { + flags |= IS_NEGATIVE; + value = -value; + } + + /* fill left_prec with amount of padding chars */ + if (left_prec >= 0) { + pad_size = __calc_left_pad((flags ^ IS_NEGATIVE), + currency_symbol, lc) - + __calc_left_pad(flags, currency_symbol, lc); + if (pad_size < 0) + pad_size = 0; + } + + if (asciivalue != NULL) + free(asciivalue); + asciivalue = __format_grouped_double(value, &flags, left_prec, + right_prec, pad_char, lc, loc); + if (asciivalue == NULL) + goto end_error; /* + * errno already set to ENOMEM by + * malloc() + */ + + /* set some variables for later use */ + __setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn, + &signstr, lc); + + /* + * Description of some LC_MONETARY's values: + * + * p_cs_precedes & n_cs_precedes + * + * = 1 - $currency_symbol precedes the value + * for a monetary quantity with a non-negative value + * = 0 - symbol succeeds the value + * + * p_sep_by_space & n_sep_by_space + * + * = 0 - no space separates $currency_symbol + * from the value for a monetary quantity with a + * non-negative value + * = 1 - space separates the symbol from the value + * = 2 - space separates the symbol and the sign string, + * if adjacent; otherwise, a space separates + * the sign string from the value + * + * p_sign_posn & n_sign_posn + * + * = 0 - parentheses enclose the quantity and the + * $currency_symbol + * = 1 - the sign string precedes the quantity and the + * $currency_symbol + * = 2 - the sign string succeeds the quantity and the + * $currency_symbol + * = 3 - the sign string precedes the $currency_symbol + * = 4 - the sign string succeeds the $currency_symbol + */ + + tmpptr = dst; + + while (pad_size-- > 0) + PRINT(' '); + + if (sign_posn == 0 && (flags & IS_NEGATIVE)) + PRINT('('); + + if (cs_precedes == 1) { + if (sign_posn == 1 || sign_posn == 3) { + PRINTS(signstr); + if (sep_by_space == 2) + PRINT(' '); + } + + if (!(flags & SUPPRESS_CURR_SYMBOL)) { + PRINTS(currency_symbol); + + if (sign_posn == 4) { + if (sep_by_space == 2) + PRINT(space_char); + PRINTS(signstr); + if (sep_by_space == 1) + PRINT(' '); + } else if (sep_by_space == 1) + PRINT(space_char); + } + } else if (sign_posn == 1) { + PRINTS(signstr); + if (sep_by_space == 2) + PRINT(' '); + } + + PRINTS(asciivalue); + + if (cs_precedes == 0) { + if (sign_posn == 3) { + if (sep_by_space == 1) + PRINT(' '); + PRINTS(signstr); + } + + if (!(flags & SUPPRESS_CURR_SYMBOL)) { + if ((sign_posn == 3 && sep_by_space == 2) || + (sep_by_space == 1 && + (sign_posn == 0 || sign_posn == 1 || + sign_posn == 2 || sign_posn == 4))) + PRINT(space_char); + PRINTS(currency_symbol); + if (sign_posn == 4) { + if (sep_by_space == 2) + PRINT(' '); + PRINTS(signstr); + } + } + } + + if (sign_posn == 2) { + if (sep_by_space == 2) + PRINT(' '); + PRINTS(signstr); + } + + if (sign_posn == 0) { + if (flags & IS_NEGATIVE) + PRINT(')'); + else if (left_prec >= 0) + PRINT(' '); + } + + if (dst - tmpptr < width) { + if (flags & LEFT_JUSTIFY) { + while (dst - tmpptr < width) + PRINT(' '); + } else { + pad_size = dst - tmpptr; + memmove(tmpptr + width - pad_size, tmpptr, + pad_size); + memset(tmpptr, ' ', width - pad_size); + dst += width - pad_size; + } + } + } + + PRINT('\0'); + free(asciivalue); + free(currency_symbol); + return (dst - s - 1); /* size of put data except trailing '\0' */ + +e2big_error: + errno = E2BIG; + goto end_error; + +format_error: + errno = EINVAL; + +end_error: + sverrno = errno; + if (asciivalue != NULL) + free(asciivalue); + if (currency_symbol != NULL) + free(currency_symbol); + errno = sverrno; + return (-1); +} + +static void +__setup_vars(int flags, char *cs_precedes, char *sep_by_space, char *sign_posn, + char **signstr, struct lconv *lc) +{ + if ((flags & IS_NEGATIVE) && (flags & USE_INTL_CURRENCY)) { + *cs_precedes = lc->int_n_cs_precedes; + *sep_by_space = lc->int_n_sep_by_space; + *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_n_sign_posn; + *signstr = (lc->negative_sign[0] == '\0') ? "-" : + lc->negative_sign; + } else if (flags & USE_INTL_CURRENCY) { + *cs_precedes = lc->int_p_cs_precedes; + *sep_by_space = lc->int_p_sep_by_space; + *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_p_sign_posn; + *signstr = lc->positive_sign; + } else if (flags & IS_NEGATIVE) { + *cs_precedes = lc->n_cs_precedes; + *sep_by_space = lc->n_sep_by_space; + *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->n_sign_posn; + *signstr = (lc->negative_sign[0] == '\0') ? "-" : + lc->negative_sign; + } else { + *cs_precedes = lc->p_cs_precedes; + *sep_by_space = lc->p_sep_by_space; + *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->p_sign_posn; + *signstr = lc->positive_sign; + } + + /* Set default values for unspecified information. */ + if (*cs_precedes != 0) + *cs_precedes = 1; + if (*sep_by_space == CHAR_MAX) + *sep_by_space = 0; + if (*sign_posn == CHAR_MAX) + *sign_posn = 0; +} + +static int +__calc_left_pad(int flags, char *cur_symb, struct lconv *lc) +{ + char cs_precedes, sep_by_space, sign_posn, *signstr; + int left_chars = 0; + + __setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn, &signstr, + lc); + + if (cs_precedes != 0) { + left_chars += strlen(cur_symb); + if (sep_by_space != 0) + left_chars++; + } + + switch (sign_posn) { + case 0: + if (flags & IS_NEGATIVE) + left_chars++; + break; + case 1: + left_chars += strlen(signstr); + break; + case 3: + case 4: + if (cs_precedes != 0) + left_chars += strlen(signstr); + } + return (left_chars); +} + +static int +get_groups(int size, char *grouping) +{ + int chars = 0; + + if (*grouping == CHAR_MAX || *grouping <= 0) /* no grouping ? */ + return (0); + + while (size > (int)*grouping) { + chars++; + size -= (int)*grouping++; + /* no more grouping ? */ + if (*grouping == CHAR_MAX) + break; + /* rest grouping with same value ? */ + if (*grouping == 0) { + chars += (size - 1) / *(grouping - 1); + break; + } + } + return (chars); +} + +/* convert double to locale-encoded string */ +static char * +__format_grouped_double(double value, int *flags, int left_prec, int right_prec, + int pad_char, struct lconv *lc, locale_t loc) +{ + + char *rslt; + char *avalue; + int avalue_size; + + size_t bufsize; + char *bufend; + + int padded; + + char *grouping; + const char *decimal_point; + const char *thousands_sep; + size_t decimal_point_size; + size_t thousands_sep_size; + + int groups = 0; + + grouping = lc->mon_grouping; + decimal_point = lc->mon_decimal_point; + if (*decimal_point == '\0') + decimal_point = lc->decimal_point; + thousands_sep = lc->mon_thousands_sep; + if (*thousands_sep == '\0') + thousands_sep = lc->thousands_sep; + + decimal_point_size = strlen(decimal_point); + thousands_sep_size = strlen(thousands_sep); + + /* fill left_prec with default value */ + if (left_prec == -1) + left_prec = 0; + + /* fill right_prec with default value */ + if (right_prec == -1) { + if (*flags & USE_INTL_CURRENCY) + right_prec = lc->int_frac_digits; + else + right_prec = lc->frac_digits; + + if (right_prec == CHAR_MAX) /* POSIX locale ? */ + right_prec = 2; + } + + if (*flags & NEED_GROUPING) + left_prec += get_groups(left_prec, grouping); + + /* convert to string */ + avalue_size = asprintf_l(&avalue, loc, "%*.*f", + left_prec + right_prec + 1, right_prec, value); + if (avalue_size < 0) + return (NULL); + + /* make sure that we've enough space for result string */ + bufsize = avalue_size * (1 + thousands_sep_size) + decimal_point_size + + 1; + rslt = calloc(1, bufsize); + if (rslt == NULL) { + free(avalue); + return (NULL); + } + bufend = rslt + bufsize - 1; /* reserve space for trailing '\0' */ + + /* skip spaces at beginning */ + padded = 0; + while (avalue[padded] == ' ') { + padded++; + avalue_size--; + } + + if (right_prec > 0) { + bufend -= right_prec; + memcpy(bufend, avalue + avalue_size + padded - right_prec, + right_prec); + bufend -= decimal_point_size; + memcpy(bufend, decimal_point, decimal_point_size); + avalue_size -= (right_prec + 1); + } + + if ((*flags & NEED_GROUPING) && thousands_sep_size > 0 && + *grouping != CHAR_MAX && *grouping > 0) { + while (avalue_size > (int)*grouping) { + GRPCPY(*grouping); + GRPSEP; + grouping++; + + /* no more grouping ? */ + if (*grouping == CHAR_MAX) + break; + + /* rest grouping with same value ? */ + if (*grouping == 0) { + grouping--; + while (avalue_size > *grouping) { + GRPCPY(*grouping); + GRPSEP; + } + } + } + if (avalue_size != 0) + GRPCPY(avalue_size); + padded -= groups; + } else { + bufend -= avalue_size; + memcpy(bufend, avalue + padded, avalue_size); + /* decrease assumed $decimal_point */ + if (right_prec == 0) + padded -= decimal_point_size; + } + + /* do padding with pad_char */ + if (padded > 0) { + bufend -= padded; + memset(bufend, pad_char, padded); + } + + bufsize = rslt + bufsize - bufend; + memmove(rslt, bufend, bufsize); + free(avalue); + return (rslt); +} + +ssize_t +strfmon(char *restrict s, size_t maxsize, const char *restrict format, ...) +{ + ssize_t ret; + va_list ap; + + va_start(ap, format); + ret = vstrfmon_l(s, maxsize, __get_locale(), format, ap); + va_end(ap); + + return (ret); +} + +ssize_t +strfmon_l(char *restrict s, size_t maxsize, locale_t loc, + const char *restrict format, ...) +{ + ssize_t ret; + va_list ap; + + va_start(ap, format); + ret = vstrfmon_l(s, maxsize, loc, format, ap); + va_end(ap); + + return (ret); +} diff --git a/lib/libc/stdlib/strtod.3 b/lib/libc/stdlib/strtod.3 new file mode 100644 index 000000000000..018e1e8c3c38 --- /dev/null +++ b/lib/libc/stdlib/strtod.3 @@ -0,0 +1,195 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd May 11, 2010 +.Dt STRTOD 3 +.Os +.Sh NAME +.Nm strtod , strtof , strtold +.Nd convert +.Tn ASCII +string to floating point +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft double +.Fn strtod "const char * restrict nptr" "char ** restrict endptr" +.Ft float +.Fn strtof "const char * restrict nptr" "char ** restrict endptr" +.Ft "long double" +.Fn strtold "const char * restrict nptr" "char ** restrict endptr" +.Sh DESCRIPTION +These conversion +functions convert the initial portion of the string +pointed to by +.Fa nptr +to +.Vt double , +.Vt float , +and +.Vt "long double" +representation, respectively. +.Pp +The expected form of the string is an optional plus (``+'') or minus +sign (``\-'') followed by either: +.Bl -bullet +.It +a decimal significand consisting of a sequence of decimal digits +optionally containing a decimal-point character, or +.It +a hexadecimal significand consisting of a ``0X'' or ``0x'' followed +by a sequence of hexadecimal digits optionally containing a +decimal-point character. +.El +.Pp +In both cases, the significand may be optionally followed by an +exponent. +An exponent consists of an ``E'' or ``e'' (for decimal +constants) or a ``P'' or ``p'' (for hexadecimal constants), +followed by an optional plus or minus sign, followed by a +sequence of decimal digits. +For decimal constants, the exponent indicates the power of 10 by +which the significand should be scaled. +For hexadecimal constants, the scaling is instead done by powers +of 2. +.Pp +Alternatively, if the portion of the string following the optional +plus or minus sign begins with +.Dq INFINITY +or +.Dq NAN , +ignoring case, it is interpreted as an infinity or a quiet \*(Na, +respectively. +The syntax +.Dq Xo Pf NAN( Ar "s" ) Xc , +where +.Ar s +is an alphanumeric string, produces the same value as the call +.Fo nan +.Qq Ar s Ns +.Fc +(respectively, +.Fo nanf +.Qq Ar s Ns +.Fc +and +.Fo nanl +.Qq Ar s Ns +.Fc . ) +.Pp +In any of the above cases, leading white-space characters in the +string (as defined by the +.Xr isspace 3 +function) are skipped. +The decimal point +character is defined in the program's locale (category +.Dv LC_NUMERIC ) . +.Sh RETURN VALUES +The +.Fn strtod , +.Fn strtof , +and +.Fn strtold +functions return the converted value, if any. +.Pp +If +.Fa endptr +is not +.Dv NULL , +a pointer to the character after the last character used +in the conversion is stored in the location referenced by +.Fa endptr . +.Pp +If no conversion is performed, zero is returned and the value of +.Fa nptr +is stored in the location referenced by +.Fa endptr . +.Pp +If the correct value would cause overflow, plus or minus +.Dv HUGE_VAL , +.Dv HUGE_VALF , +or +.Dv HUGE_VALL +is returned (according to the sign and type of the return value), and +.Er ERANGE +is stored in +.Va errno . +If the correct value would cause underflow, zero is +returned and +.Er ERANGE +is stored in +.Va errno . +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er ERANGE +Overflow or underflow occurred. +.El +.Sh SEE ALSO +.Xr atof 3 , +.Xr atoi 3 , +.Xr atol 3 , +.Xr nan 3 , +.Xr strtol 3 , +.Xr strtoul 3 , +.Xr wcstod 3 +.Sh STANDARDS +The +.Fn strtod +function +conforms to +.St -isoC-99 . +.Sh AUTHORS +The author of this software is +.An David M. Gay . +.Bd -literal +Copyright (c) 1998 by Lucent Technologies +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name of Lucent or any of its entities +not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +.Ed diff --git a/lib/libc/stdlib/strtoimax.c b/lib/libc/stdlib/strtoimax.c new file mode 100644 index 000000000000..fe2a0a237e23 --- /dev/null +++ b/lib/libc/stdlib/strtoimax.c @@ -0,0 +1,156 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * 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. + */ + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <inttypes.h> +#include "xlocale_private.h" + +/* + * Convert a string to an intmax_t integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +intmax_t +strtoimax_l(const char * __restrict nptr, char ** __restrict endptr, int base, + locale_t locale) +{ + const char *s; + uintmax_t acc; + char c; + uintmax_t cutoff; + int neg, any, cutlim; + FIX_LOCALE(locale); + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + s = nptr; + do { + c = *s++; + } while (isspace_l((unsigned char)c, locale)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X') && + ((s[1] >= '0' && s[1] <= '9') || + (s[1] >= 'A' && s[1] <= 'F') || + (s[1] >= 'a' && s[1] <= 'f'))) { + c = s[1]; + s += 2; + base = 16; + } + if ((base == 0 || base == 2) && + c == '0' && (*s == 'b' || *s == 'B') && + (s[1] >= '0' && s[1] <= '1')) { + c = s[1]; + s += 2; + base = 2; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) + goto noconv; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for intmax_t is + * [-9223372036854775808..9223372036854775807] and the input base + * is 10, cutoff will be set to 922337203685477580 and cutlim to + * either 7 (neg==0) or 8 (neg==1), meaning that if we have + * accumulated a value > 922337203685477580, or equal but the + * next digit is > 7 (or 8), the number is too big, and we will + * return a range error. + * + * Set 'any' if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? (uintmax_t)-(INTMAX_MIN + INTMAX_MAX) + INTMAX_MAX + : INTMAX_MAX; + cutlim = cutoff % base; + cutoff /= base; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? INTMAX_MIN : INTMAX_MAX; + errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; + } else if (neg) + acc = -acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} +intmax_t +strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + return strtoimax_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/stdlib/strtol.3 b/lib/libc/stdlib/strtol.3 new file mode 100644 index 000000000000..af8bec579dbf --- /dev/null +++ b/lib/libc/stdlib/strtol.3 @@ -0,0 +1,221 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Chris Torek and the American National Standards Committee X3, +.\" on Information Processing Systems. +.\" +.\" 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. +.\" +.Dd August 21, 2023 +.Dt STRTOL 3 +.Os +.Sh NAME +.Nm strtol , strtoll , strtoimax , strtoq +.Nd "convert a string value to a" +.Vt long , "long long" , intmax_t +or +.Vt quad_t +integer +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.In limits.h +.Ft long +.Fn strtol "const char * restrict nptr" "char ** restrict endptr" "int base" +.Ft long long +.Fn strtoll "const char * restrict nptr" "char ** restrict endptr" "int base" +.In inttypes.h +.Ft intmax_t +.Fn strtoimax "const char * restrict nptr" "char ** restrict endptr" "int base" +.In sys/types.h +.In stdlib.h +.In limits.h +.Ft quad_t +.Fn strtoq "const char *nptr" "char **endptr" "int base" +.Sh DESCRIPTION +The +.Fn strtol +function +converts the string in +.Fa nptr +to a +.Vt long +value. +The +.Fn strtoll +function +converts the string in +.Fa nptr +to a +.Vt "long long" +value. +The +.Fn strtoimax +function +converts the string in +.Fa nptr +to an +.Vt intmax_t +value. +The +.Fn strtoq +function +converts the string in +.Fa nptr +to a +.Vt quad_t +value. +The conversion is done according to the given +.Fa base , +which must be between 2 and 36 inclusive, +or be the special value 0. +.Pp +The string may begin with an arbitrary amount of white space +(as determined by +.Xr isspace 3 ) +followed by a single optional +.Ql + +or +.Ql - +sign. +If +.Fa base +is zero or 16, +the string may then include a +.Dq Li 0b +prefix, and the number will be read in base 2; or it may include a +.Dq Li 0x +prefix, +and the number will be read in base 16; otherwise, a zero +.Fa base +is taken as 10 (decimal) unless the next character is +.Ql 0 , +in which case it is taken as 8 (octal). +.Pp +The remainder of the string is converted to a +.Vt long , "long long" , intmax_t +or +.Vt quad_t +value in the obvious manner, +stopping at the first character which is not a valid digit +in the given base. +(In bases above 10, the letter +.Ql A +in either upper or lower case +represents 10, +.Ql B +represents 11, and so forth, with +.Ql Z +representing 35.) +.Pp +If +.Fa endptr +is not +.Dv NULL , +.Fn strtol +stores the address of the first invalid character in +.Fa *endptr . +If there were no digits at all, however, +.Fn strtol +stores the original value of +.Fa nptr +in +.Fa *endptr . +(Thus, if +.Fa *nptr +is not +.Ql \e0 +but +.Fa **endptr +is +.Ql \e0 +on return, the entire string was valid.) +.Sh RETURN VALUES +The +.Fn strtol , +.Fn strtoll , +.Fn strtoimax +and +.Fn strtoq +functions +return the result of the conversion, +unless the value would underflow or overflow. +If no conversion could be performed, 0 is returned and +the global variable +.Va errno +is set to +.Er EINVAL +(the last feature is not portable across all platforms). +If an overflow or underflow occurs, +.Va errno +is set to +.Er ERANGE +and the function return value is clamped according +to the following table. +.Bl -column -offset indent ".Fn strtoimax" ".Sy underflow" ".Sy overflow" +.It Sy Function Ta Sy underflow Ta Sy overflow +.It Fn strtol Ta Dv LONG_MIN Ta Dv LONG_MAX +.It Fn strtoll Ta Dv LLONG_MIN Ta Dv LLONG_MAX +.It Fn strtoimax Ta Dv INTMAX_MIN Ta Dv INTMAX_MAX +.It Fn strtoq Ta Dv LLONG_MIN Ta Dv LLONG_MAX +.El +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er EINVAL +The value of +.Fa base +is not supported or +no conversion could be performed +(the last feature is not portable across all platforms). +.It Bq Er ERANGE +The given string was out of range; the value converted has been clamped. +.El +.Sh SEE ALSO +.Xr atof 3 , +.Xr atoi 3 , +.Xr atol 3 , +.Xr strtod 3 , +.Xr strtonum 3 , +.Xr strtoul 3 , +.Xr wcstol 3 +.Sh STANDARDS +The +.Fn strtol +function +conforms to +.St -isoC . +The +.Fn strtoll +and +.Fn strtoimax +functions +conform to +.St -isoC-99 . +The +.Bx +.Fn strtoq +function is deprecated. diff --git a/lib/libc/stdlib/strtol.c b/lib/libc/stdlib/strtol.c new file mode 100644 index 000000000000..54f728893e08 --- /dev/null +++ b/lib/libc/stdlib/strtol.c @@ -0,0 +1,155 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * 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. + */ + +#include <limits.h> +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include "xlocale_private.h" + +/* + * Convert a string to a long integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long +strtol_l(const char * __restrict nptr, char ** __restrict endptr, int base, + locale_t locale) +{ + const char *s; + unsigned long acc; + char c; + unsigned long cutoff; + int neg, any, cutlim; + FIX_LOCALE(locale); + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + s = nptr; + do { + c = *s++; + } while (isspace_l((unsigned char)c, locale)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X') && + ((s[1] >= '0' && s[1] <= '9') || + (s[1] >= 'A' && s[1] <= 'F') || + (s[1] >= 'a' && s[1] <= 'f'))) { + c = s[1]; + s += 2; + base = 16; + } + if ((base == 0 || base == 2) && + c == '0' && (*s == 'b' || *s == 'B') && + (s[1] >= '0' && s[1] <= '1')) { + c = s[1]; + s += 2; + base = 2; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) + goto noconv; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set 'any' if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX + : LONG_MAX; + cutlim = cutoff % base; + cutoff /= base; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; + errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; + } else if (neg) + acc = -acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} +long +strtol(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + return strtol_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/stdlib/strtold.c b/lib/libc/stdlib/strtold.c new file mode 100644 index 000000000000..fa05f7a63889 --- /dev/null +++ b/lib/libc/stdlib/strtold.c @@ -0,0 +1,39 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (C) 2011 The FreeBSD Foundation + * + * This software was developed by David Chisnall under sponsorship from the + * FreeBSD Foundation. + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#include <stdlib.h> +#include "xlocale_private.h" + +long double +strtold(const char * __restrict nptr, char ** __restrict endptr) +{ + + return strtold_l(nptr, endptr, __get_locale()); +} diff --git a/lib/libc/stdlib/strtoll.c b/lib/libc/stdlib/strtoll.c new file mode 100644 index 000000000000..3ce399277049 --- /dev/null +++ b/lib/libc/stdlib/strtoll.c @@ -0,0 +1,157 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * 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. + */ + +#include <limits.h> +#include <errno.h> +#include <ctype.h> +#include <stdlib.h> +#include "xlocale_private.h" + +/* + * Convert a string to a long long integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long long +strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base, + locale_t locale) +{ + const char *s; + unsigned long long acc; + char c; + unsigned long long cutoff; + int neg, any, cutlim; + FIX_LOCALE(locale); + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0b for binary, 0x for hex, and 0 for + * octal, else assume decimal; if base is already 2, allow + * 0b; if base is already 16, allow 0x. + */ + s = nptr; + do { + c = *s++; + } while (isspace_l((unsigned char)c, locale)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X') && + ((s[1] >= '0' && s[1] <= '9') || + (s[1] >= 'A' && s[1] <= 'F') || + (s[1] >= 'a' && s[1] <= 'f'))) { + c = s[1]; + s += 2; + base = 16; + } + if ((base == 0 || base == 2) && + c == '0' && (*s == 'b' || *s == 'B') && + (s[1] >= '0' && s[1] <= '1')) { + c = s[1]; + s += 2; + base = 2; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) + goto noconv; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for quads is + * [-9223372036854775808..9223372036854775807] and the input base + * is 10, cutoff will be set to 922337203685477580 and cutlim to + * either 7 (neg==0) or 8 (neg==1), meaning that if we have + * accumulated a value > 922337203685477580, or equal but the + * next digit is > 7 (or 8), the number is too big, and we will + * return a range error. + * + * Set 'any' if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX + : LLONG_MAX; + cutlim = cutoff % base; + cutoff /= base; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LLONG_MIN : LLONG_MAX; + errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; + } else if (neg) + acc = -acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} +long long +strtoll(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + return strtoll_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/stdlib/strtonum.3 b/lib/libc/stdlib/strtonum.3 new file mode 100644 index 000000000000..2650d147e7cc --- /dev/null +++ b/lib/libc/stdlib/strtonum.3 @@ -0,0 +1,154 @@ +.\" Copyright (c) 2004 Ted Unangst +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" $OpenBSD: strtonum.3,v 1.13 2006/04/25 05:15:42 tedu Exp $ +.\" +.Dd April 29, 2004 +.Dt STRTONUM 3 +.Os +.Sh NAME +.Nm strtonum +.Nd "reliably convert string value to an integer" +.Sh SYNOPSIS +.In stdlib.h +.Ft long long +.Fo strtonum +.Fa "const char *nptr" +.Fa "long long minval" +.Fa "long long maxval" +.Fa "const char **errstr" +.Fc +.Sh DESCRIPTION +The +.Fn strtonum +function converts the string in +.Fa nptr +to a +.Vt "long long" +value. +The +.Fn strtonum +function was designed to facilitate safe, robust programming +and overcome the shortcomings of the +.Xr atoi 3 +and +.Xr strtol 3 +family of interfaces. +.Pp +The string may begin with an arbitrary amount of whitespace +(as determined by +.Xr isspace 3 ) +followed by a single optional +.Ql + +or +.Ql - +sign. +.Pp +The remainder of the string is converted to a +.Vt "long long" +value according to base 10. +.Pp +The value obtained is then checked against the provided +.Fa minval +and +.Fa maxval +bounds. +If +.Fa errstr +is non-null, +.Fn strtonum +stores an error string in +.Fa *errstr +indicating the failure. +.Sh RETURN VALUES +The +.Fn strtonum +function returns the result of the conversion, +unless the value would exceed the provided bounds or is invalid. +On error, 0 is returned, +.Va errno +is set, and +.Fa errstr +will point to an error message. +On success, +.Fa *errstr +will be set to +.Dv NULL ; +this fact can be used to differentiate +a successful return of 0 from an error. +.Sh EXAMPLES +Using +.Fn strtonum +correctly is meant to be simpler than the alternative functions. +.Bd -literal -offset indent +int iterations; +const char *errstr; + +iterations = strtonum(optarg, 1, 64, &errstr); +if (errstr != NULL) + errx(1, "number of iterations is %s: %s", errstr, optarg); +.Ed +.Pp +The above example will guarantee that the value of iterations is between +1 and 64 (inclusive). +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er ERANGE +The given string was out of range. +.It Bq Er EINVAL +The given string did not consist solely of digit characters. +.It Bq Er EINVAL +The supplied +.Fa minval +was larger than +.Fa maxval . +.El +.Pp +If an error occurs, +.Fa errstr +will be set to one of the following strings: +.Pp +.Bl -tag -width ".Li too large" -compact +.It Li "too large" +The result was larger than the provided maximum value. +.It Li "too small" +The result was smaller than the provided minimum value. +.It Li invalid +The string did not consist solely of digit characters. +.El +.Sh SEE ALSO +.Xr atof 3 , +.Xr atoi 3 , +.Xr atol 3 , +.Xr atoll 3 , +.Xr sscanf 3 , +.Xr strtod 3 , +.Xr strtol 3 , +.Xr strtoul 3 +.Sh STANDARDS +The +.Fn strtonum +function is a +.Bx +extension. +The existing alternatives, such as +.Xr atoi 3 +and +.Xr strtol 3 , +are either impossible or difficult to use safely. +.Sh HISTORY +The +.Fn strtonum +function first appeared in +.Ox 3.6 . diff --git a/lib/libc/stdlib/strtonum.c b/lib/libc/stdlib/strtonum.c new file mode 100644 index 000000000000..0d0715bf39c1 --- /dev/null +++ b/lib/libc/stdlib/strtonum.c @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2004 Ted Unangst and Todd Miller + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ + */ + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +#define INVALID 1 +#define TOOSMALL 2 +#define TOOLARGE 3 + +long long +strtonum(const char *numstr, long long minval, long long maxval, + const char **errstrp) +{ + long long ll = 0; + int error = 0; + char *ep; + struct errval { + const char *errstr; + int err; + } ev[4] = { + { NULL, 0 }, + { "invalid", EINVAL }, + { "too small", ERANGE }, + { "too large", ERANGE }, + }; + + ev[0].err = errno; + errno = 0; + if (minval > maxval) { + error = INVALID; + } else { + ll = strtoll(numstr, &ep, 10); + if (errno == EINVAL || numstr == ep || *ep != '\0') + error = INVALID; + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + error = TOOSMALL; + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + error = TOOLARGE; + } + if (errstrp != NULL) + *errstrp = ev[error].errstr; + errno = ev[error].err; + if (error) + ll = 0; + + return (ll); +} diff --git a/lib/libc/stdlib/strtoq.c b/lib/libc/stdlib/strtoq.c new file mode 100644 index 000000000000..2d97df712d37 --- /dev/null +++ b/lib/libc/stdlib/strtoq.c @@ -0,0 +1,44 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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. + * 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. + */ + +#include <sys/types.h> + +#include <stdlib.h> + +/* + * Convert a string to a quad integer. + */ +quad_t +strtoq(const char *nptr, char **endptr, int base) +{ + + return strtoll(nptr, endptr, base); +} diff --git a/lib/libc/stdlib/strtoul.3 b/lib/libc/stdlib/strtoul.3 new file mode 100644 index 000000000000..3e4b6bdc20fb --- /dev/null +++ b/lib/libc/stdlib/strtoul.3 @@ -0,0 +1,223 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Chris Torek and the American National Standards Committee X3, +.\" on Information Processing Systems. +.\" +.\" 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. +.\" +.Dd August 21, 2023 +.Dt STRTOUL 3 +.Os +.Sh NAME +.Nm strtoul , strtoull , strtoumax , strtouq +.Nd "convert a string to an" +.Vt "unsigned long" , "unsigned long long" , uintmax_t , +or +.Vt u_quad_t +integer +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.In limits.h +.Ft "unsigned long" +.Fn strtoul "const char * restrict nptr" "char ** restrict endptr" "int base" +.Ft "unsigned long long" +.Fn strtoull "const char * restrict nptr" "char ** restrict endptr" "int base" +.In inttypes.h +.Ft uintmax_t +.Fn strtoumax "const char * restrict nptr" "char ** restrict endptr" "int base" +.In sys/types.h +.In stdlib.h +.In limits.h +.Ft u_quad_t +.Fn strtouq "const char *nptr" "char **endptr" "int base" +.Sh DESCRIPTION +The +.Fn strtoul +function +converts the string in +.Fa nptr +to an +.Vt "unsigned long" +value. +The +.Fn strtoull +function +converts the string in +.Fa nptr +to an +.Vt "unsigned long long" +value. +The +.Fn strtoumax +function +converts the string in +.Fa nptr +to an +.Vt uintmax_t +value. +The +.Fn strtouq +function +converts the string in +.Fa nptr +to a +.Vt u_quad_t +value. +The conversion is done according to the given +.Fa base , +which must be between 2 and 36 inclusive, +or be the special value 0. +.Pp +The string may begin with an arbitrary amount of white space +(as determined by +.Xr isspace 3 ) +followed by a single optional +.Ql + +or +.Ql - +sign. +If +.Fa base +is zero or 16, +the string may then include a +.Dq Li 0b +prefix, and the number will be read in base 2; or it may include a +.Dq Li 0x +prefix, +and the number will be read in base 16; otherwise, a zero +.Fa base +is taken as 10 (decimal) unless the next character is +.Ql 0 , +in which case it is taken as 8 (octal). +.Pp +The remainder of the string is converted to an +.Vt "unsigned long" +value in the obvious manner, +stopping at the end of the string +or at the first character that does not produce a valid digit +in the given base. +(In bases above 10, the letter +.Ql A +in either upper or lower case +represents 10, +.Ql B +represents 11, and so forth, with +.Ql Z +representing 35.) +.Pp +If +.Fa endptr +is not +.Dv NULL , +.Fn strtoul +stores the address of the first invalid character in +.Fa *endptr . +If there were no digits at all, however, +.Fn strtoul +stores the original value of +.Fa nptr +in +.Fa *endptr . +(Thus, if +.Fa *nptr +is not +.Ql \e0 +but +.Fa **endptr +is +.Ql \e0 +on return, the entire string was valid.) +.Sh RETURN VALUES +The +.Fn strtoul , +.Fn strtoull , +.Fn strtoumax +and +.Fn strtouq +functions +return either the result of the conversion +or, if there was a leading minus sign, +the negation of the result of the conversion, +unless the original (non-negated) value would overflow; +in the latter case, +.Fn strtoul +returns +.Dv ULONG_MAX , +.Fn strtoull +returns +.Dv ULLONG_MAX , +.Fn strtoumax +returns +.Dv UINTMAX_MAX , +and +.Fn strtouq +returns +.Dv ULLONG_MAX . +In all cases, +.Va errno +is set to +.Er ERANGE . +If no conversion could be performed, 0 is returned and +the global variable +.Va errno +is set to +.Er EINVAL +(the last feature is not portable across all platforms). +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er EINVAL +The value of +.Fa base +is not supported or +no conversion could be performed +(the last feature is not portable across all platforms). +.It Bq Er ERANGE +The given string was out of range; the value converted has been clamped. +.El +.Sh SEE ALSO +.Xr strtol 3 , +.Xr strtonum 3 , +.Xr wcstoul 3 +.Sh STANDARDS +The +.Fn strtoul +function +conforms to +.St -isoC . +The +.Fn strtoull +and +.Fn strtoumax +functions +conform to +.St -isoC-99 . +The +.Bx +.Fn strtouq +function is deprecated. diff --git a/lib/libc/stdlib/strtoul.c b/lib/libc/stdlib/strtoul.c new file mode 100644 index 000000000000..dfe31ede0f44 --- /dev/null +++ b/lib/libc/stdlib/strtoul.c @@ -0,0 +1,133 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * 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. + */ + +#include <limits.h> +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include "xlocale_private.h" + +/* + * Convert a string to an unsigned long integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +unsigned long +strtoul_l(const char * __restrict nptr, char ** __restrict endptr, int base, locale_t locale) +{ + const char *s; + unsigned long acc; + char c; + unsigned long cutoff; + int neg, any, cutlim; + FIX_LOCALE(locale); + + /* + * See strtol for comments as to the logic used. + */ + s = nptr; + do { + c = *s++; + } while (isspace_l((unsigned char)c, locale)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X') && + ((s[1] >= '0' && s[1] <= '9') || + (s[1] >= 'A' && s[1] <= 'F') || + (s[1] >= 'a' && s[1] <= 'f'))) { + c = s[1]; + s += 2; + base = 16; + } + if ((base == 0 || base == 2) && + c == '0' && (*s == 'b' || *s == 'B') && + (s[1] >= '0' && s[1] <= '1')) { + c = s[1]; + s += 2; + base = 2; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) + goto noconv; + + cutoff = ULONG_MAX / base; + cutlim = ULONG_MAX % base; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULONG_MAX; + errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; + } else if (neg) + acc = -acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} +unsigned long +strtoul(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + return strtoul_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/stdlib/strtoull.c b/lib/libc/stdlib/strtoull.c new file mode 100644 index 000000000000..be60956a53a6 --- /dev/null +++ b/lib/libc/stdlib/strtoull.c @@ -0,0 +1,134 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * 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. + */ + +#include <limits.h> +#include <errno.h> +#include <ctype.h> +#include <stdlib.h> +#include "xlocale_private.h" + +/* + * Convert a string to an unsigned long long integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +unsigned long long +strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base, + locale_t locale) +{ + const char *s; + unsigned long long acc; + char c; + unsigned long long cutoff; + int neg, any, cutlim; + FIX_LOCALE(locale); + + /* + * See strtoq for comments as to the logic used. + */ + s = nptr; + do { + c = *s++; + } while (isspace_l((unsigned char)c, locale)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X') && + ((s[1] >= '0' && s[1] <= '9') || + (s[1] >= 'A' && s[1] <= 'F') || + (s[1] >= 'a' && s[1] <= 'f'))) { + c = s[1]; + s += 2; + base = 16; + } + if ((base == 0 || base == 2) && + c == '0' && (*s == 'b' || *s == 'B') && + (s[1] >= '0' && s[1] <= '1')) { + c = s[1]; + s += 2; + base = 2; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) + goto noconv; + + cutoff = ULLONG_MAX / base; + cutlim = ULLONG_MAX % base; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULLONG_MAX; + errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; + } else if (neg) + acc = -acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} +unsigned long long +strtoull(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + return strtoull_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/stdlib/strtoumax.c b/lib/libc/stdlib/strtoumax.c new file mode 100644 index 000000000000..6f4443acece0 --- /dev/null +++ b/lib/libc/stdlib/strtoumax.c @@ -0,0 +1,134 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * 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. + */ + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <inttypes.h> +#include "xlocale_private.h" + +/* + * Convert a string to a uintmax_t integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +uintmax_t +strtoumax_l(const char * __restrict nptr, char ** __restrict endptr, int base, + locale_t locale) +{ + const char *s; + uintmax_t acc; + char c; + uintmax_t cutoff; + int neg, any, cutlim; + FIX_LOCALE(locale); + + /* + * See strtoimax for comments as to the logic used. + */ + s = nptr; + do { + c = *s++; + } while (isspace_l((unsigned char)c, locale)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X') && + ((s[1] >= '0' && s[1] <= '9') || + (s[1] >= 'A' && s[1] <= 'F') || + (s[1] >= 'a' && s[1] <= 'f'))) { + c = s[1]; + s += 2; + base = 16; + } + if ((base == 0 || base == 2) && + c == '0' && (*s == 'b' || *s == 'B') && + (s[1] >= '0' && s[1] <= '1')) { + c = s[1]; + s += 2; + base = 2; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) + goto noconv; + + cutoff = UINTMAX_MAX / base; + cutlim = UINTMAX_MAX % base; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = UINTMAX_MAX; + errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; + } else if (neg) + acc = -acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} +uintmax_t +strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + return strtoumax_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/stdlib/strtouq.c b/lib/libc/stdlib/strtouq.c new file mode 100644 index 000000000000..a50e02a2ee0b --- /dev/null +++ b/lib/libc/stdlib/strtouq.c @@ -0,0 +1,44 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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. + * 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. + */ + +#include <sys/types.h> + +#include <stdlib.h> + +/* + * Convert a string to an unsigned quad integer. + */ +u_quad_t +strtouq(const char *nptr, char **endptr, int base) +{ + + return strtoull(nptr, endptr, base); +} diff --git a/lib/libc/stdlib/system.3 b/lib/libc/stdlib/system.3 new file mode 100644 index 000000000000..119432342f70 --- /dev/null +++ b/lib/libc/stdlib/system.3 @@ -0,0 +1,108 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" 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. +.\" +.Dd January 11, 2024 +.Dt SYSTEM 3 +.Os +.Sh NAME +.Nm system +.Nd pass a command to the shell +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft int +.Fn system "const char *string" +.Sh DESCRIPTION +The +.Fn system +function +hands the argument +.Fa string +to the command interpreter +.Xr sh 1 . +The calling process waits for the shell +to finish executing the command, +ignoring +.Dv SIGINT +and +.Dv SIGQUIT , +and blocking +.Dv SIGCHLD . +.Pp +If +.Fa string +is a +.Dv NULL +pointer, +.Fn system +will return non-zero if the command interpreter +.Xr sh 1 +is available, and zero if it is not. +.Sh RETURN VALUES +The +.Fn system +function +returns the exit status of the shell as returned by +.Xr waitpid 2 , +or \-1 if an error occurred when invoking +.Xr fork 2 +or +.Xr waitpid 2 . +A return value of 127 means the execution of the shell +failed. +.Sh SEE ALSO +.Xr sh 1 , +.Xr execve 2 , +.Xr fork 2 , +.Xr waitpid 2 , +.Xr popen 3 , +.Xr posix_spawn 3 +.Sh STANDARDS +The +.Fn system +function +conforms to +.St -isoC +and is expected to be +.St -p1003.2 +compatible. +.Sh SECURITY CONSIDERATIONS +The +.Fn system +function is easily misused in a manner that enables a malicious +user to run arbitrary command, +because all meta-characters supported by +.Xr sh 1 +would be honored. +User supplied parameters should always be carefully sanitized +before they appear in +.Fa string . diff --git a/lib/libc/stdlib/system.c b/lib/libc/stdlib/system.c new file mode 100644 index 000000000000..b581a6ec3b14 --- /dev/null +++ b/lib/libc/stdlib/system.c @@ -0,0 +1,108 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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. + * 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. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> +#include <paths.h> +#include <errno.h> +#include "un-namespace.h" +#include "libc_private.h" + +#pragma weak system +int +system(const char *command) +{ + + return (((int (*)(const char *)) + __libc_interposing[INTERPOS_system])(command)); +} + +int +__libc_system(const char *command) +{ + pid_t pid, savedpid; + int pstat; + struct sigaction ign, intact, quitact; + sigset_t newsigblock, oldsigblock; + + if (!command) /* just checking... */ + return(1); + + (void)sigemptyset(&newsigblock); + (void)sigaddset(&newsigblock, SIGCHLD); + (void)sigaddset(&newsigblock, SIGINT); + (void)sigaddset(&newsigblock, SIGQUIT); + (void)__libc_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); + switch(pid = vfork()) { + /* + * In the child, use unwrapped syscalls. libthr is in + * undefined state after vfork(). + */ + case -1: /* error */ + (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); + return (-1); + case 0: /* child */ + /* + * Restore original signal dispositions and exec the command. + */ + (void)__sys_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); + execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL); + _exit(127); + } + /* + * If we are running means that the child has either completed + * its execve, or has failed. + * Block SIGINT/QUIT because sh -c handles it and wait for + * it to clean up. + */ + memset(&ign, 0, sizeof(ign)); + ign.sa_handler = SIG_IGN; + (void)sigemptyset(&ign.sa_mask); + (void)__libc_sigaction(SIGINT, &ign, &intact); + (void)__libc_sigaction(SIGQUIT, &ign, &quitact); + savedpid = pid; + do { + pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0); + } while (pid == -1 && errno == EINTR); + (void)__libc_sigaction(SIGINT, &intact, NULL); + (void)__libc_sigaction(SIGQUIT, &quitact, NULL); + (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); + return (pid == -1 ? -1 : pstat); +} + +__weak_reference(__libc_system, __system); +__weak_reference(__libc_system, _system); diff --git a/lib/libc/stdlib/tdelete.c b/lib/libc/stdlib/tdelete.c new file mode 100644 index 000000000000..3b00a6cf0852 --- /dev/null +++ b/lib/libc/stdlib/tdelete.c @@ -0,0 +1,205 @@ +/*- + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#define _SEARCH_PRIVATE +#include <search.h> +#include <stdbool.h> +#include <stdlib.h> + +#include "tsearch_path.h" + +/* + * Makes a step to the left along the binary search tree. This step is + * also saved, so it can be replayed while rebalancing. +*/ +#define GO_LEFT() do { \ + if ((*leaf)->balance == 0 || \ + ((*leaf)->balance < 0 && (*leaf)->rlink->balance == 0)) { \ + /* \ + * If we reach a node that is balanced, or has a child \ + * in the opposite direction that is balanced, we know \ + * that we won't need to perform any rotations above \ + * this point. In this case rotations are always \ + * capable of keeping the subtree in balance. Make \ + * this the root node and reset the path. \ + */ \ + rootp = leaf; \ + path_init(&path); \ + } \ + path_taking_left(&path); \ + leaf = &(*leaf)->llink; \ +} while (0) + +/* Makes a step to the right along the binary search tree. */ +#define GO_RIGHT() do { \ + if ((*leaf)->balance == 0 || \ + ((*leaf)->balance > 0 && (*leaf)->llink->balance == 0)) { \ + rootp = leaf; \ + path_init(&path); \ + } \ + path_taking_right(&path); \ + leaf = &(*leaf)->rlink; \ +} while (0) + +void * +tdelete(const void *restrict key, posix_tnode **restrict rootp, + int (*compar)(const void *, const void *)) +{ + struct path path; + posix_tnode **leaf, *old, **n, *x, *y, *z, *result; + int cmp; + + /* POSIX requires that tdelete() returns NULL if rootp is NULL. */ + if (rootp == NULL) + return (NULL); + + /* + * Find the leaf that needs to be removed. Return if we cannot + * find an existing entry. Keep track of the path that is taken + * to get to the node, as we will need it to adjust the + * balances. + */ + result = (posix_tnode *)1; + path_init(&path); + leaf = rootp; + for (;;) { + if (*leaf == NULL) + return (NULL); + cmp = compar(key, (*leaf)->key); + if (cmp < 0) { + result = *leaf; + GO_LEFT(); + } else if (cmp > 0) { + result = *leaf; + GO_RIGHT(); + } else { + break; + } + } + + /* Found a matching key in the tree. Remove the node. */ + if ((*leaf)->llink == NULL) { + /* Node has no left children. Replace by its right subtree. */ + old = *leaf; + *leaf = old->rlink; + free(old); + } else { + /* + * Node has left children. Replace this node's key by + * its predecessor's and remove that node instead. + */ + void **keyp = &(*leaf)->key; + GO_LEFT(); + while ((*leaf)->rlink != NULL) + GO_RIGHT(); + old = *leaf; + *keyp = old->key; + *leaf = old->llink; + free(old); + } + + /* + * Walk along the same path a second time and adjust the + * balances. Though this code looks similar to the rebalancing + * performed in tsearch(), it is not identical. We now also need + * to consider the case of outward imbalance in the right-right + * and left-left case that only exists when deleting. Hence the + * duplication of code. + */ + for (n = rootp; n != leaf;) { + if (path_took_left(&path)) { + x = *n; + if (x->balance < 0) { + y = x->rlink; + if (y->balance > 0) { + /* Right-left case. */ + z = y->llink; + x->rlink = z->llink; + z->llink = x; + y->llink = z->rlink; + z->rlink = y; + *n = z; + + x->balance = z->balance < 0 ? 1 : 0; + y->balance = z->balance > 0 ? -1 : 0; + z->balance = 0; + } else { + /* Right-right case. */ + x->rlink = y->llink; + y->llink = x; + *n = y; + + if (y->balance < 0) { + x->balance = 0; + y->balance = 0; + } else { + x->balance = -1; + y->balance = 1; + } + } + } else { + --x->balance; + } + n = &x->llink; + } else { + x = *n; + if (x->balance > 0) { + y = x->llink; + if (y->balance < 0) { + /* Left-right case. */ + z = y->rlink; + y->rlink = z->llink; + z->llink = y; + x->llink = z->rlink; + z->rlink = x; + *n = z; + + x->balance = z->balance > 0 ? -1 : 0; + y->balance = z->balance < 0 ? 1 : 0; + z->balance = 0; + } else { + /* Left-left case. */ + x->llink = y->rlink; + y->rlink = x; + *n = y; + + if (y->balance > 0) { + x->balance = 0; + y->balance = 0; + } else { + x->balance = 1; + y->balance = -1; + } + } + } else { + ++x->balance; + } + n = &x->rlink; + } + } + + /* Return the parent of the old entry. */ + return (result); +} diff --git a/lib/libc/stdlib/tfind.c b/lib/libc/stdlib/tfind.c new file mode 100644 index 000000000000..5fa35f1bd85f --- /dev/null +++ b/lib/libc/stdlib/tfind.c @@ -0,0 +1,46 @@ +/* $NetBSD: tfind.c,v 1.2 1999/09/16 11:45:37 lukem Exp $ */ + +/* + * Tree search generalized from Knuth (6.2.2) Algorithm T just like + * the AT&T man page says. + * + * Written by reading the System V Interface Definition, not the code. + * + * Totally public domain. + */ + +#include <sys/cdefs.h> +#if 0 +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: tfind.c,v 1.2 1999/09/16 11:45:37 lukem Exp $"); +#endif /* LIBC_SCCS and not lint */ +#endif +#define _SEARCH_PRIVATE +#include <stdlib.h> +#include <search.h> + +/* + * find a node, or return 0 + * + * vkey - key to be found + * vrootp - address of the tree root + */ +posix_tnode * +tfind(const void *vkey, posix_tnode * const *rootp, + int (*compar)(const void *, const void *)) +{ + + if (rootp == NULL) + return NULL; + + while (*rootp != NULL) { /* T1: */ + int r; + + if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */ + return *rootp; /* key found */ + rootp = (r < 0) ? + &(*rootp)->llink : /* T3: follow left branch */ + &(*rootp)->rlink; /* T4: follow right branch */ + } + return NULL; +} diff --git a/lib/libc/stdlib/tsearch.3 b/lib/libc/stdlib/tsearch.3 new file mode 100644 index 000000000000..edee01cafc52 --- /dev/null +++ b/lib/libc/stdlib/tsearch.3 @@ -0,0 +1,208 @@ +.\" $NetBSD$ +.\" Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> +.\" 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. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. +.\" +.\" OpenBSD: tsearch.3,v 1.2 1998/06/21 22:13:49 millert Exp +.\" +.Dd June 4, 2017 +.Dt TSEARCH 3 +.Os +.Sh NAME +.Nm tsearch , tfind , tdelete , twalk +.Nd manipulate binary search trees +.Sh SYNOPSIS +.In search.h +.Ft void * +.Fn tdelete "const void * restrict key" "posix_tnode ** restrict rootp" "int (*compar) (const void *, const void *)" +.Ft posix_tnode * +.Fn tfind "const void *key" "posix_tnode * const *rootp" "int (*compar) (const void *, const void *)" +.Ft posix_tnode * +.Fn tsearch "const void *key" "posix_tnode **rootp" "int (*compar) (const void *, const void *)" +.Ft void +.Fn twalk "const posix_tnode *root" "void (*action) (const posix_tnode *, VISIT, int)" +.Sh DESCRIPTION +The +.Fn tdelete , +.Fn tfind , +.Fn tsearch , +and +.Fn twalk +functions manage binary search trees. +This implementation uses a balanced AVL tree, +which due to its strong theoretical limit on the height of the tree has +the advantage of calling the comparison function relatively +infrequently. +.Pp +The comparison function passed in by +the user has the same style of return values as +.Xr strcmp 3 . +.Pp +The +.Fn tfind +function +searches for the datum matched by the argument +.Fa key +in the binary tree rooted at +.Fa rootp , +returning a pointer to the datum if it is found and NULL +if it is not. +.Pp +The +.Fn tsearch +function +is identical to +.Fn tfind +except that if no match is found, +.Fa key +is inserted into the tree and a pointer to it is returned. +If +.Fa rootp +points to a NULL value a new binary search tree is created. +.Pp +The +.Fn tdelete +function +deletes a node from the specified binary search tree and returns +a pointer to the parent of the node to be deleted. +It takes the same arguments as +.Fn tfind +and +.Fn tsearch . +If the node to be deleted is the root of the binary search tree, +.Fa rootp +will be adjusted. +.Pp +The +.Fn twalk +function +walks the binary search tree rooted in +.Fa root +and calls the function +.Fa action +on each node. +The +.Fa action +function +is called with three arguments: a pointer to the current node, +a value from the enum +.Sy "typedef enum { preorder, postorder, endorder, leaf } VISIT;" +specifying the traversal type, and a node level (where level +zero is the root of the tree). +.Sh RETURN VALUES +The +.Fn tsearch +function returns NULL if allocation of a new node fails (usually +due to a lack of free memory). +.Pp +The +.Fn tfind , +.Fn tsearch , +and +.Fn tdelete +functions +return NULL if +.Fa rootp +is NULL or the datum cannot be found. +.Pp +The +.Fn twalk +function returns no value. +.Sh EXAMPLES +This example uses +.Fn tsearch +to search for four strings in +.Dv root . +Because the strings are not already present, they are added. +.Fn tsearch +is called twice on the fourth string to demonstrate that a string is not added when it is already present. +.Fn tfind +is used to find the single instance of the fourth string, and +.Fn tdelete +removes it. +Finally, +.Fn twalk +is used to return and display the resulting binary search tree. +.Bd -literal +#include <stdio.h> +#include <search.h> +#include <string.h> + +int +comp(const void *a, const void *b) +{ + + return strcmp(a, b); +} + +void +printwalk(const posix_tnode * node, VISIT v, int __unused0) +{ + + if (v == postorder || v == leaf) { + printf("node: %s\en", *(char **)node); + } +} + +int +main(void) +{ + posix_tnode *root = NULL; + + char one[] = "blah1"; + char two[] = "blah-2"; + char three[] = "blah-3"; + char four[] = "blah-4"; + + tsearch(one, &root, comp); + tsearch(two, &root, comp); + tsearch(three, &root, comp); + tsearch(four, &root, comp); + tsearch(four, &root, comp); + printf("four: %s\en", *(char **)tfind(four, &root, comp)); + tdelete(four, &root, comp); + + twalk(root, printwalk); + return 0; +} +.Ed +.Sh SEE ALSO +.Xr bsearch 3 , +.Xr hsearch 3 , +.Xr lsearch 3 +.Sh STANDARDS +These functions conform to +.St -p1003.1-2008 . +.Pp +The +.Fa posix_tnode +type is not part of +.St -p1003.1-2008 , +but is expected to be standardized by future versions of the standard. +It is defined as +.Fa void +for source-level compatibility. +Using +.Fa posix_tnode +makes distinguishing between nodes and keys easier. diff --git a/lib/libc/stdlib/tsearch.c b/lib/libc/stdlib/tsearch.c new file mode 100644 index 000000000000..7826c555c065 --- /dev/null +++ b/lib/libc/stdlib/tsearch.c @@ -0,0 +1,194 @@ +/*- + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#define _SEARCH_PRIVATE +#include <search.h> +#include <stdlib.h> + +#include "tsearch_path.h" + +posix_tnode * +tsearch(const void *key, posix_tnode **rootp, + int (*compar)(const void *, const void *)) +{ + struct path path; + posix_tnode **leaf, *result, *n, *x, *y, *z; + int cmp; + + /* POSIX requires that tsearch() returns NULL if rootp is NULL. */ + if (rootp == NULL) + return (NULL); + + /* + * Find the leaf where the new key needs to be inserted. Return + * if we've found an existing entry. Keep track of the path that + * is taken to get to the node, as we will need it to adjust the + * balances. + */ + path_init(&path); + leaf = rootp; + while (*leaf != NULL) { + if ((*leaf)->balance != 0) { + /* + * If we reach a node that has a non-zero + * balance on the way, we know that we won't + * need to perform any rotations above this + * point. In this case rotations are always + * capable of keeping the subtree in balance. + * Make this the root node and reset the path. + */ + rootp = leaf; + path_init(&path); + } + cmp = compar(key, (*leaf)->key); + if (cmp < 0) { + path_taking_left(&path); + leaf = &(*leaf)->llink; + } else if (cmp > 0) { + path_taking_right(&path); + leaf = &(*leaf)->rlink; + } else { + return (*leaf); + } + } + + /* Did not find a matching key in the tree. Insert a new node. */ + result = *leaf = malloc(sizeof(**leaf)); + if (result == NULL) + return (NULL); + result->key = (void *)key; + result->llink = NULL; + result->rlink = NULL; + result->balance = 0; + + /* + * Walk along the same path a second time and adjust the + * balances. Except for the first node, all of these nodes must + * have a balance of zero, meaning that these nodes will not get + * out of balance. + */ + for (n = *rootp; n != *leaf;) { + if (path_took_left(&path)) { + n->balance += 1; + n = n->llink; + } else { + n->balance -= 1; + n = n->rlink; + } + } + + /* + * Adjusting the balances may have pushed the balance of the + * root node out of range. Perform a rotation to bring the + * balance back in range. + */ + x = *rootp; + if (x->balance > 1) { + y = x->llink; + if (y->balance < 0) { + /* + * Left-right case. + * + * x + * / \ z + * y D / \ + * / \ --> y x + * A z /| |\ + * / \ A B C D + * B C + */ + z = y->rlink; + y->rlink = z->llink; + z->llink = y; + x->llink = z->rlink; + z->rlink = x; + *rootp = z; + + x->balance = z->balance > 0 ? -1 : 0; + y->balance = z->balance < 0 ? 1 : 0; + z->balance = 0; + } else { + /* + * Left-left case. + * + * x y + * / \ / \ + * y C --> A x + * / \ / \ + * A B B C + */ + x->llink = y->rlink; + y->rlink = x; + *rootp = y; + + x->balance = 0; + y->balance = 0; + } + } else if (x->balance < -1) { + y = x->rlink; + if (y->balance > 0) { + /* + * Right-left case. + * + * x + * / \ z + * A y / \ + * / \ --> x y + * z D /| |\ + * / \ A B C D + * B C + */ + posix_tnode *z = y->llink; + x->rlink = z->llink; + z->llink = x; + y->llink = z->rlink; + z->rlink = y; + *rootp = z; + + x->balance = z->balance < 0 ? 1 : 0; + y->balance = z->balance > 0 ? -1 : 0; + z->balance = 0; + } else { + /* + * Right-right case. + * + * x y + * / \ / \ + * A y --> x C + * / \ / \ + * B C A B + */ + x->rlink = y->llink; + y->llink = x; + *rootp = y; + + x->balance = 0; + y->balance = 0; + } + } + + /* Return the new entry. */ + return (result); +} diff --git a/lib/libc/stdlib/tsearch_path.h b/lib/libc/stdlib/tsearch_path.h new file mode 100644 index 000000000000..8b575d1ee993 --- /dev/null +++ b/lib/libc/stdlib/tsearch_path.h @@ -0,0 +1,95 @@ +/*- + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * 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 AUTHOR 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 AUTHOR 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. + */ + +#ifndef TSEARCH_PATH_H +#define TSEARCH_PATH_H + +#include <limits.h> +#include <stdbool.h> +#include <stdint.h> + +/* + * Bookkeeping for storing a path in a balanced binary search tree from + * the root to a leaf node. + * + * For an AVL tree we know that its maximum height of a tree is bounded + * by approximately 1.44 * log2(n) - 0.328. Given that the number of + * entries of the tree is constrained by the size of the address space, + * two uintptr_t's provide sufficient space to store the path from the + * root to any leaf. + */ +struct path { + uintptr_t steps[2]; + unsigned int nsteps; +}; + +/* Initializes the path structure with a zero-length path. */ +static inline void +path_init(struct path *p) +{ + + p->nsteps = 0; +} + +#define STEPS_BIT (sizeof(uintptr_t) * CHAR_BIT) + +/* Pushes a step to the left to the end of the path. */ +static inline void +path_taking_left(struct path *p) +{ + + p->steps[p->nsteps / STEPS_BIT] |= + (uintptr_t)1 << (p->nsteps % STEPS_BIT); + ++p->nsteps; +} + +/* Pushes a step to the right to the end of the path. */ +static inline void +path_taking_right(struct path *p) +{ + + p->steps[p->nsteps / STEPS_BIT] &= + ~((uintptr_t)1 << (p->nsteps % STEPS_BIT)); + ++p->nsteps; +} + +/* + * Pops the first step from the path and returns whether it was a step + * to the left. + */ +static inline bool +path_took_left(struct path *p) +{ + bool result; + + result = p->steps[0] & 0x1; + p->steps[0] = (p->steps[0] >> 1) | (p->steps[1] << (STEPS_BIT - 1)); + p->steps[1] >>= 1; + return (result); +} + +#undef STEPS_BIT + +#endif diff --git a/lib/libc/stdlib/twalk.c b/lib/libc/stdlib/twalk.c new file mode 100644 index 000000000000..28529ea00adf --- /dev/null +++ b/lib/libc/stdlib/twalk.c @@ -0,0 +1,48 @@ +/* $NetBSD: twalk.c,v 1.4 2012/03/20 16:38:45 matt Exp $ */ + +/* + * Tree search generalized from Knuth (6.2.2) Algorithm T just like + * the AT&T man page says. + * + * Written by reading the System V Interface Definition, not the code. + * + * Totally public domain. + */ + +#include <sys/cdefs.h> +#if 0 +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: twalk.c,v 1.4 2012/03/20 16:38:45 matt Exp $"); +#endif /* LIBC_SCCS and not lint */ +#endif +#define _SEARCH_PRIVATE +#include <search.h> +#include <stdlib.h> + +typedef void (*cmp_fn_t)(const posix_tnode *, VISIT, int); + +/* Walk the nodes of a tree */ +static void +trecurse(const posix_tnode *root, cmp_fn_t action, int level) +{ + + if (root->llink == NULL && root->rlink == NULL) + (*action)(root, leaf, level); + else { + (*action)(root, preorder, level); + if (root->llink != NULL) + trecurse(root->llink, action, level + 1); + (*action)(root, postorder, level); + if (root->rlink != NULL) + trecurse(root->rlink, action, level + 1); + (*action)(root, endorder, level); + } +} + +/* Walk the nodes of a tree */ +void +twalk(const posix_tnode *vroot, cmp_fn_t action) +{ + if (vroot != NULL && action != NULL) + trecurse(vroot, action, 0); +} |