add more overflow handling for printf builtin; start incorporating C23 stdckdint ; rework PRIdMAX replacements

This commit is contained in:
Chet Ramey
2024-03-15 12:55:39 -04:00
parent bf944fe91f
commit 167a9248f9
22 changed files with 608 additions and 91 deletions
+1
View File
@@ -70,6 +70,7 @@ support/bashbug.sh
lsignames.h
pathnames.h
signames.h
stdckdint.h
version.h
syntax.c
stamp-h
+44
View File
@@ -8807,3 +8807,47 @@ jobs.c
received the signal, too) as notified, since we don't report on it
in the JDEAD case if the signal is trapped
3/13
----
builtins/printf.def
- PF: print an error message if printf returns an error or leaves
ferror(stdout) true
From a report by Paul Eggert <eggert@cs.ucla.edu>
3/14
----
builtins/printf.def
- getint: now takes an int argument and returns it if the conversion
overflows an int; changed callers in printf_builtin
- getint: consolidate checks for overflow. This changes the behavior
if the argument overflows an intmax_t: it returns a field width of
0 (the overflow result) instead of -1, which changes how printf
behaves. This is consistent with the behavior when the argument
overflows an int
- printf_builtin: change check for overflow of [LONG_MIN..LONG_MAX]
for %d/%i to be explicit instead of relying on integer overflow of p
- printstr,printwidestr: print message if field width or precision
overflow, since we don't call printf
- printstr,printwidestr: set field width and precision on integer
overflow the way we do in printf_builtin
From a report by Paul Eggert <eggert@cs.ucla.edu>
bashtypes.h
- PRIdMAX: move redefinition here after including inttypes.h
builtins/printf.def,examples/loadables/seq.c,examples/loadables/getconf.h
- remove PRIdMAX redefinitions, since it's now fixed in bashtypes.h
From a report by Paul Eggert <eggert@cs.ucla.edu>
3/15
----
include/stdckdint.in.h,include/intprops-internal.h
- new files, from gnulib
configure.ac
- stdckdint.h: create in the build directory if the system doesn't
provide one by copying ${srcdir}/include/stdckdint.in.h; make
sure we don't create a new one every time, changing the timestamp
Makefile.in
- CREATED_HEADERS: add stdckdint.h
+2
View File
@@ -219,6 +219,7 @@ include/ansi_stdlib.h f
include/chartypes.h f
include/filecntl.h f
include/gettext.h f
include/intprops-internal.h f
include/maxpath.h f
include/memalloc.h f
include/ocache.h f
@@ -233,6 +234,7 @@ include/shmbutil.h f
include/shtty.h f
include/stat-time.h f
include/stdc.h f
include/stdckdint.in.h f
include/systimes.h f
include/timer.h f
include/typemax.h f
+2 -2
View File
@@ -1,4 +1,4 @@
# Makefile for bash-5.3, version 5.3
# Makefile for bash-5.3, version 5.4
#
# Copyright (C) 1996-2024 Free Software Foundation, Inc.
@@ -593,7 +593,7 @@ CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \
examples/loadables/perl/Makefile support/Makefile \
lib/intl/Makefile po/Makefile po/Makefile.in
CREATED_HEADERS = signames.h config.h pathnames.h version.h y.tab.h \
${DEFDIR}/builtext.h
${DEFDIR}/builtext.h stdckdint.h
OTHER_DOCS = $(srcdir)/CHANGES $(srcdir)/COMPAT $(srcdir)/NEWS $(srcdir)/POSIX \
$(srcdir)/RBASH $(srcdir)/README
Vendored
+1 -1
View File
@@ -3,7 +3,7 @@ dnl Bash specific tests
dnl
dnl Some derived from PDKSH 5.1.3 autoconf tests
dnl
dnl Copyright (C) 1987-2023 Free Software Foundation, Inc.
dnl Copyright (C) 1987-2024 Free Software Foundation, Inc.
dnl
dnl
+1 -1
View File
@@ -1,6 +1,6 @@
/* bashhist.c -- bash interface to the GNU history library. */
/* Copyright (C) 1993-2023 Free Software Foundation, Inc.
/* Copyright (C) 1993-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+13 -1
View File
@@ -1,6 +1,6 @@
/* bashtypes.h -- Bash system types. */
/* Copyright (C) 1993-2009 Free Software Foundation, Inc.
/* Copyright (C) 1993-2009,2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -35,6 +35,18 @@
# include <inttypes.h>
#endif
/* Fix PRIdMAX on systems where it's broken. */
#ifdef PRI_MACROS_BROKEN
# undef PRIdMAX
#endif
#ifndef PRIdMAX
# if HAVE_LONG_LONG
# define PRIdMAX "lld"
# else
# define PRIdMAX "ld"
# endif
#endif
#if HAVE_STDINT_H
# include <stdint.h>
#endif
+77 -55
View File
@@ -89,18 +89,6 @@ $END
#include "bashgetopt.h"
#include "common.h"
#if defined (PRI_MACROS_BROKEN)
# undef PRIdMAX
#endif
#if !defined (PRIdMAX)
# if HAVE_LONG_LONG
# define PRIdMAX "lld"
# else
# define PRIdMAX "ld"
# endif
#endif
#if !defined (errno)
extern int errno;
#endif
@@ -154,7 +142,7 @@ extern int errno;
char b[2]; \
tw++; \
b[0] = c; b[1] = '\0'; \
if (vflag) \
if (vflag) \
vbadd (b, 1); \
else \
putchar (c); \
@@ -178,8 +166,7 @@ extern int errno;
if (nw < 0 || (vflag == 0 && ferror (stdout))) \
{ \
QUIT; \
if (vflag) \
builtin_error ("%s", strerror (errno)); \
builtin_error ("%s", strerror (errno)); \
PRETURN (EXECUTION_FAILURE); \
} \
tw += nw; \
@@ -203,7 +190,8 @@ extern int asprintf (char **, const char *, ...) __attribute__((__format__ (prin
extern int vsnprintf (char *, size_t, const char *, va_list) __attribute__((__format__ (printf, 3, 0)));
#endif
static void printf_erange (char *);
static inline void printf_erange (char *);
static inline void report_erange (char *, char *);
static int printstr (char *, char *, int, int, int);
static int tescape (char *, char *, int *, int *);
static char *bexpand (char *, int, int *, int *);
@@ -212,7 +200,7 @@ static int vbprintf (const char *, ...) __attribute__((__format__ (printf, 1, 2)
static char *mklong (char *, char *, size_t);
static int getchr (void);
static char *getstr (void);
static int getint (void);
static int getint (int);
static intmax_t getintmax (void);
static uintmax_t getuintmax (void);
@@ -260,11 +248,21 @@ static inline int
decodeprec (char *ps)
{
intmax_t mpr;
int pr;
char *s;
s = ps; /* error checking */
mpr = *ps++ - '0';
while (DIGIT (*ps))
mpr = (mpr * 10) + (*ps++ - '0');
return (mpr < 0 || mpr > INT_MAX) ? INT_MAX : mpr;
if (mpr < 0 || mpr > INT_MAX)
{
#if 0
report_erange (s, ps);
#endif
return -1;
}
return (pr = mpr);
}
int
@@ -419,10 +417,9 @@ printf_builtin (WORD_LIST *list)
{
fmt++;
have_fieldwidth = 1;
fieldwidth = getint ();
/* Handle field with overflow by ignoring it. */
if (fieldwidth == INT_MAX || fieldwidth == INT_MIN)
fieldwidth = 0;
/* Handle field with overflow by ignoring fieldwidth for now.
getint() prints a message. */
fieldwidth = getint (0);
}
else
while (DIGIT (*fmt))
@@ -436,11 +433,10 @@ printf_builtin (WORD_LIST *list)
{
fmt++;
have_precision = 1;
precision = getint ();
/* Handle precision overflow by ignoring it. "A negative
precision is treated as if it were missing." */
if (precision == INT_MAX || precision == INT_MIN)
precision = -1;
/* Handle precision overflow by ignoring precision for now.
getint() prints a message.
"A negative precision is treated as if it were missing." */
precision = getint (-1);
}
else
{
@@ -712,8 +708,8 @@ printf_builtin (WORD_LIST *list)
long p;
intmax_t pp;
p = pp = getintmax ();
if (p != pp)
pp = getintmax ();
if (pp < LONG_MIN || pp > LONG_MAX)
{
f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2);
PF (f, pp);
@@ -724,6 +720,7 @@ printf_builtin (WORD_LIST *list)
in "long". This also works around some long
long and/or intmax_t library bugs in the common
case, e.g. glibc 2.2 x86. */
p = pp;
f = mklong (start, "l", 1);
PF (f, p);
}
@@ -811,13 +808,24 @@ printf_builtin (WORD_LIST *list)
PRETURN (retval);
}
static void
static inline void
printf_erange (char *s)
{
builtin_error (_("%s: %s"), s, strerror(ERANGE));
conversion_error = 1;
}
static inline void
report_erange (char *s, char *e)
{
unsigned char sc;
sc = *e;
*e = 0;
printf_erange (s);
*e = sc;
}
/* We duplicate a lot of what printf(3) does here. */
/* FMT: format
STRING: expanded string argument
@@ -830,9 +838,7 @@ printf_erange (char *s)
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;
@@ -872,11 +878,18 @@ printstr (char *fmt, char *string, int len, int fieldwidth, int precision)
}
else if (DIGIT (*fmt))
{
s = fmt;
mfw = *fmt++ - '0';
while (DIGIT (*fmt))
mfw = (mfw * 10) + (*fmt++ - '0');
/* Error if fieldwidth > INT_MAX here? */
fw = (mfw < 0 || mfw > INT_MAX) ? INT_MAX : mfw;
/* Error if fieldwidth > INT_MAX here */
if (mfw < 0 || mfw > INT_MAX)
{
report_erange (s, fmt);
fw = 0;
}
else
fw = mfw;
}
/* get precision, if present. doesn't handle negative precisions */
@@ -890,11 +903,18 @@ printstr (char *fmt, char *string, int len, int fieldwidth, int precision)
}
else if (DIGIT (*fmt))
{
s = fmt;
mpr = *fmt++ - '0';
while (DIGIT (*fmt))
mpr = (mpr * 10) + (*fmt++ - '0');
/* Error if precision > INT_MAX here? */
pr = (mpr < 0 || mpr > INT_MAX) ? INT_MAX : mpr;
/* Error if precision > INT_MAX here */
if (mpr < 0 || mpr > INT_MAX)
{
report_erange (s, fmt);
pr = -1;
}
else
pr = mpr;
if (pr < precision && precision < INT_MAX)
pr = precision; /* XXX */
}
@@ -940,9 +960,7 @@ printstr (char *fmt, char *string, int len, int fieldwidth, int precision)
static int
printwidestr (char *fmt, wchar_t *wstring, size_t len, int fieldwidth, int precision)
{
#if 0
char *s;
#endif
char *string;
int padlen, nc, ljust, i;
int fw, pr; /* fieldwidth and precision */
@@ -986,8 +1004,14 @@ printwidestr (char *fmt, wchar_t *wstring, size_t len, int fieldwidth, int preci
mfw = *fmt++ - '0';
while (DIGIT (*fmt))
mfw = (mfw * 10) + (*fmt++ - '0');
/* Error if fieldwidth > INT_MAX here? */
fw = (mfw < 0 || mfw > INT_MAX) ? INT_MAX : mfw;
/* Error if fieldwidth > INT_MAX here */
if (mfw < 0 || mfw > INT_MAX)
{
report_erange (s, fmt);
fw = 0;
}
else
fw = mfw;
}
/* get precision, if present. doesn't handle negative precisions */
@@ -1004,8 +1028,14 @@ printwidestr (char *fmt, wchar_t *wstring, size_t len, int fieldwidth, int preci
mpr = *fmt++ - '0';
while (DIGIT (*fmt))
mpr = (mpr * 10) + (*fmt++ - '0');
/* Error if precision > INT_MAX here? */
pr = (mpr < 0 || mpr > INT_MAX) ? INT_MAX : mpr;
/* Error if precision > INT_MAX here */
if (mpr < 0 || mpr > INT_MAX)
{
report_erange (s, fmt);
pr = -1;
}
else
pr = mpr;
if (pr < precision && precision < INT_MAX)
pr = precision; /* XXX */
}
@@ -1358,10 +1388,11 @@ getstr (void)
/* Don't call getintmax here because it may consume an argument on error, and
we call this to get field width/precision arguments. */
static int
getint (void)
getint (int overflow_retval)
{
intmax_t ret;
char *ep;
int overflow;
if (garglist == 0)
return (0);
@@ -1371,27 +1402,18 @@ getint (void)
errno = 0;
ret = strtoimax (garglist->word->word, &ep, 0);
overflow = (errno == ERANGE) || (ret < INT_MIN || ret > INT_MAX);
if (*ep)
{
sh_invalidnum (garglist->word->word);
conversion_error = 1;
}
else if (errno == ERANGE)
else if (overflow)
printf_erange (garglist->word->word);
else if (ret > INT_MAX)
{
printf_erange (garglist->word->word);
ret = INT_MAX;
}
else if (ret < INT_MIN)
{
printf_erange (garglist->word->word);
ret = INT_MIN;
}
garglist = garglist->next;
return ((int)ret);
return (overflow ? overflow_retval : (int)ret);
}
static intmax_t
+1 -1
View File
@@ -1,6 +1,6 @@
/* config-top.h - various user-settable options not under the control of autoconf. */
/* Copyright (C) 2002-2021 Free Software Foundation, Inc.
/* Copyright (C) 2002-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Vendored
+15 -1
View File
@@ -1,5 +1,5 @@
#! /bin/sh
# From configure.ac for Bash 5.3, version 5.061.
# From configure.ac for Bash 5.3, version 5.062.
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71 for bash 5.3-devel.
#
@@ -14533,6 +14533,12 @@ if test "x$ac_cv_header_strings_h" = xyes
then :
printf "%s\n" "#define HAVE_STRINGS_H 1" >>confdefs.h
fi
ac_fn_c_check_header_compile "$LINENO" "stdckdint.h" "ac_cv_header_stdckdint_h" "$ac_includes_default"
if test "x$ac_cv_header_stdckdint_h" = xyes
then :
printf "%s\n" "#define HAVE_STDCKDINT_H 1" >>confdefs.h
fi
ac_fn_c_check_header_compile "$LINENO" "regex.h" "ac_cv_header_regex_h" "$ac_includes_default"
if test "x$ac_cv_header_regex_h" = xyes
@@ -22381,6 +22387,14 @@ ac_config_files="$ac_config_files Makefile builtins/Makefile lib/readline/Makefi
ac_config_commands="$ac_config_commands stamp-h"
if test "$ac_cv_header_stdckdint_h" = yes; then
rm -f stdckdint.h
elif cmp ${srcdir}/include/stdckdint.in.h stdckdint.h 2>/dev/null; then
:
else
cp ${srcdir}/include/stdckdint.in.h stdckdint.h
fi
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
+10 -1
View File
@@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
AC_REVISION([for Bash 5.3, version 5.061])dnl
AC_REVISION([for Bash 5.3, version 5.062])dnl
define(bashvers, 5.3)
define(relstatus, devel)
@@ -788,6 +788,7 @@ BASH_HEADER_INTTYPES
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 \
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 \
sys/mman.h sys/param.h sys/random.h sys/socket.h sys/stat.h \
@@ -1352,4 +1353,12 @@ AC_CONFIG_FILES([Makefile builtins/Makefile lib/readline/Makefile \
dnl Makefile uses this timestamp file to record whether config.h is up to date.
AC_CONFIG_COMMANDS([stamp-h], [echo timestamp > stamp-h])
if test "$ac_cv_header_stdckdint_h" = yes; then
rm -f stdckdint.h
elif cmp ${srcdir}/include/stdckdint.in.h stdckdint.h 2>/dev/null; then
:
else
cp ${srcdir}/include/stdckdint.in.h stdckdint.h
fi
AC_OUTPUT
-8
View File
@@ -125,12 +125,4 @@
# define WORD_BIT (sizeof (int) * CHAR_BIT)
#endif
#if !defined (PRIdMAX)
# if HAVE_LONG_LONG
# define PRIdMAX "lld"
# else
# define PRIdMAX "ld"
# endif
#endif
#endif /* _GETCONF_H */
-12
View File
@@ -35,18 +35,6 @@
extern int errno;
#endif
#if defined (PRI_MACROS_BROKEN)
# undef PRIdMAX
#endif
#if !defined (PRIdMAX)
# if HAVE_LONG_LONG
# define PRIdMAX "lld"
# else
# define PRIdMAX "ld"
# endif
#endif
#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN)
typedef long double floatmax_t;
# define FLOATMAX_CONV "L"
+1 -1
View File
@@ -1,6 +1,6 @@
/* execute_cmd.h - functions from execute_cmd.c. */
/* Copyright (C) 1993-2017,2022 Free Software Foundation, Inc.
/* Copyright (C) 1993-2017,2022-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+397
View File
@@ -0,0 +1,397 @@
/* intprops-internal.h -- properties of integer types not visible to users
Copyright (C) 2001-2024 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef _GL_INTPROPS_INTERNAL_H
#define _GL_INTPROPS_INTERNAL_H
#include <limits.h>
/* Pacify GCC 13.2 in some calls to _GL_EXPR_SIGNED. */
#if defined __GNUC__ && 4 < __GNUC__ + (3 <= __GNUC_MINOR__)
# pragma GCC diagnostic ignored "-Wtype-limits"
#endif
/* Return a value with the common real type of E and V and the value of V.
Do not evaluate E. */
#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see
<https://lists.gnu.org/r/bug-gnulib/2011-05/msg00406.html>. */
#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
/* The extra casts in the following macros work around compiler bugs,
e.g., in Cray C 5.0.3.0. */
/* True if the real type T is signed. */
#define _GL_TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
/* Return 1 if the real expression E, after promotion, has a
signed or floating type. Do not evaluate E. */
#define _GL_EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
/* Minimum and maximum values for integer types and expressions. */
/* The width in bits of the integer type or expression T.
Do not evaluate T. T must not be a bit-field expression.
Padding bits are not supported; this is checked at compile-time below. */
#define _GL_TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
/* The maximum and minimum values for the type of the expression E,
after integer promotion. E is not evaluated. */
#define _GL_INT_MINIMUM(e) \
(_GL_EXPR_SIGNED (e) \
? ~ _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_CONVERT (e, 0))
#define _GL_INT_MAXIMUM(e) \
(_GL_EXPR_SIGNED (e) \
? _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_NEGATE_CONVERT (e, 1))
#define _GL_SIGNED_INT_MAXIMUM(e) \
(((_GL_INT_CONVERT (e, 1) << (_GL_TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
/* Work around OpenVMS incompatibility with C99. */
#if !defined LLONG_MAX && defined __INT64_MAX
# define LLONG_MAX __INT64_MAX
# define LLONG_MIN __INT64_MIN
#endif
/* This include file assumes that signed types are two's complement without
padding bits; the above macros have undefined behavior otherwise.
If this is a problem for you, please let us know how to fix it for your host.
This assumption is tested by the intprops-tests module. */
/* Does the __typeof__ keyword work? This could be done by
'configure', but for now it's easier to do it by hand. */
#if (2 <= __GNUC__ \
|| (4 <= __clang_major__) \
|| (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \
|| (0x5110 <= __SUNPRO_C && !__STDC__))
# define _GL_HAVE___TYPEOF__ 1
#else
# define _GL_HAVE___TYPEOF__ 0
#endif
/* Return 1 if the integer type or expression T might be signed. Return 0
if it is definitely unsigned. T must not be a bit-field expression.
This macro does not evaluate its argument, and expands to an
integer constant expression. */
#if _GL_HAVE___TYPEOF__
# define _GL_SIGNED_TYPE_OR_EXPR(t) _GL_TYPE_SIGNED (__typeof__ (t))
#else
# define _GL_SIGNED_TYPE_OR_EXPR(t) 1
#endif
/* Return 1 if - A would overflow in [MIN,MAX] arithmetic.
A should not have side effects, and A's type should be an
integer with minimum value MIN and maximum MAX. */
#define _GL_INT_NEGATE_RANGE_OVERFLOW(a, min, max) \
((min) < 0 ? (a) < - (max) : 0 < (a))
/* True if __builtin_add_overflow (A, B, P) and __builtin_sub_overflow
(A, B, P) work when P is non-null. */
#ifdef __EDG__
/* EDG-based compilers like nvc 22.1 cannot add 64-bit signed to unsigned
<https://bugs.gnu.org/53256>. */
# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0
#elif defined __has_builtin
# define _GL_HAS_BUILTIN_ADD_OVERFLOW __has_builtin (__builtin_add_overflow)
/* __builtin_{add,sub}_overflow exists but is not reliable in GCC 5.x and 6.x,
see <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98269>. */
#elif 7 <= __GNUC__
# define _GL_HAS_BUILTIN_ADD_OVERFLOW 1
#else
# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0
#endif
/* True if __builtin_mul_overflow (A, B, P) works when P is non-null. */
#if defined __clang_major__ && __clang_major__ < 14
/* Work around Clang bug <https://bugs.llvm.org/show_bug.cgi?id=16404>. */
# define _GL_HAS_BUILTIN_MUL_OVERFLOW 0
#else
# define _GL_HAS_BUILTIN_MUL_OVERFLOW _GL_HAS_BUILTIN_ADD_OVERFLOW
#endif
/* True if __builtin_add_overflow_p (A, B, C) works, and similarly for
__builtin_sub_overflow_p and __builtin_mul_overflow_p. */
#ifdef __EDG__
/* In EDG-based compilers like ICC 2021.3 and earlier,
__builtin_add_overflow_p etc. are not treated as integral constant
expressions even when all arguments are. */
# define _GL_HAS_BUILTIN_OVERFLOW_P 0
#elif defined __has_builtin
# define _GL_HAS_BUILTIN_OVERFLOW_P __has_builtin (__builtin_mul_overflow_p)
#else
# define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
#endif
#if (!defined _GL_STDCKDINT_H && 202311 <= __STDC_VERSION__ \
&& ! (_GL_HAS_BUILTIN_ADD_OVERFLOW && _GL_HAS_BUILTIN_MUL_OVERFLOW))
# include <stdckdint.h>
#endif
/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R.
Return 1 if the result overflows. Arguments should not have side
effects and A, B and *R can be of any integer type other than char,
bool, a bit-precise integer type, or an enumeration type. */
#if _GL_HAS_BUILTIN_ADD_OVERFLOW
# define _GL_INT_ADD_WRAPV(a, b, r) __builtin_add_overflow (a, b, r)
# define _GL_INT_SUBTRACT_WRAPV(a, b, r) __builtin_sub_overflow (a, b, r)
#elif defined ckd_add && defined ckd_sub && !defined _GL_STDCKDINT_H
# define _GL_INT_ADD_WRAPV(a, b, r) ckd_add (r, + (a), + (b))
# define _GL_INT_SUBTRACT_WRAPV(a, b, r) ckd_sub (r, + (a), + (b))
#else
# define _GL_INT_ADD_WRAPV(a, b, r) \
_GL_INT_OP_WRAPV (a, b, r, +, _GL_INT_ADD_RANGE_OVERFLOW)
# define _GL_INT_SUBTRACT_WRAPV(a, b, r) \
_GL_INT_OP_WRAPV (a, b, r, -, _GL_INT_SUBTRACT_RANGE_OVERFLOW)
#endif
#if _GL_HAS_BUILTIN_MUL_OVERFLOW
# if ((9 < __GNUC__ + (3 <= __GNUC_MINOR__) \
|| (__GNUC__ == 8 && 4 <= __GNUC_MINOR__)) \
&& !defined __EDG__)
# define _GL_INT_MULTIPLY_WRAPV(a, b, r) __builtin_mul_overflow (a, b, r)
# else
/* Work around GCC bug 91450. */
# define _GL_INT_MULTIPLY_WRAPV(a, b, r) \
((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && _GL_EXPR_SIGNED (a) && _GL_EXPR_SIGNED (b) \
&& _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, 0, (__typeof__ (*(r))) -1)) \
? ((void) __builtin_mul_overflow (a, b, r), 1) \
: __builtin_mul_overflow (a, b, r))
# endif
#elif defined ckd_mul && !defined _GL_STDCKDINT_H
# define _GL_INT_MULTIPLY_WRAPV(a, b, r) ckd_mul (r, + (a), + (b))
#else
# define _GL_INT_MULTIPLY_WRAPV(a, b, r) \
_GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW)
#endif
/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193
https://llvm.org/bugs/show_bug.cgi?id=25390
For now, assume all versions of GCC-like compilers generate bogus
warnings for _Generic. This matters only for compilers that
lack relevant builtins. */
#if __GNUC__ || defined __clang__
# define _GL__GENERIC_BOGUS 1
#else
# define _GL__GENERIC_BOGUS 0
#endif
/* Store the low-order bits of A <op> B into *R, where OP specifies
the operation and OVERFLOW the overflow predicate. Return 1 if the
result overflows. Arguments should not have side effects,
and A, B and *R can be of any integer type other than char, bool, a
bit-precise integer type, or an enumeration type. */
#if 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS
# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
(_Generic \
(*(r), \
signed char: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
signed char, SCHAR_MIN, SCHAR_MAX), \
unsigned char: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
unsigned char, 0, UCHAR_MAX), \
short int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
short int, SHRT_MIN, SHRT_MAX), \
unsigned short int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
unsigned short int, 0, USHRT_MAX), \
int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
int, INT_MIN, INT_MAX), \
unsigned int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
unsigned int, 0, UINT_MAX), \
long int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
long int, LONG_MIN, LONG_MAX), \
unsigned long int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
unsigned long int, 0, ULONG_MAX), \
long long int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
long long int, LLONG_MIN, LLONG_MAX), \
unsigned long long int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
unsigned long long int, 0, ULLONG_MAX)))
#else
/* Store the low-order bits of A <op> B into *R, where OP specifies
the operation and OVERFLOW the overflow predicate. If *R is
signed, its type is ST with bounds SMIN..SMAX; otherwise its type
is UT with bounds U..UMAX. ST and UT are narrower than int.
Return 1 if the result overflows. Arguments should not have side
effects, and A, B and *R can be of any integer type other than
char, bool, a bit-precise integer type, or an enumeration type. */
# if _GL_HAVE___TYPEOF__
# define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \
(_GL_TYPE_SIGNED (__typeof__ (*(r))) \
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, st, smin, smax) \
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, ut, 0, umax))
# else
# define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \
(overflow (a, b, smin, smax) \
? (overflow (a, b, 0, umax) \
? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 1) \
: (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) < 0) \
: (overflow (a, b, 0, umax) \
? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) >= 0 \
: (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 0)))
# endif
# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
(sizeof *(r) == sizeof (signed char) \
? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \
signed char, SCHAR_MIN, SCHAR_MAX, \
unsigned char, UCHAR_MAX) \
: sizeof *(r) == sizeof (short int) \
? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \
short int, SHRT_MIN, SHRT_MAX, \
unsigned short int, USHRT_MAX) \
: sizeof *(r) == sizeof (int) \
? (_GL_EXPR_SIGNED (*(r)) \
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
int, INT_MIN, INT_MAX) \
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
unsigned int, 0, UINT_MAX)) \
: _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow))
# ifdef LLONG_MAX
# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
(sizeof *(r) == sizeof (long int) \
? (_GL_EXPR_SIGNED (*(r)) \
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
long int, LONG_MIN, LONG_MAX) \
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
unsigned long int, 0, ULONG_MAX)) \
: (_GL_EXPR_SIGNED (*(r)) \
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
long long int, LLONG_MIN, LLONG_MAX) \
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
unsigned long long int, 0, ULLONG_MAX)))
# else
# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
(_GL_EXPR_SIGNED (*(r)) \
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
long int, LONG_MIN, LONG_MAX) \
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
unsigned long int, 0, ULONG_MAX))
# endif
#endif
/* Store the low-order bits of A <op> B into *R, where the operation
is given by OP. Use the unsigned type UT for calculation to avoid
overflow problems. *R's type is T, with extrema TMIN and TMAX.
T can be any signed integer type other than char, bool, a
bit-precise integer type, or an enumeration type.
Return 1 if the result overflows. */
#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \
(overflow (a, b, tmin, tmax) \
? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \
: (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0))
/* Return 1 if the integer expressions A - B and -A would overflow,
respectively. Arguments should not have side effects,
and can be any signed integer type other than char, bool, a
bit-precise integer type, or an enumeration type.
These macros are tuned for their last input argument being a constant. */
#if _GL_HAS_BUILTIN_OVERFLOW_P
# define _GL_INT_NEGATE_OVERFLOW(a) \
__builtin_sub_overflow_p (0, a, (__typeof__ (- (a))) 0)
#else
# define _GL_INT_NEGATE_OVERFLOW(a) \
_GL_INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
#endif
/* Return the low-order bits of A <op> B, where the operation is given
by OP. Use the unsigned type UT for calculation to avoid undefined
behavior on signed integer overflow, and convert the result to type T.
UT is at least as wide as T and is no narrower than unsigned int,
T is two's complement, and there is no padding or trap representations.
Assume that converting UT to T yields the low-order bits, as is
done in all known two's-complement C compilers. E.g., see:
https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html
According to the C standard, converting UT to T yields an
implementation-defined result or signal for values outside T's
range. However, code that works around this theoretical problem
runs afoul of a compiler bug in Oracle Studio 12.3 x86. See:
https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html
As the compiler bug is real, don't try to work around the
theoretical problem. */
#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \
((t) ((ut) (a) op (ut) (b)))
/* Return true if the numeric values A + B, A - B, A * B fall outside
the range TMIN..TMAX. Arguments should not have side effects
and can be any integer type other than char, bool,
a bit-precise integer type, or an enumeration type.
TMIN should be signed and nonpositive.
TMAX should be positive, and should be signed unless TMIN is zero. */
#define _GL_INT_ADD_RANGE_OVERFLOW(a, b, tmin, tmax) \
((b) < 0 \
? (((tmin) \
? ((_GL_EXPR_SIGNED (_GL_INT_CONVERT (a, (tmin) - (b))) || (b) < (tmin)) \
&& (a) < (tmin) - (b)) \
: (a) <= -1 - (b)) \
|| ((_GL_EXPR_SIGNED (a) ? 0 <= (a) : (tmax) < (a)) && (tmax) < (a) + (b))) \
: (a) < 0 \
? (((tmin) \
? ((_GL_EXPR_SIGNED (_GL_INT_CONVERT (b, (tmin) - (a))) || (a) < (tmin)) \
&& (b) < (tmin) - (a)) \
: (b) <= -1 - (a)) \
|| ((_GL_EXPR_SIGNED (_GL_INT_CONVERT (a, b)) || (tmax) < (b)) \
&& (tmax) < (a) + (b))) \
: (tmax) < (b) || (tmax) - (b) < (a))
#define _GL_INT_SUBTRACT_RANGE_OVERFLOW(a, b, tmin, tmax) \
(((a) < 0) == ((b) < 0) \
? ((a) < (b) \
? !(tmin) || -1 - (tmin) < (b) - (a) - 1 \
: (tmax) < (a) - (b)) \
: (a) < 0 \
? ((!_GL_EXPR_SIGNED (_GL_INT_CONVERT ((a) - (tmin), b)) && (a) - (tmin) < 0) \
|| (a) - (tmin) < (b)) \
: ((! (_GL_EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
&& _GL_EXPR_SIGNED (_GL_INT_CONVERT ((tmax) + (b), a))) \
&& (tmax) <= -1 - (b)) \
|| (tmax) + (b) < (a)))
#define _GL_INT_MULTIPLY_RANGE_OVERFLOW(a, b, tmin, tmax) \
((b) < 0 \
? ((a) < 0 \
? (_GL_EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
? (a) < (tmax) / (b) \
: ((_GL_INT_NEGATE_OVERFLOW (b) \
? _GL_INT_CONVERT (b, tmax) >> (_GL_TYPE_WIDTH (+ (b)) - 1) \
: (tmax) / -(b)) \
<= -1 - (a))) \
: _GL_INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (b, tmin)) && (b) == -1 \
? (_GL_EXPR_SIGNED (a) \
? 0 < (a) + (tmin) \
: 0 < (a) && -1 - (tmin) < (a) - 1) \
: (tmin) / (b) < (a)) \
: (b) == 0 \
? 0 \
: ((a) < 0 \
? (_GL_INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (a, tmin)) && (a) == -1 \
? (_GL_EXPR_SIGNED (b) ? 0 < (b) + (tmin) : -1 - (tmin) < (b) - 1) \
: (tmin) / (a) < (b)) \
: (tmax) / (b) < (a)))
#endif /* _GL_INTPROPS_INTERNAL_H */
+35
View File
@@ -0,0 +1,35 @@
/* stdckdint.h -- checked integer arithmetic
Copyright 2022-2024 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef _GL_STDCKDINT_H
#define _GL_STDCKDINT_H
#include "intprops-internal.h"
/* Store into *R the low-order bits of A + B, A - B, A * B, respectively.
Return 1 if the result overflows, 0 otherwise.
A, B, and *R can have any integer type other than char, bool, a
bit-precise integer type, or an enumeration type.
These are like the standard macros introduced in C23, except that
arguments should not have side effects. */
#define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r))
#define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r))
#define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r))
#endif /* _GL_STDCKDINT_H */
+1 -1
View File
@@ -2,7 +2,7 @@
* mksyntax.c - construct shell syntax table for fast char attribute lookup.
*/
/* Copyright (C) 2000-2009,2012,2022-2023 Free Software Foundation, Inc.
/* Copyright (C) 2000-2009,2012,2022-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+1 -1
View File
@@ -1,6 +1,6 @@
/* sig.c - interface for shell signal handlers and signal initialization. */
/* Copyright (C) 1994-2022 Free Software Foundation, Inc.
/* Copyright (C) 1994-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+1 -1
View File
@@ -1,6 +1,6 @@
/* stringlib.c - Miscellaneous string functions. */
/* Copyright (C) 1996-2009,2022-2023 Free Software Foundation, Inc.
/* Copyright (C) 1996-2009,2022-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+3 -2
View File
@@ -377,11 +377,11 @@ VAR=[]
./printf7.sub: line 25: printf: 21474836470: Result too large
VAR=[X]
./printf7.sub: line 31: printf: 9223372036854775825: Result too large
[ ]
[]
./printf7.sub: line 32: printf: 9223372036854775825: Result too large
[X]
./printf7.sub: line 34: printf: 9223372036854775825: Result too large
VAR=[ ]
VAR=[]
./printf7.sub: line 37: printf: 9223372036854775825: Result too large
VAR=[X]
./printf7.sub: line 43: printf: 21474836470: Result too large
@@ -401,4 +401,5 @@ VAR=[]
./printf7.sub: line 61: printf: 9223372036854775825: Result too large
VAR=[X]
XY
./printf7.sub: line 71: printf: 9223372036854775825: Result too large
XY
+1 -1
View File
@@ -1,6 +1,6 @@
/* variables.c -- Functions for hacking shell variables. */
/* Copyright (C) 1987-2023 Free Software Foundation, Inc.
/* Copyright (C) 1987-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+1 -1
View File
@@ -1,6 +1,6 @@
/* variables.h -- data structures for shell variables. */
/* Copyright (C) 1987-2023 Free Software Foundation, Inc.
/* Copyright (C) 1987-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.