Makefile.in
- CREATED_HEADERS: add stdckdint.h
+
+stringlib.c,externs.h
+ - substring: now takes size_t arguments for START and END
+
+lib/sh/stringvec.c
+ - strvec_create,strvec_mcreate,strvec_resize,strvec_mresize: use
+ ckd_mul to avoid size_t overflow
+ - strvec_len,strvec_flush: use size_t variable as array index
+ From a report by Paul Eggert <eggert@cs.ucla.edu>
+
+bashansi.h
+ - stdbool.h: include if we have it, typedef bool as unsigned char if
+ we don't and HAVE_C_BOOL isn't defined
+
+
+m4/c-bool.m4
+ - autoconf check for `bool' from gnulib
+
+configure.ac
+ - include m4/c-bool.m4, call gl_C_BOOL; don't explicitly check for
+ stdbool.h using AC_CHECK_HEADERS any more
+
+config.h.in
+ - HAVE_C_BOOL: define
+
+ 3/16
+ ----
+
+builtins/printf.def
+ - decodeprec: now decodeint, takes new arguments: a char ** that is
+ the string to parse and update, an argument saying whether or not
+ to print an error message on overflow, and an argument that should
+ be the return value on overflow; use ckd_* macros to check overflow
+ - printstr, printwidestr: use a different mechanism to check overflow;
+ call decodeint to get precision and field width
+
+braces.c
+ - include stdckdint.h for the ckd_* overflow checking macros
+ - mkseq: the width argument is now size_t
+ - mkseq: perform overflow detection using the ckd_* macros
+ - mkseq: perform zero-padding directly instead of using asprintf; the
+ sprintf family has trouble when width > INT_MAX
+ - expand_seqterm: use size_t instead of int for length and width
+ variables
+ From a report by Paul Eggert <eggert@cs.ucla.edu>
m4/stat-time.m4 f
m4/timespec.m4 f
m4/bison.m4 f
+m4/c-bool.m4 f
m4/codeset.m4 f
m4/extern-inline.m4 f
m4/fcntl-o.m4 f
/* bashansi.h -- Typically included information required by picky compilers. */
-/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
+/* Copyright (C) 1993-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
# include "ansi_stdlib.h"
#endif /* !HAVE_STDLIB_H */
+/* Prefer stdbool.h if we have it, maybe have to rethink this later */
+#if defined (HAVE_STDBOOL_H)
+# include <stdbool.h>
+#else
+# ifndef HAVE_C_BOOL
+# undef bool
+typedef unsigned char bool;
+# endif
+#endif
+
#endif /* !_BASHANSI_H_ */
#endif
#include <errno.h>
+#include <stdckdint.h>
#include "bashansi.h"
#include "bashintl.h"
static int brace_gobbler (char *, size_t, int *, int);
static char **expand_amble (char *, size_t, int);
static char **expand_seqterm (char *, size_t);
-static char **mkseq (intmax_t, intmax_t, intmax_t, int, int);
+static char **mkseq (intmax_t, intmax_t, intmax_t, int, size_t);
static char **array_concat (char **, char **);
#if 0
#define ST_ZINT 3
static char **
-mkseq (intmax_t start, intmax_t end, intmax_t incr, int type, int width)
+mkseq (intmax_t start, intmax_t end, intmax_t incr, int type, size_t width)
{
- intmax_t n, prevn;
- int i, nelem;
+ intmax_t prevn, n, abs_incr;
+ size_t nelem, i;
char **result, *t;
+ char lbuf[INT_BUFSIZE_BOUND (uintmax_t)];
if (incr == 0)
incr = 1;
- if (start > end && incr > 0)
- incr = -incr;
- else if (start < end && incr < 0)
- {
- if (incr == INTMAX_MIN) /* Don't use -INTMAX_MIN */
- return ((char **)NULL);
- incr = -incr;
- }
-
- /* Check that end-start will not overflow INTMAX_MIN, INTMAX_MAX. The +3
- and -2, not strictly necessary, are there because of the way the number
- of elements and value passed to strvec_create() are calculated below. */
- if (SUBOVERFLOW (end, start, INTMAX_MIN+3, INTMAX_MAX-2))
+ abs_incr = incr;
+ if (incr < 0 && ckd_sub (&abs_incr, 0, incr))
return ((char **)NULL);
- prevn = sh_imaxabs (end - start);
- /* Need to check this way in case INT_MAX == INTMAX_MAX */
- if (INT_MAX == INTMAX_MAX && (ADDOVERFLOW (prevn, 2, INT_MIN, INT_MAX)))
+ /* Make sure incr agrees with start and end */
+ if ((start < end) == (incr < 0) && ckd_sub (&incr, 0, incr))
return ((char **)NULL);
- /* Make sure the assignment to nelem below doesn't end up <= 0 due to
- intmax_t overflow */
- else if (ADDOVERFLOW ((prevn/sh_imaxabs(incr)), 1, INTMAX_MIN, INTMAX_MAX))
+
+ /* prevn = sh_imaxabs (end - start); */
+ if (start < end ? ckd_sub (&prevn, end, start) : ckd_sub (&prevn, start, end))
return ((char **)NULL);
- /* XXX - TOFIX: potentially allocating a lot of extra memory if
- imaxabs(incr) != 1 */
- /* Instead of a simple nelem = prevn + 1, something like:
- nelem = (prevn / imaxabs(incr)) + 1;
- would work */
- if ((prevn / sh_imaxabs (incr)) > INT_MAX - 3) /* check int overflow */
+ /* nelem = floor (abs ((end - start) / incr)) plus 1 for first element plus
+ trailing null. Account for trailing null up here for overflow check */
+ if (ckd_add (&nelem, prevn / abs_incr, 2))
return ((char **)NULL);
- nelem = (prevn / sh_imaxabs(incr)) + 1;
- result = strvec_mcreate (nelem + 1);
+
+ result = strvec_mcreate (nelem);
if (result == 0)
{
- internal_error (_("brace expansion: failed to allocate memory for %u elements"), (unsigned int)nelem);
+ internal_error (_("brace expansion: failed to allocate memory for %s elements"), uinttostr (nelem - 1, lbuf, sizeof (lbuf)));
return ((char **)NULL);
}
result[i++] = t = itos (n);
else if (type == ST_ZINT)
{
- int len, arg;
- arg = n;
- len = asprintf (&t, "%0*d", width, arg);
+ size_t tlen;
+
+ t = itos (n);
+ tlen = strlen (t);
+ if (tlen < width) /* zero-pad the result directly to avoid sprintf */
+ {
+ char *t0;
+ t0 = t;
+ t = realloc (t, width + 1);
+ if (t == 0)
+ free (t0);
+ else
+ {
+ memmove (t + (width - tlen), t, tlen + 1);
+ memset (t + (n < 0), '0', width - tlen);
+ }
+ }
result[i++] = t;
}
else
/* We failed to allocate memory for this number, so we bail. */
if (t == 0)
{
- char *p, lbuf[INT_STRLEN_BOUND(intmax_t) + 1];
+ char *p;
/* Easier to do this than mess around with various intmax_t printf
formats (%ld? %lld? %jd?) and PRIdMAX. */
- p = inttostr (n, lbuf, sizeof (lbuf));
+ p = uinttostr (n, lbuf, sizeof (lbuf));
internal_error (_("brace expansion: failed to allocate memory for `%s'"), p);
strvec_dispose (result);
return ((char **)NULL);
}
- /* Handle overflow and underflow of n+incr */
- if (ADDOVERFLOW (n, incr, INTMAX_MIN, INTMAX_MAX))
- break;
-
n += incr;
- if ((incr < 0 && n < end) || (incr > 0 && n > end))
+ if (i == nelem - 1)
break;
}
while (1);
expand_seqterm (char *text, size_t tlen)
{
char *t, *lhs, *rhs;
- int lhs_t, rhs_t, lhs_l, rhs_l, width;
+ int lhs_t, rhs_t;
+ size_t lhs_l, rhs_l, width;
intmax_t lhs_v, rhs_v, incr;
intmax_t tl, tr;
char **result, *ep, *oep;
#include <stdarg.h>
+#include <stdckdint.h>
#include <stdio.h>
#include <chartypes.h>
static size_t conv_bufsize;
static inline int
-decodeprec (char *ps)
+decodeint (char **str, int diagnose, int overflow_return)
{
- intmax_t mpr;
- int pr;
- char *s;
+ int pr, v;
+ char *ps;
+
+ ps = *str;
+ pr = *ps++ - '0';
+ v = 0;
- s = ps; /* error checking */
- mpr = *ps++ - '0';
- while (DIGIT (*ps))
- mpr = (mpr * 10) + (*ps++ - '0');
- if (mpr < 0 || mpr > INT_MAX)
+ /* use C23 macros to check overflow */
+ for (; DIGIT (*ps); ps++)
{
-#if 0
- report_erange (s, ps);
-#endif
+ v |= ckd_mul (&pr, pr, 10);
+ v |= ckd_add (&pr, pr, *ps - '0');
+ }
+ if (v && diagnose)
+ {
+ report_erange (*str, ps);
return -1;
- }
- return (pr = mpr);
+ }
+
+ *str = ps;
+ return (v ? overflow_return : pr);
}
int
if (convch == 'Q' && (have_precision || precstart))
{
if (precstart)
- precision = decodeprec (precstart);
+ {
+ char *prec;
+ prec = precstart;
+ precision = decodeint (&prec, 0, -1);
+ }
slen = strlen (p);
/* printf precision works in bytes. */
if (precision >= 0 && precision < slen)
static int
printstr (char *fmt, char *string, int len, int fieldwidth, int precision)
{
+#if 0
char *s;
+#endif
int padlen, nc, ljust, i;
int fw, pr; /* fieldwidth and precision */
- intmax_t mfw, mpr;
if (string == 0)
string = "";
ljust = fw = 0;
pr = -1;
- mfw = 0;
- mpr = -1;
/* skip flags */
while (strchr (SKIP1, *fmt))
}
}
else if (DIGIT (*fmt))
- {
- s = fmt;
- mfw = *fmt++ - '0';
- while (DIGIT (*fmt))
- mfw = (mfw * 10) + (*fmt++ - '0');
- /* Error if fieldwidth > INT_MAX here */
- if (mfw < 0 || mfw > INT_MAX)
- {
- report_erange (s, fmt);
- fw = 0;
- }
- else
- fw = mfw;
- }
+ fw = decodeint (&fmt, 1, 0);
/* get precision, if present. doesn't handle negative precisions */
if (*fmt == '.')
}
else if (DIGIT (*fmt))
{
- s = fmt;
- mpr = *fmt++ - '0';
- while (DIGIT (*fmt))
- mpr = (mpr * 10) + (*fmt++ - '0');
- /* Error if precision > INT_MAX here */
- if (mpr < 0 || mpr > INT_MAX)
- {
- report_erange (s, fmt);
- pr = -1;
- }
- else
- pr = mpr;
+ pr = decodeint (&fmt, 1, -1);
+ /* pr < precision means we adjusted precision in printf_builtin
+ for the quoted string length (%Q), so we use the adjusted value */
if (pr < precision && precision < INT_MAX)
- pr = precision; /* XXX */
+ pr = precision;
}
else
pr = 0; /* "a null digit string is treated as zero" */
char *string;
int padlen, nc, ljust, i;
int fw, pr; /* fieldwidth and precision */
- intmax_t mfw, mpr;
if (wstring == 0)
wstring = L"";
ljust = fw = 0;
pr = -1;
- mfw = 0;
- mpr = -1;
/* skip flags */
while (strchr (SKIP1, *fmt))
}
}
else if (DIGIT (*fmt))
- {
- mfw = *fmt++ - '0';
- while (DIGIT (*fmt))
- mfw = (mfw * 10) + (*fmt++ - '0');
- /* Error if fieldwidth > INT_MAX here */
- if (mfw < 0 || mfw > INT_MAX)
- {
- report_erange (s, fmt);
- fw = 0;
- }
- else
- fw = mfw;
- }
+ fw = decodeint (&fmt, 1, 0);
/* get precision, if present. doesn't handle negative precisions */
if (*fmt == '.')
}
else if (DIGIT (*fmt))
{
- mpr = *fmt++ - '0';
- while (DIGIT (*fmt))
- mpr = (mpr * 10) + (*fmt++ - '0');
- /* Error if precision > INT_MAX here */
- if (mpr < 0 || mpr > INT_MAX)
- {
- report_erange (s, fmt);
- pr = -1;
- }
- else
- pr = mpr;
+ pr = decodeint (&fmt, 1, -1);
+ /* pr < precision means we adjusted precision in printf_builtin
+ for the quoted string length (%Q), so we use the adjusted value */
if (pr < precision && precision < INT_MAX)
- pr = precision; /* XXX */
+ pr = precision;
}
else
pr = 0; /* "a null digit string is treated as zero" */
/* The number of bytes in a `wchar_t', if supported */
#undef SIZEOF_WCHAR_T
+#undef HAVE_C_BOOL
+
/* System paths */
#define DEFAULT_MAIL_DIRECTORY "/usr/spool/mail"
as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H"
as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H"
+as_fn_append ac_header_c_list " stdbool.h stdbool_h HAVE_STDBOOL_H"
gt_needs="$gt_needs need-ngettext"
as_fn_append ac_header_c_list " sys/param.h sys_param_h HAVE_SYS_PARAM_H"
as_fn_append ac_func_c_list " getpagesize HAVE_GETPAGESIZE"
+# Check for bool that conforms to C2023.
+
+
+
+
+
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
printf %s "checking for an ANSI C-conforming const... " >&6; }
if test ${ac_cv_c_const+y}
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for bool, true, false" >&5
+printf %s "checking for bool, true, false... " >&6; }
+if test ${gl_cv_c_bool+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #if true == false
+ #error "true == false"
+ #endif
+ extern bool b;
+ bool b = true == false;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ gl_cv_c_bool=yes
+else $as_nop
+ gl_cv_c_bool=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_c_bool" >&5
+printf "%s\n" "$gl_cv_c_bool" >&6; }
+ if test "$gl_cv_c_bool" = yes; then
+
+printf "%s\n" "#define HAVE_C_BOOL 1" >>confdefs.h
+
+ fi
+
+
+
+
+
+
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5
printf %s "checking for a race-free mkdir -p... " >&6; }
if test -z "$MKDIR_P"; then
LIBS=$save_LIBS
test $gl_pthread_api = yes && break
done
- echo "$as_me:9071: gl_pthread_api=$gl_pthread_api" >&5
- echo "$as_me:9072: LIBPTHREAD=$LIBPTHREAD" >&5
+ echo "$as_me:9115: gl_pthread_api=$gl_pthread_api" >&5
+ echo "$as_me:9116: LIBPTHREAD=$LIBPTHREAD" >&5
gl_pthread_in_glibc=no
# On Linux with glibc >= 2.34, libc contains the fully functional
;;
esac
- echo "$as_me:9098: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
+ echo "$as_me:9142: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
# Test for libpthread by looking for pthread_kill. (Not pthread_self,
# since it is defined as a macro on OSF/1.)
fi
fi
- echo "$as_me:9252: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
+ echo "$as_me:9296: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5
printf %s "checking whether POSIX threads API is available... " >&6; }
LIBS=$save_LIBS
test $gl_pthread_api = yes && break
done
- echo "$as_me:9480: gl_pthread_api=$gl_pthread_api" >&5
- echo "$as_me:9481: LIBPTHREAD=$LIBPTHREAD" >&5
+ echo "$as_me:9524: gl_pthread_api=$gl_pthread_api" >&5
+ echo "$as_me:9525: LIBPTHREAD=$LIBPTHREAD" >&5
gl_pthread_in_glibc=no
# On Linux with glibc >= 2.34, libc contains the fully functional
;;
esac
- echo "$as_me:9507: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
+ echo "$as_me:9551: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
# Test for libpthread by looking for pthread_kill. (Not pthread_self,
# since it is defined as a macro on OSF/1.)
fi
fi
- echo "$as_me:9661: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
+ echo "$as_me:9705: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5
printf %s "checking whether POSIX threads API is available... " >&6; }
then :
printf "%s\n" "#define HAVE_DLFCN_H 1" >>confdefs.h
-fi
-ac_fn_c_check_header_compile "$LINENO" "stdbool.h" "ac_cv_header_stdbool_h" "$ac_includes_default"
-if test "x$ac_cv_header_stdbool_h" = xyes
-then :
- printf "%s\n" "#define HAVE_STDBOOL_H 1" >>confdefs.h
-
fi
ac_fn_c_check_header_compile "$LINENO" "stddef.h" "ac_cv_header_stddef_h" "$ac_includes_default"
if test "x$ac_cv_header_stddef_h" = xyes
m4_include([m4/glibc21.m4])
m4_include([m4/host-cpu-c-abi.m4])
+m4_include([m4/c-bool.m4])
+
dnl C compiler characteristics
AC_C_CONST
AC_C_INLINE
AC_C_VOLATILE
AC_C_RESTRICT
+gl_C_BOOL
+
dnl initialize GNU gettext
dnl the use-libtool is a lie, we just use the standard Unix tools
BASH_GNU_GETTEXT([use-libtool], [need-ngettext], [lib/intl])
AC_CHECK_HEADERS(unistd.h stdlib.h varargs.h limits.h string.h \
memory.h locale.h termcap.h termio.h termios.h dlfcn.h \
- stdbool.h stddef.h stdint.h netdb.h pwd.h grp.h strings.h \
+ stddef.h stdint.h netdb.h pwd.h grp.h strings.h \
stdckdint.h \
regex.h syslog.h ulimit.h)
AC_CHECK_HEADERS(sys/pte.h sys/stream.h sys/select.h sys/file.h sys/ioctl.h \
translation, using the ‘LC_MESSAGES’, ‘TEXTDOMAINDIR’, and ‘TEXTDOMAIN’
shell variables, as explained below. See the gettext documentation for
additional details not covered here. If the current locale is ‘C’ or
-‘POSIX’, if there are no translations available, of if the string is not
+‘POSIX’, if there are no translations available, or if the string is not
translated, the dollar sign is ignored. Since this is a form of double
quoting, the string remains double-quoted by default, whether or not it
is translated and replaced. If the ‘noexpand_translation’ option is
translation, using the ‘LC_MESSAGES’, ‘TEXTDOMAINDIR’, and ‘TEXTDOMAIN’
shell variables, as explained below. See the gettext documentation for
additional details not covered here. If the current locale is ‘C’ or
-‘POSIX’, if there are no translations available, of if the string is not
+‘POSIX’, if there are no translations available, or if the string is not
translated, the dollar sign is ignored. Since this is a form of double
quoting, the string remains double-quoted by default, whether or not it
is translated and replaced. If the ‘noexpand_translation’ option is
See the gettext documentation for additional details not covered here.
If the current locale is @code{C} or @code{POSIX},
if there are no translations available,
-of if the string is not translated,
+or if the string is not translated,
the dollar sign is ignored.
Since this is a form of double quoting, the string remains double-quoted
by default, whether or not it is translated and replaced.
extern char *find_token_in_alist (int, STRING_INT_ALIST *, int);
extern int find_index_in_alist (char *, STRING_INT_ALIST *, int);
-extern char *substring (const char *, int, int);
+extern char *substring (const char *, size_t, size_t);
extern char *strsub (const char *, const char *, const char *, int);
extern char *strcreplace (const char *, int, const char *, int);
extern void strip_leading (char *);
#endif
#include <bashansi.h>
+#include <stdckdint.h>
#include <stdio.h>
#include <chartypes.h>
char **
strvec_create (size_t n)
{
- return ((char **)xmalloc ((n) * sizeof (char *)));
+ size_t nbytes;
+
+ return ckd_mul (&nbytes, n, sizeof (char *)) ? NULL : xmalloc (nbytes);
}
/* Allocate an array of strings with room for N members. */
char **
strvec_mcreate (size_t n)
{
- return ((char **)malloc ((n) * sizeof (char *)));
+ size_t nbytes;
+
+ return ckd_mul (&nbytes, n, sizeof (char *)) ? NULL : malloc (nbytes);
}
char **
strvec_resize (char **array, size_t nsize)
{
- return ((char **)xrealloc (array, nsize * sizeof (char *)));
+ size_t nbytes;
+
+ return ckd_mul (&nbytes, nsize, sizeof (char *)) ? NULL : (char **)xrealloc (array, nbytes);
}
char **
strvec_mresize (char **array, size_t nsize)
{
- return ((char **)realloc (array, nsize * sizeof (char *)));
+ size_t nbytes;
+
+ return ckd_mul (&nbytes, nsize, sizeof (char *)) ? NULL : (char **)realloc (array, nbytes);
}
/* Return the length of ARRAY, a NULL terminated array of char *. */
size_t
strvec_len (char * const *array)
{
- register int i;
+ register size_t i;
for (i = 0; array[i]; i++);
return (i);
void
strvec_flush (char **array)
{
- register int i;
+ register size_t i;
if (array == 0)
return;
--- /dev/null
+# Check for bool that conforms to C2023.
+
+dnl Copyright 2022-2024 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_C_BOOL],
+[
+ AC_CACHE_CHECK([for bool, true, false], [gl_cv_c_bool],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE([[
+ #if true == false
+ #error "true == false"
+ #endif
+ extern bool b;
+ bool b = true == false;]])],
+ [gl_cv_c_bool=yes],
+ [gl_cv_c_bool=no])])
+ if test "$gl_cv_c_bool" = yes; then
+ AC_DEFINE([HAVE_C_BOOL], [1],
+ [Define to 1 if bool, true and false work as per C2023.])
+ fi
+
+ AC_CHECK_HEADERS_ONCE([stdbool.h])
+
+])
/* Cons a new string from STRING starting at START and ending at END,
not including END. */
char *
-substring (const char *string, int start, int end)
+substring (const char *string, size_t start, size_t end)
{
- int len;
+ size_t len;
char *result;
len = end - start;